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 if (auto r = entries.reserve(alloc, entries.capacity() * 2); r.is_error()) {
131 return r.error();
132 };
133 dead.resize(alloc, entries.capacity(), true);
134
135 return add(item).value();
136 }
#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:196
size_t capacity() const noexcept
Capacity of GenList.
Definition gen_list.hpp:199
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 166 of file gen_list.hpp.

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

◆ capacity()

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

Capacity of GenList.

Definition at line 199 of file gen_list.hpp.

199{ 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 302 of file gen_list.hpp.

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

◆ 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 182 of file gen_list.hpp.

182 {
183 if (handle.index >= entries.size()) {
184 return false;
185 }
186 if (dead[handle.index]) {
187 return false;
188 }
189 if (entries[handle.index].generation != handle.generation) {
190 return false;
191 }
192 return true;
193 }
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 291 of file gen_list.hpp.

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

◆ 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 143 of file gen_list.hpp.

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

◆ 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 154 of file gen_list.hpp.

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

◆ 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 285 of file gen_list.hpp.

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

◆ 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 206 of file gen_list.hpp.

206 {
207 ensure(is_handle_valid(handle), "BAD HANDLE");
208 dead[handle.index] = true;
209 }
bool is_handle_valid(const Handle &handle) const noexcept
Checks if a handle is currently valid.
Definition gen_list.hpp:182
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 196 of file gen_list.hpp.

196{ 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: