28# define AL_LOG(FMT, ...) DBG("ARRAY_LIST", FMT __VA_OPT__(, ) __VA_ARGS__)
30# define AL_LOG(FMT, ...)
46 for (
size_t i = 0; i <
AL_BR; i++) {
90 if (child ==
nullptr) {
107 al.maybe_error =
nullptr;
132 size_t sz_without_tail = al->
len - (size_t)al->
tail_len;
142 if (al->
root ==
nullptr) {
144 al->maybe_error =
nullptr;
204 int msg_len = snprintf(
nullptr, 0,
"%zu",
n);
205 PANIC_IF(msg_len < 0,
"index formatting failed");
206 char *err_msg =
srn_allocate(ctx, (
size_t)msg_len + 1,
alignof(
char));
207 (void)snprintf(err_msg, (
size_t)msg_len + 1,
"%zu",
n);
211 size_t tail_start = al->
len - (size_t)al->
tail_len;
212 if (
n >= tail_start) {
213 *out_slot = &al->
tail[
n - tail_start];
218 for (int16_t d = al->
depth; d >= 0; d--) {
230 PANIC(
"It should never happen");
266 uint64_t last = al->
len - 1;
268 if (al->
depth == 0) {
277 for (uint8_t d = al->
depth; d > 1; d--) {
306 if (err !=
nullptr) {
317 PANIC_IF(err !=
nullptr,
"array_list_remove failed. This should not happen");
array_list_maybe_element_t array_list_get(const array_list_t *al, array_list_index_t n)
Negative index is not supported.
srn_error_t * array_list_update(array_list_t *al, array_list_index_t n, array_list_elem_t x)
Update the given index n of the array list al with the new element x.
static void array_list_push_leaf(const srn_context_t *ctx, array_list_node_t *node, uint8_t depth, uint64_t index, array_list_node_t *leaf)
Insert leaf below node at the position of logical index index, mutating node and its descendants in p...
static uint16_t array_list_depth_index(const uint8_t depth, const uint64_t index)
Find the array index of the given index, considering the given depth.
srn_error_t * array_list_remove(array_list_t *al, array_list_index_t n)
Remove the element at the given index n from the array list al, shifting every later element down one...
static array_list_node_t * array_list_new_path(const srn_context_t *ctx, uint8_t depth, array_list_node_t *leaf)
Walk from the root to a possible leaf node and create all the inner and leaf nodes if necessary.
static void array_list_pull_last_leaf(array_list_t *al)
Detach the rightmost leaf from the trie and hand its buffer back as the tail, the inverse of the prom...
static array_list_node_t * array_list_new_node(const srn_context_t *ctx)
static srn_error_t * array_list_slot(const array_list_t *al, array_list_index_t n, array_list_elem_t **out_slot)
Resolve the address of the slot backing logical index n into *out_slot.
static array_list_elem_t * array_list_create_page(const srn_context_t *ctx)
Create a PAGE (just slots for the data).
array_list_t array_list_empty(const srn_context_t *ctx)
Create an empty array list in the given context ctx.
srn_error_t * array_list_push(array_list_t *al, array_list_elem_t x)
Push the given element x to the end of array_list al.
static void array_list_drop_last(array_list_t *al)
Drop the final element, keeping the tail as the physical end of the sequence.
A bit-partitioned trie with a tail buffer, used as a growable indexed sequence in the runtime.
#define AL_SHIFT
log2(AL_BR)
#define AL_MAX_ELEMENTS
Maximum number of elements an array list can hold: a full trie at AL_MAX_DEPTH plus a full tail.
void * array_list_elem_t
We use generic pointers to refer to internal nodes, leaf nodes and even elements.
#define AL_MAX_DEPTH
Maximum trie depth, meaning the level of the root.
#define AL_BR
branching factor (power of two)
size_t array_list_index_t
void * srn_allocate(const srn_context_t *ctx, size_t size, size_t alignment)
#define ALLOCN(ctx, T, N)
#define ERR(ctx, err, msg)
We have two type of node that both are implemented using the same data structure.
array_list_elem_t * children
We allocate children to be a buffer of AL_BR number of pointers.
array_list_node_t * root
NULL means “all data is in tail”
uint8_t depth
tree depth in levels (0 == leaf level)
array_list_elem_t * tail
small tail array for fast push/pop.
size_t len
logical length.
uint16_t tail_len
0..AL_BR
const srn_context_t * ctx
The context that owns every allocation the array list retains.
A runtime error, a tag classifying the failure and a human-readable message.
#define PANIC_IF_NULL(ptr)
#define PANIC_IF(cond, msg)