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

Segmented list where each segment contains multiple nodes Allows growing the list without having to invalidate all previous memory addresses. More...

#include <segmented_list.hpp>

Classes

struct  ConstIter
 Const reference for mutating elements Using custom iterator for speed. More...
 
struct  ConstPtrIter
 Pointer iterator for mutating elements Using custom iterator for speed. More...
 
struct  PtrIter
 Pointer iterator for mutating elements Using custom iterator for speed. More...
 

Public Types

using Elem = T
 

Public Member Functions

PtrIter ptr_iter () noexcept
 Mutable iterator that gives element pointers.
 
ConstPtrIter ptr_iter () const noexcept
 Const iterator that gives const element pointers.
 
ConstIter iter () const noexcept
 Const iterator that gives element references.
 
size_t size () const noexcept
 Gets the size of the list.
 
Result< void, AllocationErrorinit (Allocator &alloc, size_t initCapacity)
 Initializes a segmented list.
 
Result< void, AllocationErrorinit (Allocator &alloc, std::initializer_list< T > list)
 Initializes a segmented list.
 
void deinit (Allocator &alloc)
 Cleans up memory tied to segmented list.
 
void drop_unused_segments (Allocator &alloc)
 Lowers memory footprint by dropping unused segments.
 
Result< void, CollectionAddNoAllocationErrorpush (const T &elem) noexcept
 Pushes a new element.
 
Result< void, AllocationErrorpush (Allocator &alloc, const T &elem) noexcept
 Pushes a new element.
 
const T & operator[] (size_t index) const noexcept
 Access element at index.
 
T & operator[] (size_t index) noexcept
 Access element at index.
 
const T & at (size_t index) const noexcept
 Access element at index.
 
T & at (size_t index) noexcept
 Access element at index.
 
bool operator== (const SegmentedList &other)
 
bool operator!= (const SegmentedList &other)
 
void pop ()
 remove last element
 
size_t capacity () const
 

Detailed Description

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

Segmented list where each segment contains multiple nodes Allows growing the list without having to invalidate all previous memory addresses.

Only allows removing elements at the end.

The only operations which invalidate existing memory addresses are pop(), swap_remove(), and deinit() Otherwise, memory addresses are guaranteed to remain stable

Accessing elements is \(O(log_{1.5}(N))\) Adding elements is \(O(1)\) Removing elements is \(O(1)\), but only removes last element

For a more flexible removal/insertion,

See also
GenList or
ArrayList

Definition at line 45 of file segmented_list.hpp.

Member Typedef Documentation

◆ Elem

template<typename T>
using mtcore::SegmentedList< T >::Elem = T

Definition at line 46 of file segmented_list.hpp.

Member Function Documentation

◆ at() [1/2]

template<typename T>
const T & mtcore::SegmentedList< T >::at ( size_t index) const
inlinenodiscardnoexcept

Access element at index.

Parameters
indexindex to access
Returns
reference at index

Definition at line 372 of file segmented_list.hpp.

372 {
373 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
374 ensure(index < len, "OUT OF BOUNDS ACCESS");
375 const Segment *cur = &start;
376 while (cur) {
377 if (index < cur->elements.len) {
378 return cur->elements[index];
379 }
380 index -= cur->elements.len;
381 cur = cur->next;
382 }
383 unreachable("OUT OF BOUNDS ACCESS");
384 }
#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.
Segmented list where each segment contains multiple nodes Allows growing the list without having to i...
Here is the caller graph for this function:

◆ at() [2/2]

template<typename T>
T & mtcore::SegmentedList< T >::at ( size_t index)
inlinenodiscardnoexcept

Access element at index.

Parameters
indexindex to access
Returns
reference at index

Definition at line 391 of file segmented_list.hpp.

391 {
392 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
393 ensure(index < len, "OUT OF BOUNDS ACCESS");
394 Segment *cur = &start;
395 while (cur) {
397 return cur->elements[index];
398 }
399 index -= cur->elements.size();
400 cur = cur->next;
401 }
402 unreachable("OUT OF BOUNDS ACCESS");
403 }
size_t size() const noexcept
Gets the size of the list.

◆ capacity()

template<typename T>
size_t mtcore::SegmentedList< T >::capacity ( ) const
inlinenodiscard

