burkey.co /docs/libflint/darray
index darray
~/docs/libflint/darray.md
libflint

Darray

libflint·Data Structures

A growable array of inline, trivially copyable elements, copied with memcpy of stride bytes. Padding is left as stored, and pointers inside an element are not freed.

Usage#

Initialize a caller-owned LfDArray with the element size. init stores that stride and allocates two slots. Push copies bytes into the array; the caller's object can be reused or go out of scope afterward. There is no destructor and no arena.

struct rec {
    char tag;
    int value;
};

LfDArray a;
struct rec in = {'k', 7};
if (lf_darray_init(&a, sizeof in) == 0) {
    if (lf_darray_push(&a, &in) == 0) {
        struct rec out;
        if (lf_darray_get(&a, 0, &out) == 0) {
            /* out.tag == 'k' && out.value == 7 */
        }
    }
    lf_darray_destroy(&a);
}

lf_darray_destroy frees the backing buffer and zeros the handle. It does not free the LfDArray. Concurrent use is unsupported. Pointers from lf_darray_at and lf_darray_at_const are invalidated when push, insert, remove, reserve, or destroy reallocates or shifts. sort permutes element bytes in place and does not reallocate the buffer. Do not pass a pointer into the array as elem or out to a call that can reallocate or shift.

Structs#

LfDArray#

typedef struct {
    void *data;
    size_t len;
    size_t cap;
    size_t stride;
} LfDArray;

The caller owns the handle and may read the fields. The library owns data. len is the number of elements, cap is the number of allocated slots, and stride is the byte size of one element. Spare capacity is uninitialized. Allocation failure in init leaves data == NULL, len == 0, cap == 0, and stride set. A NULL handle or a zero stride in init does not write the handle.

Functions#

lf_darray_init#

Stores stride and allocates 2 * stride bytes (cap == 2). Returns 0 on success. Returns -1 if a is NULL or stride is 0, and does not write the handle. Allocation failure or a byte-count overflow returns -1 and leaves a destroyable handle: data == NULL, len == 0, cap == 0, stride set. destroy on that handle is safe. Do not initialize a live array.

int lf_darray_init(LfDArray *a, size_t stride);

lf_darray_clear#

Sets len to 0 and keeps data, cap, and stride. Does not scrub bytes. A NULL handle returns without crashing.

void lf_darray_clear(LfDArray *a);

lf_darray_destroy#

Frees data and zeros the handle, including after a failed init. Does not free the handle. A NULL handle returns without crashing. A second destroy on a zeroed handle is a no-op.

void lf_darray_destroy(LfDArray *a);

lf_darray_reserve#

Ensures cap >= n by doubling capacity as needed. Returns 0 on success, including when n <= cap (no allocation). Returns -1 on a NULL handle, a zero stride, a size overflow, or allocation failure. On failure len, cap, data, and the existing bytes are unchanged.

int lf_darray_reserve(LfDArray *a, size_t n);

lf_darray_push#

Appends a copy of stride bytes from elem. Returns 0 on success. Returns -1 if a or elem is NULL, or if growth overflows or the allocation fails. On failure the array is unchanged. The array does not take ownership of elem.

int lf_darray_push(LfDArray *a, const void *elem);

lf_darray_pop#

Copies the last element to out when out is non-NULL, then decrements len. Returns 0 on success. Returns 1 if the array is empty and leaves out unchanged. Returns -1 if a is NULL. A NULL out discards the element.

int lf_darray_pop(LfDArray *a, void *out);

lf_darray_get#

Copies element i into out. Returns 0 on success. Returns -1 if a or out is NULL or if i >= len. On failure out is unchanged.

int lf_darray_get(const LfDArray *a, size_t i, void *out);

lf_darray_set#

Copies stride bytes from elem over element i. Does not change len and does not grow. Returns 0 on success. Returns -1 if a or elem is NULL or if i >= len. On failure the array is unchanged.

int lf_darray_set(LfDArray *a, size_t i, const void *elem);

lf_darray_at / lf_darray_at_const#

Returns a pointer to element i, or NULL if a is NULL or i >= len. The pointer addresses the array's buffer. push, insert, remove, reserve, sort, and destroy invalidate it whenever they reallocate or shift. sort also permutes which element sits at that address.

void *lf_darray_at(LfDArray *a, size_t i);
const void *lf_darray_at_const(const LfDArray *a, size_t i);

lf_darray_insert#

Copies stride bytes from elem into index i and shifts the tail up with memmove. i == len appends. Returns 0 on success. Returns -1 if a or elem is NULL, if i > len, or if growth overflows or the allocation fails. Growth happens before the shift. On failure len, cap, data, and the existing bytes are unchanged.

int lf_darray_insert(LfDArray *a, size_t i, const void *elem);

lf_darray_remove#

Copies element i to out when out is non-NULL, shifts the tail down with memmove, then decrements len. Returns 0 on success. Returns -1 if a is NULL or i >= len. On failure out and the array are unchanged. A NULL out discards the element.

int lf_darray_remove(LfDArray *a, size_t i, void *out);

lf_darray_sort#

Sorts the live elements with ISO qsort. The comparator is called with pointers to elements, not void **. The sort is not stable. Equal elements may end up in either order. A NULL array, a NULL comparator, a NULL buffer, a zero stride, or fewer than two elements does nothing. qsort_r is not used. The call does not reallocate the buffer. It invalidates element identity inside the buffer.

void lf_darray_sort(LfDArray *a, int (*cmp)(const void *a, const void *b));