@@ -34,7 +34,8 @@ struct alignas(void*) SDoublyLinkedNode
34
34
prev = invalid_iterator;
35
35
next = invalid_iterator;
36
36
}
37
- SDoublyLinkedNode (Value&& val) : data (std::move (val))
37
+ template <typename ... Args>
38
+ SDoublyLinkedNode (Args&&... args) : data (std::forward<Args>(args)...)
38
39
{
39
40
prev = invalid_iterator;
40
41
next = invalid_iterator;
@@ -69,6 +70,7 @@ class DoublyLinkedList
69
70
{
70
71
public:
71
72
using allocator_t = allocator;
73
+ using allocator_traits_t = std::allocator_traits<allocator_t >;
72
74
using address_allocator_t = PoolAddressAllocator<uint32_t >;
73
75
using node_t = SDoublyLinkedNode<Value>;
74
76
using value_t = Value;
@@ -112,15 +114,15 @@ class DoublyLinkedList
112
114
template <typename ... Args>
113
115
inline void emplaceFront (Args&&... args)
114
116
{
115
- insertAt (reserveAddress (), value_t ( std::forward<Args>(args)...) );
117
+ insertAt (reserveAddress (), std::forward<Args>(args)...);
116
118
}
117
119
118
120
/* *
119
- * @brief Resets list to initial state.
121
+ * @brief Empties list: calls disposal function on and destroys every node in list, then resets state
120
122
*/
121
123
inline void clear ()
122
124
{
123
- disposeAll ();
125
+ destroyAll ();
124
126
125
127
m_addressAllocator = address_allocator_t (m_reservedSpace, 0u , 0u , 1u , m_cap, 1u );
126
128
m_back = invalid_iterator;
@@ -139,6 +141,8 @@ class DoublyLinkedList
139
141
get (backNode->prev )->next = invalid_iterator;
140
142
uint32_t temp = m_back;
141
143
m_back = backNode->prev ;
144
+ if (m_back == invalid_iterator)
145
+ m_begin = invalid_iterator;
142
146
common_delete (temp);
143
147
}
144
148
@@ -189,9 +193,12 @@ class DoublyLinkedList
189
193
return false ;
190
194
// Have to consider allocating enough space for list AND state of the address allocator
191
195
const auto firstPart = core::alignUp (address_allocator_t::reserved_size (1u , newCapacity, 1u ), alignof (node_t ));
192
- void * newReservedSpace = reinterpret_cast <void *>(m_allocator.allocate (firstPart + newCapacity * sizeof (node_t )));
196
+ // Allocator can only allocate in terms of nodes
197
+ const size_t firstPartNodes = (firstPart + sizeof (node_t ) - 1 ) / sizeof (node_t );
198
+ const size_t newAllocationSize = firstPartNodes + newCapacity;
199
+ void * newReservedSpace = reinterpret_cast <void *>(allocator_traits_t::allocate (m_allocator, newAllocationSize));
193
200
194
- // Malloc failed, not possible to grow
201
+ // Allocation failed, not possible to grow
195
202
if (!newReservedSpace)
196
203
return false ;
197
204
@@ -201,12 +208,12 @@ class DoublyLinkedList
201
208
// Create new address allocator from old one
202
209
m_addressAllocator = address_allocator_t (newCapacity, std::move (m_addressAllocator), newReservedSpace);
203
210
// After address allocator creation we can free the old buffer
204
- m_allocator. deallocate (reinterpret_cast <node_t *>(m_reservedSpace));
211
+ allocator_traits_t:: deallocate (m_allocator, reinterpret_cast <node_t *>(m_reservedSpace), m_currentAllocationSize );
205
212
m_cap = newCapacity;
206
213
m_array = newArray;
207
214
m_reservedSpace = newReservedSpace;
215
+ m_currentAllocationSize = newAllocationSize;
208
216
209
-
210
217
return true ;
211
218
}
212
219
@@ -216,11 +223,15 @@ class DoublyLinkedList
216
223
{
217
224
// Have to consider allocating enough space for list AND state of the address allocator
218
225
const auto firstPart = core::alignUp (address_allocator_t::reserved_size (1u , capacity, 1u ), alignof (node_t ));
219
- m_reservedSpace = reinterpret_cast <void *>(m_allocator.allocate (firstPart + capacity * sizeof (node_t )));
226
+ // Allocator can only allocate in terms of nodes
227
+ const size_t firstPartNodes = (firstPart + sizeof (node_t ) - 1 ) / sizeof (node_t );
228
+ m_currentAllocationSize = firstPartNodes + capacity;
229
+ m_reservedSpace = reinterpret_cast <void *>(allocator_traits_t::allocate (m_allocator, m_currentAllocationSize));
220
230
m_array = reinterpret_cast <node_t *>(reinterpret_cast <uint8_t *>(m_reservedSpace) + firstPart);
221
231
222
232
m_addressAllocator = address_allocator_t (m_reservedSpace, 0u , 0u , 1u , capacity, 1u );
223
- m_cap = capacity;
233
+ // If allocation failed, create list with no capacity to indicate creation failed
234
+ m_cap = m_reservedSpace ? capacity : 0 ;
224
235
m_back = invalid_iterator;
225
236
m_begin = invalid_iterator;
226
237
}
@@ -250,11 +261,11 @@ class DoublyLinkedList
250
261
251
262
~DoublyLinkedList ()
252
263
{
253
- disposeAll ();
264
+ destroyAll ();
254
265
// Could be null if list was moved out of
255
266
if (m_reservedSpace)
256
267
{
257
- m_allocator. deallocate (reinterpret_cast <node_t *>(m_reservedSpace));
268
+ allocator_traits_t:: deallocate (m_allocator, reinterpret_cast <node_t *>(m_reservedSpace), m_currentAllocationSize );
258
269
}
259
270
}
260
271
@@ -266,12 +277,14 @@ class DoublyLinkedList
266
277
return addr;
267
278
}
268
279
269
- // create a new node which stores data at already allocated address,
270
- inline void insertAt (uint32_t addr, value_t && val)
280
+ // create a new node which stores data at already allocated address
281
+ template <typename ... Args>
282
+ inline void insertAt (uint32_t addr, Args&&... args)
271
283
{
272
284
assert (addr < m_cap);
273
285
assert (addr != invalid_iterator);
274
- SDoublyLinkedNode<Value>* n = new (m_array + addr) SDoublyLinkedNode<Value>(std::move (val));
286
+ node_t * n = m_array + addr;
287
+ allocator_traits_t::construct (m_allocator, n, std::forward<Args>(args)...);
275
288
n->prev = invalid_iterator;
276
289
n->next = m_begin;
277
290
@@ -283,20 +296,18 @@ class DoublyLinkedList
283
296
}
284
297
285
298
/* *
286
- * @brief Calls disposal function on all elements of the list.
299
+ * @brief Calls disposal function then destroys all elements in the list.
287
300
*/
288
- inline void disposeAll ()
301
+ inline void destroyAll ()
289
302
{
290
- if (m_dispose_f && m_begin != invalid_iterator)
303
+ uint32_t currentAddress = m_begin;
304
+ while (currentAddress != invalid_iterator)
291
305
{
292
- auto * begin = getBegin ();
293
- auto * back = getBack ();
294
- while (begin != back)
295
- {
296
- m_dispose_f (begin->data );
297
- begin = get (begin->next );
298
- }
299
- m_dispose_f (back->data );
306
+ node_t * currentNode = get (currentAddress);
307
+ uint32_t nextAddress = currentNode->next ;
308
+ if (m_dispose_f) m_dispose_f (currentNode->data );
309
+ currentNode->~node_t ();
310
+ currentAddress = nextAddress;
300
311
}
301
312
}
302
313
@@ -319,6 +330,8 @@ class DoublyLinkedList
319
330
allocator_t m_allocator;
320
331
address_allocator_t m_addressAllocator;
321
332
void * m_reservedSpace;
333
+ // In term of nodes
334
+ size_t m_currentAllocationSize;
322
335
node_t * m_array;
323
336
324
337
uint32_t m_cap;
0 commit comments