Definition at line 439 of file segmented_list.hpp.

439{ return totalCapacity; }

◆ deinit()

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

Cleans up memory tied to segmented list.

Parameters
allocallocator to clean up memory with

Definition at line 241 of file segmented_list.hpp.

241 {
242 if (start.elements.head != nullptr) {
243 alloc.destroy_many(start.elements);
244 }
245 if (start.next != nullptr) {
246 Segment *cur = start.next;
247 while (cur) {
248 Segment *next = cur->next;
249 alloc.destroy_many(cur->elements);
250 alloc.destroy(cur);
251 cur = next;
252 }
253 }
254 totalCapacity = 0;
255 end = nullptr;
256 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ drop_unused_segments()

template<typename T>
void mtcore::SegmentedList< T >::drop_unused_segments ( Allocator & alloc)
inline

Lowers memory footprint by dropping unused segments.

Parameters
allocAllocator to drop segments with

Definition at line 262 of file segmented_list.hpp.

262 {
263 ensure(start.elements.head, "NOT INITIALIZED");
264 Segment *prev = &start;
265 Segment *cur = start.next;
266 end = &start;
267 size_t remaining = size();
268 while (cur) {
269 if (remaining > prev->elements.len) {
270 remaining -= prev->elements.len;
271 auto next = cur->next;
272 end = cur;
273 prev = cur;
274 cur = next;
275 }
276 else {
277 prev->next = nullptr;
278 while (cur) {
279 Segment *next = cur->next;
280 totalCapacity -= cur->elements.size();
281 alloc.destroy_many(cur->elements);
282 alloc.destroy(cur);
283 cur = next;
284 }
285 break;
286 }
287 }
288 }
Here is the call graph for this function:

◆ init() [1/2]

template<typename T>
Result< void, AllocationError > mtcore::SegmentedList< T >::init ( Allocator & alloc,
size_t initCapacity )
inlinenodiscard

Initializes a segmented list.

Parameters
allocAllocator to use for initializing memory
initCapacityInitial list capacity
Returns
Successful Result or error

Definition at line 190 of file segmented_list.hpp.

190 {
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");
195
196 auto allocRes = alloc.create_many<T>(initCapacity);
197 if (allocRes.is_error()) {
198 return allocRes.error();
199 }
200
201 start.elements = *allocRes;
202 totalCapacity = initCapacity;
203 return success();
204 }
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:

◆ init() [2/2]

template<typename T>
Result< void, AllocationError > mtcore::SegmentedList< T >::init ( Allocator & alloc,
std::initializer_list< T > list )
inlinenodiscard

Initializes a segmented list.

Parameters
allocAllocator to use for initializing memory
listList of elements to initialize with
Returns
Successful Result or error

Definition at line 212 of file segmented_list.hpp.

212 {
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");
218
219 auto allocRes = alloc.create_many<T>(list.size());
220 if (allocRes.is_error()) {
221 return allocRes.error();
222 }
223 totalCapacity = list.size();
224
225 start.elements = *allocRes;
226
227 size_t i = 0;
228 for (const auto &elem: list) {
229 start.elements[i++] = elem;
230 }
231 len = list.size();
232 end = &start;
233
234 return success();
235 }
Here is the call graph for this function:

◆ iter()

template<typename T>
ConstIter mtcore::SegmentedList< T >::iter ( ) const
inlinenodiscardnoexcept

Const iterator that gives element references.

Returns
Const reference iterator

Definition at line 173 of file segmented_list.hpp.

173 {
174 ensure(start.elements.head, "NOT INITIALIZED");
175 return {0, *this, 0, &start};
176 }
Here is the caller graph for this function:

◆ operator!=()

template<typename T>
bool mtcore::SegmentedList< T >::operator!= ( const SegmentedList< T > & other)
inlinenodiscard
Parameters
otherList to compare to
Returns
true if doesn't have same elements

Definition at line 427 of file segmented_list.hpp.

427{ return !(*this == other); }

◆ operator==()

template<typename T>
bool mtcore::SegmentedList< T >::operator== ( const SegmentedList< T > & other)
inlinenodiscard
Parameters
otherList to compare to
Returns
true if does have same elements

Definition at line 409 of file segmented_list.hpp.

409 {
410 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
411 ensure(other.start.elements.head != nullptr, "NOT INITIALIZED");
412 if (len != other.len) {
413 return false;
414 }
415 for (size_t i = 0; i < len; ++i) {
416 if (at(i) != other.at(i)) {
417 return false;
418 }
419 }
420 return true;
421 }
const T & at(size_t index) const noexcept
Access element at index.
Here is the call graph for this function:

◆ operator[]() [1/2]

template<typename T>
const T & mtcore::SegmentedList< T >::operator[] ( size_t index) const
inlinenodiscardnoexcept

Access element at index.

Parameters
indexindex to access
Returns
reference at index

Definition at line 352 of file segmented_list.hpp.

352 {
353 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
354 return at(index);
355 }
Here is the call graph for this function:

◆ operator[]() [2/2]

template<typename T>
T & mtcore::SegmentedList< T >::operator[] ( size_t index)
inlinenodiscardnoexcept

Access element at index.

Parameters
indexindex to access
Returns
reference at index

Definition at line 362 of file segmented_list.hpp.

362 {
363 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
364 return at(index);
365 }
Here is the call graph for this function:

◆ pop()

template<typename T>
void mtcore::SegmentedList< T >::pop ( )
inline

remove last element

Definition at line 432 of file segmented_list.hpp.

432 {
433 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
434 if (len > 0) {
435 --len;
436 }
437 }

◆ ptr_iter() [1/2]

template<typename T>
ConstPtrIter mtcore::SegmentedList< T >::ptr_iter ( ) const
inlinenodiscardnoexcept

Const iterator that gives const element pointers.

Returns
Pointer iterator

Definition at line 164 of file segmented_list.hpp.

164 {
165 ensure(start.elements.head, "NOT INITIALIZED");
166 return {0, *this, 0, &start};
167 }

◆ ptr_iter() [2/2]

template<typename T>
PtrIter mtcore::SegmentedList< T >::ptr_iter ( )
inlinenodiscardnoexcept

Mutable iterator that gives element pointers.

Returns
Pointer iterator

Definition at line 155 of file segmented_list.hpp.

155 {
156 ensure(start.elements.head, "NOT INITIALIZED");
157 return {0, *this, 0, &start};
158 }

◆ push() [1/2]

template<typename T>
Result< void, AllocationError > mtcore::SegmentedList< T >::push ( Allocator & alloc,
const T & elem )
inlinenodiscardnoexcept

Pushes a new element.

Will allocate if there is no space

Parameters
allocAllocator to use for additional allocation
elemElement to add
Returns
Success or error

Definition at line 314 of file segmented_list.hpp.

314 {
315 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
316
317 Segment *cur = end;
319 mtdefer { ++len; };
320 cur->elements[endIndex++] = elem;
321 return success();
322 }
323
324 auto allocSegRes = alloc.create<Segment>();
325
326 if (allocSegRes.is_error()) {
327 return allocSegRes.error();
328 }
329
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();
334 }
335 mtdefer { ++len; };
336 cur->next = *allocSegRes;
337 end = cur->next;
338 endIndex = 0;
339 cur = cur->next;
340 cur->elements = *allocElemRes;
341 cur->elements[endIndex++] = elem;
342 end = cur;
343 totalCapacity += cur->elements.size();
344 return success();
345 }
Here is the call graph for this function:

◆ push() [2/2]

template<typename T>
Result< void, CollectionAddNoAllocationError > mtcore::SegmentedList< T >::push ( const T & elem)
inlinenodiscardnoexcept

Pushes a new element.

Will error if there is no space

Parameters
elemElement to add
Returns
Success or error

Definition at line 295 of file segmented_list.hpp.

295 {
296 ensure(start.elements.head != nullptr, "NOT INITIALIZED");
297
298 Segment *cur = end;
299 ensure(cur);
301 mtdefer { ++len; };
302 cur->elements[endIndex++] = elem;
303 return success();
304 }
306 }
Error< Underlying > error(Underlying err)
Creates an error.
Definition result.hpp:425
Here is the call graph for this function:
Here is the caller graph for this function:

◆ size()

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

Gets the size of the list.

Returns
Size of segmented list

Definition at line 182 of file segmented_list.hpp.

182{ return len; }
Here is the caller graph for this function:

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