fennec
Loading...
Searching...
No Matches
list.h
Go to the documentation of this file.
1// =====================================================================================================================
2// fennec, a free and open source game engine
3// Copyright © 2025 Medusa Slockbower
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17// =====================================================================================================================
18
30
31#ifndef FENNEC_CONTAINERS_LIST_H
32#define FENNEC_CONTAINERS_LIST_H
33
38
39#include <fennec/math/common.h>
40
41namespace fennec
42{
43
66template<class TypeT, class Alloc = allocator<TypeT>>
67struct list {
68
69// Definitions =========================================================================================================
70
71private:
72 struct node;
73
74public:
76 using alloc_t = typename allocator_traits<Alloc>::template rebind<node>;
77
78 using value_t = TypeT;
79
80 static constexpr size_t npos = -1;
81
82 class iterator;
83 class const_iterator;
84
85
86// Constructors & Destructor ===========================================================================================
87
90
93 constexpr list()
94 : _table(), _freed(), _root(npos), _last(npos), _size(0) {
95 }
96
100 constexpr list(const list& l)
101 : list() {
102 for (const value_t& it : l) {
103 this->push_back(it);
104 }
105 }
106
107
111 constexpr list(list&& l) noexcept
112 : _table(fennec::move(l._table))
113 , _freed(fennec::move(l._freed))
114 , _root(l._root)
115 , _last(l._last)
116 , _size(l._size) {
117 }
118
121 constexpr ~list() {
122 for (size_t i = 0; i < capacity(); ++i) {
123 _table[i].value = nullopt;
124 }
125 }
126
128
129// Assignment ==========================================================================================================
130
133
138 constexpr list& operator=(const list& l) {
139 this->clear();
140 for (const value_t& it : l) {
141 this->push_back(it);
142 }
143 return *this;
144 }
145
150 constexpr list& operator=(list&& l) noexcept {
151 this->clear();
152 _table = fennec::move(l._table);
153 _freed = fennec::move(l._freed);
154 _root = l._root; _last = l._last;
155 _size = l._size;
156 return *this;
157 }
158
160
161
162// Properties ==========================================================================================================
163
166
169 constexpr size_t size() const {
170 return _size;
171 }
172
175 constexpr size_t capacity() const {
176 return _table.capacity();
177 }
178
181 constexpr bool empty() const {
182 return _root == npos;
183 }
184
186
187
188// Access ==============================================================================================================
189
192
199 constexpr value_t& operator[](int i) {
200 assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
201 size_t n = _walk(i);
202 assertd(n != npos, "Index out of Bounds");
203 return *_table[n].value;
204 }
205
212 constexpr const value_t& operator[](int i) const {
213 assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
214 size_t n = _walk(i);
215 assertd(n != npos, "Index out of Bounds");
216 return *_table[n].value;
217 }
218
222 constexpr value_t& front() {
223 return *_table[_root].value;
224 }
225
229 constexpr const value_t& front() const {
230 return *_table[_root].value;
231 }
232
236 constexpr value_t& back() {
237 return *_table[_last].value;
238 }
239
243 constexpr const value_t& back() const {
244 return *_table[_last].value;
245 }
246
248
249
250// Modifiers ===========================================================================================================
251
254
261 constexpr size_t insert(const iterator& it, const value_t& x) {
262 return this->_insert(it._n, x);
263 }
264
271 constexpr size_t insert(const iterator& it, value_t&& x) {
272 return this->_insert(it._n, fennec::forward<value_t>(x));
273 }
274
281 constexpr size_t insert(size_t i, const value_t& x) {
282 assert(i <= size(), "Index out of Bounds");
283
284 size_t n = _walk(min(i, size_t(size() - 1)));
285 return this->_insert(n, x);
286 }
287
294 constexpr size_t insert(size_t i, value_t&& x) {
295 assert(i <= size(), "Index out of Bounds");
296
297 size_t n = _walk(min(i, size_t(size() - 1)));
298 return this->_insert(n, fennec::forward<value_t>(x));
299 }
300
308 template<typename...ArgsT>
309 constexpr size_t emplace(size_t i, ArgsT&&...args) {
310 assert(i <= size(), "Index out of Bounds");
311
312 size_t n = _walk(min(i, size_t(size() - 1)));
313 return this->_insert(n, fennec::forward<ArgsT>(args)...);
314 }
315
319 constexpr size_t push_front(const value_t& x) {
320 return this->_insert(_root, x);
321 }
322
326 constexpr size_t push_front(value_t&& x) {
327 return this->_insert(_root, fennec::forward<value_t>(x));
328 }
329
334 template<typename...ArgsT>
335 constexpr size_t emplace_front(ArgsT&&...args) {
336 return this->_insert(_root, fennec::forward<ArgsT>(args)...);
337 }
338
342 constexpr size_t push_back(const value_t& x) {
343 return this->_insert(npos, x);
344 }
345
349 constexpr size_t push_back(value_t&& x) {
350 return this->_insert(npos, fennec::forward<value_t>(x));
351 }
352
357 template<typename...ArgsT>
358 constexpr size_t emplace_back(ArgsT&&...args) {
359 return this->_insert(npos, fennec::forward<ArgsT>(args)...);
360 }
361
365 constexpr void erase(size_t i) {
366 assert(i < size(), "Index out of Bounds!");
367 size_t n = _walk(i);
368 _erase(n);
369 }
370
374 constexpr void erase(const iterator& it) {
375 _erase(it._n);
376 }
377
380 constexpr void pop_front() {
381 _erase(_root);
382 }
383
386 constexpr void pop_back() {
387 _erase(_last);
388 }
389
392 constexpr void clear() {
393 size_t i = _root;
394 while (i != npos) {
395 fennec::destruct(&_table[i]);
396 i = this->_next(i);
397 }
398 _table.deallocate();
399 }
400
402
403// ITERATOR ============================================================================================================
404
407
411 constexpr iterator begin() {
412 return iterator(this, _root);
413 }
414
418 constexpr iterator end() {
419 return iterator(this, npos);
420 }
421
425 constexpr const_iterator begin() const {
426 return const_iterator(this, _root);
427 }
428
432 constexpr const_iterator end() const {
433 return const_iterator(this, npos);
434 }
435
437
440 class iterator {
441 public:
442 ~iterator() {
443 _list = nullptr;
444 }
445
446 // prefix operator
447 constexpr friend iterator& operator++(iterator& rhs) {
448 rhs._n = rhs._list->_next(rhs._n);
449 return rhs;
450 }
451
452 constexpr friend iterator operator++(iterator& lhs, int) {
453 iterator prev = lhs;
454 ++lhs;
455 return prev;
456 }
457
458 constexpr value_t& operator*() {
459 return *(_list->_table[_n].value);
460 }
461
462 constexpr value_t* operator->() {
463 return &*(_list->_table[_n].value);
464 }
465
466 constexpr bool operator==(const iterator& it) {
467 return _list == it._list and _n == it._n;
468 }
469
470 constexpr bool operator!=(const iterator& it) {
471 return _list != it._list or _n != it._n;
472 }
473
474 private:
475 list* _list;
476 size_t _n;
477 friend list;
478
479 iterator(list* ls, size_t n)
480 : _list(ls)
481 , _n(n) {
482 }
483 };
484
488 public:
490 _list = nullptr;
491 }
492
493 // prefix operator
494 constexpr friend const_iterator& operator++(const_iterator& rhs) {
495 if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
496 return rhs;
497 }
498 rhs._n = npos;
499 return rhs;
500 }
501
502 constexpr friend const_iterator operator++(const_iterator& lhs, int) {
503 const_iterator prev = lhs;
504 ++lhs;
505 return prev;
506 }
507
508 constexpr const value_t& operator*() {
509 return *(_list->_table[_n].value);
510 }
511
512 constexpr const value_t* operator->() {
513 return &*(_list->_table[_n].value);
514 }
515
516 constexpr bool operator==(const const_iterator& it) {
517 return _list == it._list and _n == it._n;
518 }
519
520 constexpr bool operator!=(const const_iterator& it) {
521 return _list != it._list or _n != it._n;
522 }
523
524 private:
525 const list* _list;
526 size_t _n;
527 friend list;
528
529 const_iterator(const list* ls, size_t n)
530 : _list(ls)
531 , _n(n) {
532 }
533 };
534
535private:
537 dynarray<size_t> _freed;
538 size_t _root, _last, _size;
539
540 friend class iterator;
541
542 constexpr void _expand() {
543 _table.creallocate(fennec::max(_table.capacity(), size_t(1)) * 2);
544 }
545
546 struct node {
547 optional<value_t> value;
548 size_t prev, next;
549
550 constexpr node()
551 : value()
552 , prev(npos)
553 , next(npos) {
554 }
555
556 constexpr node(size_t p, size_t n)
557 : value()
558 , prev(p)
559 , next(n) {
560 }
561
562 constexpr node(size_t p, size_t n, value_t&& val)
563 : value(fennec::forward<value_t>(val))
564 , prev(p)
565 , next(n) {
566 }
567
568 constexpr ~node() = default;
569
570 constexpr void clear() {
571 value = nullopt;
572 prev = npos;
573 next = npos;
574 }
575 };
576
577 constexpr size_t _next(size_t n) const {
578 return _table[n].next;
579 }
580
581 constexpr size_t _prev(size_t n) const {
582 return _table[n].prev;
583 }
584
585 constexpr size_t _walk(size_t i) const {
586 size_t n = _root;
587 if (n == npos) return n;
588 while (i > 0 && n != npos) {
589 n = _next(n); --i;
590 }
591 return n;
592 }
593
594 constexpr size_t _next_free() {
595 if (not _freed.empty()) {
596 size_t n = _freed.back();
597 _freed.pop_back();
598 return n;
599 }
600 return _size;
601 }
602
603 template<typename...ArgsT>
604 constexpr size_t _insert(size_t n, ArgsT&&...args) {
605 if (size() == capacity()) {
606 _expand();
607 }
608
609 size_t i = _next_free();
610 ++_size;
611 fennec::construct(&_table[i].value, fennec::forward<ArgsT>(args)...);
612
613 if (_root == npos) {
614 _table[i].prev = npos;
615 _table[i].next = npos;
616 _root = _last = i;
617 return i;
618 }
619
620 if (n == npos) {
621 _table[_last].next = i;
622 _table[i].prev = _last;
623 _table[i].next = npos;
624 _last = i;
625 return i;
626 }
627
628 _table[i].prev = _prev(n);
629 _table[i].next = n;
630 _table[n].prev = i;
631 _root = n == _root ? i : _root;
632 return i;
633 }
634
635 constexpr void _erase(size_t n) {
636 if (n == npos) return;
637
638 fennec::destruct(&_table[n].value);
639 _freed.push_back(n);
640 --_size;
641
642 size_t prev = _prev(n);
643 size_t next = _next(n);
644
645 if (prev != npos) {
646 _table[prev].next = next;
647 }
648
649 if (next != npos) {
650 _table[next].prev = prev;
651 }
652
653 _root = (n == _root) ? next : _root;
654 _last = (n == _last) ? prev : _last;
655 }
656};
657
658}
659
660#endif // FENNEC_CONTAINERS_LIST_H
This header contains structures and classes related to allocating blocks of memory.
Iterator Class for Const Access.
Definition list.h:487
Iterator Class.
Definition list.h:440
A header containing the definition for a dynamically allocated array.
A header containing the definition for a linked list of values.
Common
constexpr genType min(genType x, genType y)
Returns if otherwise it returns .
Definition common.h:688
A header containing the definition for a container with an optionally present variable.
Container to hold a memory allocation.
Definition allocator.h:285
constexpr size_t capacity() const
Getter for the number of elements n of type T that the allocation can hold.
Definition allocator.h:617
constexpr void deallocate() noexcept
Release the block of memory.
Definition allocator.h:505
constexpr void creallocate(size_t n, align_t align=zero< align_t >()) noexcept
Reallocate the block with a new size. Contents are copied to the new allocation.
Definition allocator.h:541
typename _rebind< Alloc, TypeT >::type rebind
Rebinds the allocator type to produce an element type of type TypeT
Definition allocator.h:134
Wrapper for dynamically sized and allocated arrays.
Definition dynarray.h:64
constexpr bool empty() const
Definition dynarray.h:343
constexpr void pop_back()
Erase last element.
Definition dynarray.h:505
constexpr void push_back(const TypeT &val)
Push Back Copy.
Definition dynarray.h:483
constexpr TypeT & back()
Definition dynarray.h:387
Data Structure defining lists of elements.
Definition list.h:67
constexpr size_t capacity() const
Definition list.h:175
constexpr const_iterator begin() const
Const C++ Iterator Specification begin()
Definition list.h:425
constexpr size_t push_back(value_t &&x)
Push Back Move.
Definition list.h:349
constexpr size_t emplace_front(ArgsT &&...args)
Emplace Front.
Definition list.h:335
constexpr value_t & operator[](int i)
Array Access Operator.
Definition list.h:199
constexpr iterator begin()
C++ Iterator Specification begin()
Definition list.h:411
constexpr list & operator=(const list &l)
Copy Assignment Operator.
Definition list.h:138
constexpr void pop_front()
Pop Front, erases first element.
Definition list.h:380
static constexpr size_t npos
Constant representing a non-existant position.
Definition list.h:80
constexpr const value_t & back() const
Const Access Back Element.
Definition list.h:243
TypeT value_t
Alias for the value type.
Definition list.h:78
constexpr value_t & back()
Access Back Element.
Definition list.h:236
constexpr list(const list &l)
Copy Constructor, copies all elements in l with optimized layout.
Definition list.h:100
constexpr bool empty() const
Definition list.h:181
constexpr void clear()
Clears the list, destructing all elements in order.
Definition list.h:392
constexpr iterator end()
C++ Iterator Specification end()
Definition list.h:418
typename allocator_traits< Alloc >::template rebind< node > alloc_t
Alias for the allocator type, rebound to list nodes.
Definition list.h:76
constexpr list & operator=(list &&l) noexcept
Move Assignment Operator.
Definition list.h:150
constexpr const value_t & front() const
Const Access Front Element.
Definition list.h:229
constexpr size_t push_back(const value_t &x)
Push Back Copy.
Definition list.h:342
constexpr const_iterator end() const
Const C++ Iterator Specification end()
Definition list.h:432
constexpr size_t push_front(const value_t &x)
Push Front Copy.
Definition list.h:319
constexpr size_t insert(const iterator &it, value_t &&x)
Move Insertion.
Definition list.h:271
constexpr size_t insert(size_t i, value_t &&x)
Move Insertion.
Definition list.h:294
constexpr ~list()
Destructor, destructs all elements then releases the allocation.
Definition list.h:121
constexpr size_t size() const
Definition list.h:169
constexpr value_t & front()
Access Front Element.
Definition list.h:222
constexpr size_t push_front(value_t &&x)
Push Front Move.
Definition list.h:326
constexpr size_t insert(const iterator &it, const value_t &x)
Copy Insertion.
Definition list.h:261
constexpr list(list &&l) noexcept
Move Constructor, takes ownership of the list.
Definition list.h:111
constexpr size_t emplace(size_t i, ArgsT &&...args)
Emplace Insertion.
Definition list.h:309
constexpr list()
Default Constructor, initializes an empty list.
Definition list.h:93
constexpr void pop_back()
Pop Back, erases first element.
Definition list.h:386
constexpr void erase(size_t i)
Erase Element.
Definition list.h:365
constexpr size_t emplace_back(ArgsT &&...args)
Emplace Back.
Definition list.h:358
constexpr void erase(const iterator &it)
Erase Element.
Definition list.h:374
constexpr size_t insert(size_t i, const value_t &x)
Copy Insertion.
Definition list.h:281
constexpr const value_t & operator[](int i) const
Const Array Access Operator.
Definition list.h:212
Structure to hold an optional value.
Definition optional.h:51
constexpr T && forward(remove_reference_t< T > &x) noexcept
forwards reference types to extend their lifetime
Definition utility.h:75
constexpr remove_reference_t< T > && move(T &&x) noexcept
produces an x-value type to indicate x may be "moved"
Definition utility.h:92