Home Rumble Youtube Twitter/X Kofi Contact / Crypto

 

SLOT is effectively a typesafe, iterable block allocator. It implemented as a 2-level tree with per-instance configurable leaf size, using a per-leaf bitfield to track occupancy and a free list embedded in unallocated entries. Because of the 64 bit value used in the free list, element sizes are rounded up to 8 bytes. SLOTs do not shrink their internal allocations automatically.

A SLOT is declared using the following macro, where Tis the type and chunk_size is the size of each leaf of the tree. Small values will lead to fragmentation while large values will lead to over-allocation. SLOT(T, [size_t] chunk_size) var_name; In this documentation, SVEC* will be used to refer to a pointer to an SVEC of unspecified type, which is used by all of the functions. Usually this is the address of the actual variable, not a proper independent pointer to it. T will be used as the declared internal type of the SVEC.
Examples: typedef struct { u64 qty; u64 price; char* name; } Item; SLOT(Item, 1024) inventory; Item* it = SLOT_inc(&inventory); it->qty = 7; it->price = 6300; it->name = "Widget"; There is a magic loop macro for iterating over the contents. It works just like it appears to, including the use of break and continue, and are a single statement internally, allowing constructs like if(foo) SLOT_EACHP(&bar, i, b) { printf("%d\n", *b); } or nesting loops without braces on the outer ones.

SLOT_EACHP(SLOT* o, [size_t] iterator, [T*] elem_ptr) { ... } SLOT_EACHP_INDEX(SLOT* o, [size_t] elem_index, [T*] elem_ptr) { ... } SLOT_EACH_INDEX(SLOT* o, [size_t] elem_index, [T] elem) { ... }

Iterator, elem_index, elem, and elem_ptr are all declared as local variables. A copy of the current element is copied into elem. A pointer to the actual internal memory for SLOT_index(o, index) is copied into elem_ptr, allowing direct modification. The value of iterator is sequential with the number of iterations. The value of elem_index is the index of the current element as would be fetched with SLOT_get_index(o, elem_ptr) and may contain gaps.

T* SLOT_index(SLOT* o, size_t index)
O(1)
Returns a pointer to the element at the given index. There is no bounds checking; passing in an out-of-bounds index is User Error and you deserve the segfault.
T* SLOT_get_index(SLOT* o, T* elem_ptr)
O(num_chunks)
Returns the index corresponding to the provided a pointer. The pointer must be a valid address within the SLOT, but need not be currently occupied.
T* SLOT_inc(SLOT* o) T* SLOT_inc(SLOT* o, size_t* out_index)
O(1)
Allocates a new element and returns a stable pointer to it. The optional argument out_index is filled with the index of the new element.
void SLOT_push(SLOT* o, T val)
O(1)
Allocates a new element and copies val into it.
void SLOT_rm(SLOT* o, T* ptr)
O(num_chunks)
Deletes the entry given by ptr and marks it as available for later allocation. ptr must point to a valid and current element of the SLOT.
void SLOT_rm_yolo(SLOT* o, T* ptr)
O(num_chunks)
Deletes the entry given by ptr and marks it as available for later allocation, if it exists. Returns silently if ptr is not a valid active element.
void SLOT_rm_index(SLOT* o, size_t index)
O(1)
Deletes the entry at the provided index. The provided index must be a valid and active index. active element.
void SLOT_assert_index(SLOT* o, size_t index)
O(1)
Sets the specified index as occupied and returns a pointer to it, regardless of the previous state of that index. Automatically resizes the internal memory if needed. This function breaks the internal free list; use with care. SLOT_rebuild_freelist() should be called after all operations with this function are complete. The pair is used to reconstruct a SLOT into an exact state from serialized data.
void SLOT_rebuild_freelist(SLOT* o)
O(num_elements)
Reconstructs the internal free list from scratch based on the occupancy bitfields. Used to return the SLOT to a fully functional state after using SLOT_assert_index().
void SLOT_free(SLOT* o, T* ptr)
Frees all internal memory.