@@ -69,6 +69,14 @@ template<typename Value, class allocator = core::allocator<SDoublyLinkedNode<Val
69
69
class DoublyLinkedList
70
70
{
71
71
public:
72
+ template <bool Mutable>
73
+ class Iterator ;
74
+ template <bool Mutable>
75
+ friend class Iterator ;
76
+
77
+ using iterator = Iterator<true >;
78
+ using const_iterator = Iterator<false >;
79
+
72
80
using allocator_t = allocator;
73
81
using allocator_traits_t = std::allocator_traits<allocator_t >;
74
82
using address_allocator_t = PoolAddressAllocator<uint32_t >;
@@ -233,16 +241,43 @@ class DoublyLinkedList
233
241
// Offset the array start by the storage used by the address allocator
234
242
m_array = reinterpret_cast <node_t *>(reinterpret_cast <uint8_t *>(m_reservedSpace) + addressAllocatorStorageSize * sizeof (node_t ));
235
243
236
- m_addressAllocator = address_allocator_t (m_reservedSpace, 0u , 0u , 1u , capacity, 1u );
237
244
// If allocation failed, create list with no capacity to indicate creation failed
238
245
m_cap = m_reservedSpace ? capacity : 0 ;
239
- m_back = invalid_iterator;
240
- m_begin = invalid_iterator;
246
+ m_addressAllocator = address_allocator_t (m_reservedSpace, 0u , 0u , 1u , m_cap, 1u );
241
247
}
242
248
243
249
DoublyLinkedList () = default ;
244
250
245
- DoublyLinkedList (const DoublyLinkedList& other) = delete ;
251
+ // Copy Constructor
252
+ explicit DoublyLinkedList (const DoublyLinkedList& other) : m_dispose_f(other.m_dispose_f), m_allocator(other.m_allocator)
253
+ {
254
+ const size_t addressAllocatorStorageSize = (address_allocator_t::reserved_size (1u , other.m_cap , 1u ) + sizeof (node_t ) - 1 ) / sizeof (node_t );
255
+ m_currentAllocationSize = addressAllocatorStorageSize + other.m_cap ;
256
+ m_reservedSpace = reinterpret_cast <void *>(allocator_traits_t::allocate (m_allocator, m_currentAllocationSize));
257
+ // If allocation failed, create a list with no capacity
258
+ m_cap = m_reservedSpace ? other.m_cap : 0 ;
259
+ if (!m_cap) return ; // Allocation failed
260
+ // Offset the array start by the storage used by the address allocator
261
+ m_array = reinterpret_cast <node_t *>(reinterpret_cast <uint8_t *>(m_reservedSpace) + addressAllocatorStorageSize * sizeof (node_t ));
262
+
263
+ if constexpr (std::is_trivially_copyable_v<Value>)
264
+ {
265
+ // Create new address allocator by copying state
266
+ m_addressAllocator = address_allocator_t (m_cap, other.m_addressAllocator , m_reservedSpace);
267
+ // Copy memory over
268
+ memcpy (m_array, other.m_array , m_cap * sizeof (node_t ));
269
+ m_back = other.m_back ;
270
+ m_begin = other.m_begin ;
271
+ }
272
+ else
273
+ {
274
+ m_addressAllocator = address_allocator_t (m_reservedSpace, 0u , 0u , 1u , m_cap, 1u );
275
+ // Reverse iteration since we push from the front
276
+ for (auto it = other.crbegin (); it != other.crend (); it++)
277
+ pushFront (value_t (*it));
278
+
279
+ }
280
+ }
246
281
247
282
DoublyLinkedList& operator =(const DoublyLinkedList& other) = delete ;
248
283
@@ -273,6 +308,16 @@ class DoublyLinkedList
273
308
}
274
309
}
275
310
311
+ // Iterator stuff
312
+ iterator begin ();
313
+ iterator end ();
314
+ const_iterator cbegin () const ;
315
+ const_iterator cend () const ;
316
+ std::reverse_iterator<iterator> rbegin ();
317
+ std::reverse_iterator<iterator> rend ();
318
+ std::reverse_iterator<const_iterator> crbegin () const ;
319
+ std::reverse_iterator<const_iterator> crend () const ;
320
+
276
321
private:
277
322
// allocate and get the address of the next free node
278
323
inline uint32_t reserveAddress ()
@@ -339,14 +384,130 @@ class DoublyLinkedList
339
384
node_t * m_array;
340
385
341
386
uint32_t m_cap;
342
- uint32_t m_back;
343
- uint32_t m_begin;
387
+ uint32_t m_back = invalid_iterator ;
388
+ uint32_t m_begin = invalid_iterator ;
344
389
disposal_func_t m_dispose_f;
345
390
};
346
391
392
+ // ---------------------------------------------------- ITERATOR -----------------------------------------------------------
393
+
394
+ // Satifies std::bidirectional_iterator
395
+ template <typename Value, class allocator >
396
+ template <bool Mutable>
397
+ class DoublyLinkedList <Value, allocator>::Iterator
398
+ {
399
+ using base_iterable_t = DoublyLinkedList<Value, allocator>;
400
+ using iterable_t = std::conditional_t <Mutable, base_iterable_t , const base_iterable_t >;
401
+ friend class base_iterable_t ;
402
+ public:
403
+ using value_type = std::conditional_t <Mutable, Value, const Value>;
404
+ using pointer = value_type*;
405
+ using reference = value_type&;
406
+ using difference_type = int32_t ;
407
+
408
+ Iterator () = default ;
409
+
410
+ // Prefix
411
+ Iterator& operator ++()
412
+ {
413
+ m_current = m_iterable->get (m_current)->next ;
414
+ return *this ;
415
+ }
416
+
417
+ Iterator& operator --()
418
+ {
419
+ m_current = m_current != invalid_iterator ? m_iterable->get (m_current)->prev : m_iterable->m_back ;
420
+ return *this ;
421
+ }
422
+
423
+ // Postfix
424
+ Iterator operator ++(int )
425
+ {
426
+ Iterator beforeIncrement = *this ;
427
+ operator ++();
428
+ return beforeIncrement;
429
+ }
430
+
431
+ Iterator operator --(int )
432
+ {
433
+ Iterator beforeDecrement = *this ;
434
+ operator --();
435
+ return beforeDecrement;
436
+ }
347
437
438
+ // Comparison
439
+ bool operator ==(const Iterator& rhs) const
440
+ {
441
+ return m_iterable == rhs.m_iterable && m_current == rhs.m_current ;
442
+ }
443
+
444
+ // Deref
445
+ reference operator *() const
446
+ {
447
+ return m_iterable->get (m_current)->data ;
448
+ }
449
+
450
+ pointer operator ->() const
451
+ {
452
+ return & operator *();
453
+ }
454
+ private:
455
+ Iterator (iterable_t * const iterable, uint32_t idx) : m_iterable(iterable), m_current(idx) {}
456
+
457
+ iterable_t * m_iterable;
458
+ uint32_t m_current;
459
+ };
460
+
461
+ template <typename Value, class allocator >
462
+ DoublyLinkedList<Value, allocator>::iterator DoublyLinkedList<Value, allocator>::begin()
463
+ {
464
+ return iterator (this , m_begin);
465
+ }
466
+
467
+ template <typename Value, class allocator >
468
+ DoublyLinkedList<Value, allocator>::const_iterator DoublyLinkedList<Value, allocator>::cbegin() const
469
+ {
470
+ return const_iterator (this , m_begin);
471
+ }
472
+
473
+ template <typename Value, class allocator >
474
+ DoublyLinkedList<Value, allocator>::iterator DoublyLinkedList<Value, allocator>::end()
475
+ {
476
+ return iterator (this , invalid_iterator);
348
477
}
478
+
479
+ template <typename Value, class allocator >
480
+ DoublyLinkedList<Value, allocator>::const_iterator DoublyLinkedList<Value, allocator>::cend() const
481
+ {
482
+ return const_iterator (this , invalid_iterator);
349
483
}
350
484
485
+ template <typename Value, class allocator >
486
+ std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::iterator> DoublyLinkedList<Value, allocator>::rbegin()
487
+ {
488
+ return std::reverse_iterator<iterator>(iterator (this , invalid_iterator));
489
+ }
490
+
491
+ template <typename Value, class allocator >
492
+ std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::const_iterator> DoublyLinkedList<Value, allocator>::crbegin() const
493
+ {
494
+ return std::reverse_iterator<const_iterator>(const_iterator (this , invalid_iterator));
495
+ }
496
+
497
+ template <typename Value, class allocator >
498
+ std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::iterator> DoublyLinkedList<Value, allocator>::rend()
499
+ {
500
+ return std::reverse_iterator<iterator>(iterator (this , m_begin));
501
+ }
502
+
503
+ template <typename Value, class allocator >
504
+ std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::const_iterator> DoublyLinkedList<Value, allocator>::crend() const
505
+ {
506
+ return std::reverse_iterator<const_iterator>(const_iterator (this , m_begin));
507
+ }
508
+
509
+ } // namespace core
510
+ } // namespace nbl
511
+
351
512
352
513
#endif
0 commit comments