19#ifndef MTCORE_STABLE_VEC_HPP
20#define MTCORE_STABLE_VEC_HPP
51 Segment *next =
nullptr;
55 Segment *end = &start;
58 size_t totalCapacity = 0;
76 if (
s ==
nullptr ||
index >=
r.size()) {
106 if (
s ==
nullptr ||
index >=
r.size()) {
136 if (
s ==
nullptr ||
index >=
r.size()) {
156 ensure(start.elements.head,
"NOT INITIALIZED");
157 return {0, *
this, 0, &start};
165 ensure(start.elements.head,
"NOT INITIALIZED");
166 return {0, *
this, 0, &start};
174 ensure(start.elements.head,
"NOT INITIALIZED");
175 return {0, *
this, 0, &start};
182 [[nodiscard]]
size_t size() const noexcept {
return len; }
191 ensure(initCapacity > 0,
"NO INITIAL CAPACITY");
192 ensure(start.elements.head ==
nullptr,
"ALREADY INITIALIZED");
193 ensure(start.elements.size() == 0,
"ALREADY INITIALIZED");
194 ensure(start.next ==
nullptr,
"ALREADY INITIALIZED");
196 auto allocRes = alloc.
create_many<T>(initCapacity);
197 if (allocRes.is_error()) {
198 return allocRes.error();
201 start.elements = *allocRes;
202 totalCapacity = initCapacity;
213 ensure(start.elements.head ==
nullptr,
"ALREADY INITIALIZED");
214 ensure(list.size() > 0,
"NO INITIAL CAPACITY");
215 ensure(!start.elements.head,
"ALREADY INITIALIZED");
216 ensure(!start.elements.size(),
"ALREADY INITIALIZED");
217 ensure(!start.next,
"ALREADY INITIALIZED");
220 if (allocRes.is_error()) {
221 return allocRes.error();
223 totalCapacity = list.size();
225 start.elements = *allocRes;
228 for (
const auto &elem: list) {
229 start.elements[i++] = elem;
242 if (start.elements.head !=
nullptr) {
245 if (start.next !=
nullptr) {
246 Segment *cur = start.next;
248 Segment *next = cur->next;
263 ensure(start.elements.head,
"NOT INITIALIZED");
264 Segment *prev = &start;
265 Segment *cur = start.next;
267 size_t remaining =
size();
269 if (remaining > prev->elements.len) {
270 remaining -= prev->elements.len;
271 auto next = cur->next;
277 prev->next =
nullptr;
279 Segment *next = cur->next;
280 totalCapacity -= cur->elements.size();
296 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
300 if (endIndex < cur->elements.size()) {
302 cur->elements[endIndex++] = elem;
315 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
318 if (endIndex < cur->elements.size()) {
320 cur->elements[endIndex++] = elem;
324 auto allocSegRes = alloc.create<Segment>();
326 if (allocSegRes.is_error()) {
327 return allocSegRes.error();
330 auto allocElemRes = alloc.create_many<T>(cur->elements.size() + cur->elements.size() / 2);
331 if (allocElemRes.is_error()) {
332 alloc.destroy(*allocSegRes);
333 return allocElemRes.error();
336 cur->next = *allocSegRes;
340 cur->elements = *allocElemRes;
341 cur->elements[endIndex++] = elem;
343 totalCapacity += cur->elements.size();
352 [[nodiscard]]
const T &
operator[](
size_t index)
const noexcept {
353 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
363 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
372 [[nodiscard]]
const T &
at(
size_t index)
const noexcept {
373 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
374 ensure(index < len,
"OUT OF BOUNDS ACCESS");
375 const Segment *cur = &start;
377 if (index < cur->elements.len) {
378 return cur->elements[index];
380 index -= cur->elements.len;
391 [[nodiscard]] T &
at(
size_t index)
noexcept {
392 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
393 ensure(index < len,
"OUT OF BOUNDS ACCESS");
394 Segment *cur = &start;
396 if (index < cur->elements.size()) {
397 return cur->elements[index];
399 index -= cur->elements.size();
410 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
411 ensure(other.start.elements.head !=
nullptr,
"NOT INITIALIZED");
412 if (len != other.len) {
415 for (
size_t i = 0; i < len; ++i) {
416 if (
at(i) != other.
at(i)) {
433 ensure(start.elements.head !=
nullptr,
"NOT INITIALIZED");
439 [[nodiscard]]
size_t capacity()
const {
return totalCapacity; }
constexpr auto nullopt
Placeholder value for an empty Optional.
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
#define unreachable(...)
Marks code as unreachable.
#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.
Error< Underlying > error(Underlying err)
Creates an error.
constexpr bool is_mutable_addressable
Boolean check for if something has the trait Addressable.
Core library for C++ with Zig-related functionality.
Represents a memory allocator Exact behavior depends on the underlying VTable used Should use the a_*...
void destroy_many(Slice< T > s)
Destroys objects allocated by this allocator by calling the destructors and freeing memory.
Result< Slice< T >, AllocationError > create_many(size_t count=1)
Allocates some block of memory with an allocator with a known type Will call default constructor on t...
void destroy(T *&ptr)
Destroys an object allocated by this allocator by calling the destructor and freeing memory.
Represents a value that may or may not exist (an "Optional" value) Similar concept to std::optional,...
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Const reference for mutating elements Using custom iterator for speed.
Optional< T > next()
Gets next item.
Pointer iterator for mutating elements Using custom iterator for speed.
Optional< const T * > next()
Gets next item.
Pointer iterator for mutating elements Using custom iterator for speed.
Optional< T * > next()
Gets next item.
Segmented list where each segment contains multiple nodes Allows growing the list without having to i...
T & at(size_t index) noexcept
Access element at index.
ConstPtrIter ptr_iter() const noexcept
Const iterator that gives const element pointers.
Result< void, CollectionAddNoAllocationError > push(const T &elem) noexcept
Pushes a new element.
Result< void, AllocationError > init(Allocator &alloc, std::initializer_list< T > list)
Initializes a segmented list.
const T & operator[](size_t index) const noexcept
Access element at index.
void deinit(Allocator &alloc)
Cleans up memory tied to segmented list.
Result< void, AllocationError > push(Allocator &alloc, const T &elem) noexcept
Pushes a new element.
size_t size() const noexcept
Gets the size of the list.
bool operator!=(const SegmentedList &other)
void pop()
remove last element
Result< void, AllocationError > init(Allocator &alloc, size_t initCapacity)
Initializes a segmented list.
PtrIter ptr_iter() noexcept
Mutable iterator that gives element pointers.
const T & at(size_t index) const noexcept
Access element at index.
T & operator[](size_t index) noexcept
Access element at index.
void drop_unused_segments(Allocator &alloc)
Lowers memory footprint by dropping unused segments.
bool operator==(const SegmentedList &other)
ConstIter iter() const noexcept
Const iterator that gives element references.
A Slice which is just a pointer + length Accessing elements through the array operator will do bounds...