MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
mtcore::GenList< T > Struct Template Reference

Represents a generational list where removed items are marked and recycled. More...

#include <gen_list.hpp>

Inheritance diagram for mtcore::GenList< T >:

Classes

struct  ConstIter
 An iterator that iterates over values (copies) of each stored element. More...
 
struct  HandleIter
 An iterator that iterates over all handles of each stored element. More...
 
struct  PtrIter
 An iterator that iterates over pointers to each stored element. More...
 

Public Member Functions

Result< void, AllocationErrorinit (Allocator &alloc, size_t initCapacity=64)
 Initializes a generational list.
 
void deinit (Allocator &alloc)
 Deinitializes a list.
 
Result< Handle, CollectionAddNoAllocationErroradd (const T &item) noexcept
 Adds a new item to the generational list Will first try to recycle removed items Will then try to add a new item if there is remaining capacity Will fail if there is no remaining capacity.
 
Result< Handle, AllocationErroradd (Allocator &alloc, const T &item) noexcept
 Adds a new item to the generational list Will first try to recycle removed items Will then try to add a new item if there is remaining capacity Will reallocate if there is no remaining capacity.
 
const T & operator[] (const Handle &handle) const noexcept
 References an element by handle.
 
T & operator[] (const Handle &handle) noexcept
 References an element by handle.
 
Optional< T > at (const Handle &handle) const noexcept
 Gets an item at a handle If item does not exist, or handle is no longer valid, will return nullopt.
 
bool is_handle_valid (const Handle &handle) const noexcept
 Checks if a handle is currently valid.
 
size_t size () const noexcept
 Size of GenList (number of live elements)
 
size_t capacity () const noexcept
 Capacity of GenList.
 
void remove (const Handle &handle) noexcept
 Will remove the element at a handle Aborts if handle is no longer valid.
 
PtrIter ptr_iter () noexcept
 Iterates over pointers of stored elements Allows changing stored elements directly.
 
ConstIter iter () const noexcept
 Iterates over copied values of stored elements.
 
HandleIter handles () const noexcept
 Iterates over handles for stored elements Allows accessing and manipulating elements by handles Since removed elements are only marked deleted, it is safe to remove handles while iterating so long as you do not try to access a deleted element by handle once it's been removed Note that adding elements while iterating may Result in undefined behavior.
 

Detailed Description

template<typename T>
struct mtcore::GenList< T >

Represents a generational list where removed items are marked and recycled.

Each element is referred to with a handle (index + generation) instead of pointers. This allows elements to be reliably referenced, even after a memory copy (such as reallocation). Additionally, it also allows detection of dead handles (i.e. the referenced element was removed), which may be important when lifetimes are complex.

Note that this data structure is not memory stable as it uses an ArrayList which does memory copies when it runs out of memory.

Accessing elements is \(O(1)\) Adding elements is \(O(N)\) (though it should be fast as we check 64 slots at once) Removing elements is \(O(1)\)

Template Parameters
TStored element type

Definition at line 59 of file gen_list.hpp.

Member Function Documentation

◆ add() [1/2]

template<typename T>
Result< Handle, AllocationError > mtcore::GenList< T >::add ( Allocator & alloc,
const T & item )
inlinenoexcept

Adds a new item to the generational list Will first try to recycle removed items Will then try to add a new item if there is remaining capacity Will reallocate if there is no remaining capacity.

Parameters
allocAllocator to use for growing memory
itemItem to add
Returns
Handle (on success) or failure

Definition at line 124 of file gen_list.hpp.

124 {
125 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
126 if (auto res = add(item); res.is_success()) {
127 return res.value();
128 }
129
130 entries.reserve(alloc, entries.capacity() * 2);
131 dead.resize(alloc, entries.capacity(), true);
132
133 return add(item).value();
134 }
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Represents a generational list where removed items are marked and recycled.
Definition gen_list.hpp:59
Result< Handle, CollectionAddNoAllocationError > add(const T &item) noexcept
Adds a new item to the generational list Will first try to recycle removed items Will then try to add...
Definition gen_list.hpp:96
size_t size() const noexcept
Size of GenList (number of live elements)
Definition gen_list.hpp:194
size_t capacity() const noexcept
Capacity of GenList.
Definition gen_list.hpp:197
Here is the call graph for this function:

◆ add() [2/2]

template<typename T>
Result< Handle, CollectionAddNoAllocationError > mtcore::GenList< T >::add ( const T & item)
inlinenoexcept

Adds a new item to the generational list Will first try to recycle removed items Will then try to add a new item if there is remaining capacity Will fail if there is no remaining capacity.

Parameters
itemItem to add
Returns
Handle (on success) or failure

Definition at line 96 of file gen_list.hpp.

96 {
97 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
98 auto index = dead.first_set();
99 if (index.has_value() && index.value() < entries.size()) {
100 auto i = *index;
101 ensure(dead[i], "BAD INDEX");
102 entries[i].generation += 1;
103 entries[i].item = item;
104 dead.set(i, false);
105 return success(Handle{i, entries[i].generation});
106 }
107
108 size_t i = entries.size();
109 if (auto res = entries.push(Gen{item, 0}); res.is_error()) {
110 return res.error();
111 }
112 return success(Handle{i, 0});
113 }
Success< void > success()
Creates a successful void Result object.
Definition result.hpp:398
Here is the call graph for this function:
Here is the caller graph for this function:

◆ at()

template<typename T>
Optional< T > mtcore::GenList< T >::at ( const Handle & handle) const
inlinenoexcept

Gets an item at a handle If item does not exist, or handle is no longer valid, will return nullopt.

