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 entries.reserve(alloc, entries.capacity() * 2);
131 dead.resize(alloc, entries.capacity(), true);
132
133 return add(item).value();
134 }
135
141 const T &operator[](const Handle &handle) const noexcept {
142 auto index = handle.index;
143 ensure(entries[index].generation == handle.generation, "INVALID HANDLE, BAD GENERATION");
144 return entries[index].item;
145 }
146
152 T &operator[](const Handle &handle) noexcept {
153 auto index = handle.index;
154 ensure(entries[index].generation == handle.generation, "INVALID HANDLE, BAD GENERATION");
155 return entries[index].item;
156 }
157
164 Optional<T> at(const Handle &handle) const noexcept {
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 }
174
180 [[nodiscard]] bool is_handle_valid(const Handle &handle) const noexcept {
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 }
192
194 [[nodiscard]] size_t size() const noexcept { return entries.size() - dead.pop_count(); }
195
197 [[nodiscard]] size_t capacity() const noexcept { return entries.capacity(); }
198
204 void remove(const Handle &handle) noexcept {
205 ensure(is_handle_valid(handle), "BAD HANDLE");
206 dead[handle.index] = true;
207 }
208
212 struct PtrIter {
214 size_t index = 0;
215
221 while (index < list.entries.size()) {
222 mtdefer { ++index; };
223 if (list.dead[index]) {
224 continue;
225 }
226 return &list.entries[index].item;
227 }
228 return nullopt;
229 }
230 };
231
235 struct ConstIter {
236 const GenList &list;
237 size_t index = 0;
238
244 while (index < list.entries.size()) {
245 mtdefer { ++index; };
246 if (list.dead[index]) {
247 continue;
248 }
249 return list.entries[index].item;
250 }
251 return nullopt;
252 }
253 };
254
258 struct HandleIter {
259 const GenList &list;
260 size_t index = 0;
261
267 while (index < list.entries.size()) {
268 mtdefer { ++index; };
269 if (list.dead[index]) {
270 continue;
271 }
272 return Handle{index, list.entries[index].generation};
273 }
274 return nullopt;
275 }
276 };
277
283 PtrIter ptr_iter() noexcept { return PtrIter{*this}; }
284
289 ConstIter iter() const noexcept { return ConstIter{*this}; }
290
300 HandleIter handles() const noexcept { return HandleIter{*this}; }
301
302 private:
303 struct Gen {
304 T item;
305 size_t generation;
306 };
307
308 ArrayList<Gen> entries = {};
309 Bitset dead = {};
310 };
311} // namespace mtcore
312
313#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:235
Optional< T > next()
Gets the next element.
Definition gen_list.hpp:243
An iterator that iterates over all handles of each stored element.
Definition gen_list.hpp:258
Optional< Handle > next()
Gets the next element.
Definition gen_list.hpp:266
An iterator that iterates over pointers to each stored element.
Definition gen_list.hpp:212
Optional< T * > next()
Gets the pointer to the next stored element.
Definition gen_list.hpp:220
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:283
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:164
HandleIter handles() const noexcept
Iterates over handles for stored elements Allows accessing and manipulating elements by handles Since...
Definition gen_list.hpp:300
bool is_handle_valid(const Handle &handle) const noexcept
Checks if a handle is currently valid.
Definition gen_list.hpp:180
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:141
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:194
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:289
void deinit(Allocator &alloc)
Deinitializes a list.
Definition gen_list.hpp:83
size_t capacity() const noexcept
Capacity of GenList.
Definition gen_list.hpp:197
T & operator[](const Handle &handle) noexcept
References an element by handle.
Definition gen_list.hpp:152
void remove(const Handle &handle) noexcept
Will remove the element at a handle Aborts if handle is no longer valid.
Definition gen_list.hpp:204
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