MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
gen_list.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 Matthew Tolman
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*/
18
19#pragma once
20
21#ifndef MTCORE_GEN_LIST_HPP
22#define MTCORE_GEN_LIST_HPP
23
24#include "../alloc.hpp"
25#include "../core.hpp"
26#include "array_list.hpp"
27#include "bitset.hpp"
28#include "optional.hpp"
29#include "result.hpp"
30
31namespace mtcore {
36 struct Handle {
37 size_t index;
38 size_t generation;
39 };
40
58 template<typename T>
59 struct GenList {
60
67 Result<void, AllocationError> init(Allocator &alloc, size_t initCapacity = 64) {
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 }
78
83 void deinit(Allocator &alloc) {
84 entries.deinit(alloc);
85 dead.deinit(alloc);
86 }
87
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 }
114
124 Result<Handle, AllocationError> add(Allocator &alloc, const T &item) noexcept {
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 }
137
143 const T &operator[](const Handle &handle) const noexcept {
144 auto index = handle.index;
145 ensure(entries[index].generation == handle.generation, "INVALID HANDLE, BAD GENERATION");
146 return entries[index].item;
147 }
148
154 T &operator[](const Handle &handle) noexcept {
155 auto index = handle.index;
156 ensure(entries[index].generation == handle.generation, "INVALID HANDLE, BAD GENERATION");
157 return entries[index].item;
158 }
159
166 Optional<T> at(const Handle &handle) const noexcept {
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 }
176
182 [[nodiscard]] bool is_handle_valid(const Handle &handle) const noexcept {
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 }
194
196 [[nodiscard]] size_t size() const noexcept { return entries.size() - dead.pop_count(); }
197
199 [[nodiscard]] size_t capacity() const noexcept { return entries.capacity(); }
200
206 void remove(const Handle &handle) noexcept {
207 ensure(is_handle_valid(handle), "BAD HANDLE");
208 dead[handle.index] = true;
209 }
210
214 struct PtrIter {
216 size_t index = 0;
217
223 while (index < list.entries.size()) {
224 mtdefer { ++index; };
225 if (list.dead[index]) {
226 continue;
227 }
228 return &list.entries[index].item;
229 }
230 return nullopt;
231 }
232 };
233
237 struct ConstIter {
238 const GenList &list;
239 size_t index = 0;
240
246 while (index < list.entries.size()) {
247 mtdefer { ++index; };
248 if (list.dead[index]) {
249 continue;
250 }
251 return list.entries[index].item;
252 }
253 return nullopt;
254 }
255 };
256
260 struct HandleIter {
261 const GenList &list;
262 size_t index = 0;
263
269 while (index < list.entries.size()) {
270 mtdefer { ++index; };
271 if (list.dead[index]) {
272 continue;
273 }
274 return Handle{index, list.entries[index].generation};
275 }
276 return nullopt;
277 }
278 };
279
285 PtrIter ptr_iter() noexcept { return PtrIter{*this}; }
286
291 ConstIter iter() const noexcept { return ConstIter{*this}; }
292
302 HandleIter handles() const noexcept { return HandleIter{*this}; }
303
304 private:
305 struct Gen {
306 T item;
307 size_t generation;
308 };
309
310 ArrayList<Gen> entries = {};
311 Bitset dead = {};
312 };
313} // namespace mtcore
314
315#endif // MTCORE_GEN_LIST_HPP
constexpr auto nullopt
Placeholder value for an empty Optional.
Definition optional.hpp:409
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
#define mtdefer
Defer statement that will mtdefer execution until the scope is left, at which point the code will run...
Success< void > success()
Creates a successful void Result object.
Definition result.hpp:398
Core library for C++ with Zig-related functionality.
Represents a memory allocator Exact behavior depends on the underlying VTable used Should use the a_*...
An iterator that iterates over values (copies) of each stored element.
Definition gen_list.hpp:237
Optional< T > next()
Gets the next element.
Definition gen_list.hpp:245
An iterator that iterates over all handles of each stored element.
Definition gen_list.hpp:260
Optional< Handle > next()
Gets the next element.
Definition gen_list.hpp:268
An iterator that iterates over pointers to each stored element.
Definition gen_list.hpp:214
Optional< T * > next()
Gets the pointer to the next stored element.
Definition gen_list.hpp:222
Represents a generational list where removed items are marked and recycled.
Definition gen_list.hpp:59
PtrIter ptr_iter() noexcept
Iterates over pointers of stored elements Allows changing stored elements directly.
Definition gen_list.hpp:285
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.
Definition gen_list.hpp:166
HandleIter handles() const noexcept
Iterates over handles for stored elements Allows accessing and manipulating elements by handles Since...
Definition gen_list.hpp:302
bool is_handle_valid(const Handle &handle) const noexcept
Checks if a handle is currently valid.
Definition gen_list.hpp:182
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
const T & operator[](const Handle &handle) const noexcept
References an element by handle.
Definition gen_list.hpp:143
Result< Handle, AllocationError > add(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...
Definition gen_list.hpp:124
size_t size() const noexcept
Size of GenList (number of live elements)
Definition gen_list.hpp:196
Result< void, AllocationError > init(Allocator &alloc, size_t initCapacity=64)
Initializes a generational list.
Definition gen_list.hpp:67
ConstIter iter() const noexcept
Iterates over copied values of stored elements.
Definition gen_list.hpp:291
void deinit(Allocator &alloc)
Deinitializes a list.
Definition gen_list.hpp:83
size_t capacity() const noexcept
Capacity of GenList.
Definition gen_list.hpp:199
T & operator[](const Handle &handle) noexcept
References an element by handle.
Definition gen_list.hpp:154
void remove(const Handle &handle) noexcept
Will remove the element at a handle Aborts if handle is no longer valid.
Definition gen_list.hpp:206
Handle to an item in the list.
Definition gen_list.hpp:36
size_t generation
Definition gen_list.hpp:38
Represents a value that may or may not exist (an "Optional" value) Similar concept to std::optional,...
Definition optional.hpp:235
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Definition result.hpp:170