Parameters
handleHandle (from add) to use to access element
Returns
Copy of element (if handle is valid), nullopt otherwise

Definition at line 164 of file gen_list.hpp.

164 {
165 auto index = handle.index;
166 if (index >= entries.size()) {
167 return nullopt;
168 }
169 if (entries[index].generation != handle.generation) {
170 return nullopt;
171 }
172 return entries[index].item;
173 }

◆ capacity()

template<typename T>
size_t mtcore::GenList< T >::capacity ( ) const
inlinenodiscardnoexcept

Capacity of GenList.

Definition at line 197 of file gen_list.hpp.

197{ return entries.capacity(); }
Here is the caller graph for this function:

◆ deinit()

template<typename T>
void mtcore::GenList< T >::deinit ( Allocator & alloc)
inline

Deinitializes a list.

Parameters
allocAllocator for memory cleanup

Definition at line 83 of file gen_list.hpp.

83 {
84 entries.deinit(alloc);
85 dead.deinit(alloc);
86 }

◆ handles()

template<typename T>
HandleIter mtcore::GenList< T >::handles ( ) const
inlinenoexcept

Iterates over handles for stored elements Allows accessing and manipulating elements by handles Since removed elements are only marked deleted, it is safe to remove handles while iterating so long as you do not try to access a deleted element by handle once it's been removed Note that adding elements while iterating may Result in undefined behavior.

Returns
Iterator over handles for elements

Definition at line 300 of file gen_list.hpp.

300{ return HandleIter{*this}; }
An iterator that iterates over all handles of each stored element.
Definition gen_list.hpp:258

◆ init()

template<typename T>
Result< void, AllocationError > mtcore::GenList< T >::init ( Allocator & alloc,
size_t initCapacity = 64 )
inline

Initializes a generational list.

Parameters
allocAllocator for memory allocation
initCapacityInitial list capacity
Returns
success or failure

Definition at line 67 of file gen_list.hpp.

67 {
68 if (auto res = entries.init(alloc, initCapacity); res.is_error()) {
69 return res;
70 }
71 if (auto res = dead.init(alloc, initCapacity); res.is_error()) {
72 entries.deinit(alloc);
73 return res;
74 }
75 dead.set_all(false);
76 return success();
77 }
Result< void, AllocationError > init(Allocator &alloc, size_t initCapacity=64)
Initializes a generational list.
Definition gen_list.hpp:67
Here is the call graph for this function:

◆ is_handle_valid()

template<typename T>
bool mtcore::GenList< T >::is_handle_valid ( const Handle & handle) const
inlinenodiscardnoexcept

Checks if a handle is currently valid.

Parameters
handleHandle to check
Returns
true if valid, false otherwise

Definition at line 180 of file gen_list.hpp.

180 {
181 if (handle.index >= entries.size()) {
182 return false;
183 }
184 if (dead[handle.index]) {
185 return false;
186 }
187 if (entries[handle.index].generation != handle.generation) {
188 return false;
189 }
190 return true;
191 }
Here is the caller graph for this function:

◆ iter()

template<typename T>
ConstIter mtcore::GenList< T >::iter ( ) const
inlinenoexcept

Iterates over copied values of stored elements.

Returns
Iterator over copies of elements

Definition at line 289 of file gen_list.hpp.

289{ return ConstIter{*this}; }
An iterator that iterates over values (copies) of each stored element.
Definition gen_list.hpp:235

◆ operator[]() [1/2]

template<typename T>
const T & mtcore::GenList< T >::operator[] ( const Handle & handle) const
inlinenoexcept

References an element by handle.

Parameters
handleHandle (from add) to use to access element
Returns
Reference to element

Definition at line 141 of file gen_list.hpp.

141 {
142 auto index = handle.index;
143 ensure(entries[index].generation == handle.generation, "INVALID HANDLE, BAD GENERATION");
144 return entries[index].item;
145 }

◆ operator[]() [2/2]

template<typename T>
T & mtcore::GenList< T >::operator[] ( const Handle & handle)
inlinenoexcept

References an element by handle.

Parameters
handleHandle (from add) to use to access element
Returns
Reference to element

Definition at line 152 of file gen_list.hpp.

152 {
153 auto index = handle.index;
154 ensure(entries[index].generation == handle.generation, "INVALID HANDLE, BAD GENERATION");
155 return entries[index].item;
156 }

◆ ptr_iter()

template<typename T>
PtrIter mtcore::GenList< T >::ptr_iter ( )
inlinenoexcept

Iterates over pointers of stored elements Allows changing stored elements directly.

Returns
Iterator over pointers to elements

Definition at line 283 of file gen_list.hpp.

283{ return PtrIter{*this}; }
An iterator that iterates over pointers to each stored element.
Definition gen_list.hpp:212

◆ remove()

template<typename T>
void mtcore::GenList< T >::remove ( const Handle & handle)
inlinenoexcept

Will remove the element at a handle Aborts if handle is no longer valid.

Parameters
handleHandle to remove element at

Definition at line 204 of file gen_list.hpp.

204 {
205 ensure(is_handle_valid(handle), "BAD HANDLE");
206 dead[handle.index] = true;
207 }
bool is_handle_valid(const Handle &handle) const noexcept
Checks if a handle is currently valid.
Definition gen_list.hpp:180
Here is the call graph for this function:

◆ size()

template<typename T>
size_t mtcore::GenList< T >::size ( ) const
inlinenodiscardnoexcept

Size of GenList (number of live elements)

Definition at line 194 of file gen_list.hpp.

194{ return entries.size() - dead.pop_count(); }
Here is the caller graph for this function:

The documentation for this struct was generated from the following file: