growable-buf

Growable Memory Buffer for C99

UNLICENSE License

Stars
113

Growable Memory Buffers for C99

This C99 header library provides a simple, portable interface to growable buffers of homogeneous values of any type, similar to a std::vector in C++. The user need not use any particular struct, and the buffer need only initialize to NULL.

Each "function" in the interface is actually a macro, and its usage is reflected by these hypothetical prototypes:

/* Returns the number of elements in the buffer (for push and pop).
*/
size_t buf_size(type *v);

/* Returns the total capacity of the buffer.
*/
size_t buf_capacity(type *v);

/* Destroy and free the buffer, effectively resetting it.
 * Potentially assigns a new V pointer.
*/
void buf_free(type *v);

/* Append an element E to the end of the buffer, growing if necessary.
 * Potentially increases the capacity and assigns a new V pointer.
*/
void buf_push(type *v, type e);

/* Remove an element E from the end of the buffer.
 * Neither the capacity nor the V pointer will change. Popping when the
 * size is zero has undefined results.
 */
type buf_pop(type *v);

/* Increase buffer capactity by N elements.
 * Potentially assigns a new V pointer while also returning it.
 */
type *buf_grow(type *v, ptrdiff_t n);

/* Set buffer capactity to exactly N elements.
 * Potentially assigns a new V pointer while also returning it. A
 * negative capacity has undefined results.
 */
type *buf_trunc(type *v, ptrdiff_t n);

/* Set buffer size to zero.
 * Only affects push and pop. The capacity and buffer contents are
 * unchanged.
 */
void buf_clear(type *v);

Note: buf_push(), buf_grow(), buf_trunc(), and buf_free() may change the buffer pointer, and any previously-taken pointers should be considered invalidated. This has important consequences that must be considered.

The BUF_INIT_CAPACITY determines the initial capacity for buffers receiving their first push.

The BUF_ABORT macro is evaluated when the system runs out of memory. It defaults to abort(), but you may override it to run your own abort code instead.

Example usage:

float *values = 0;

/* Append 25 values */
for (size_t i = 0; i < 25; i++)
    buf_push(values, rand() / (float)RAND_MAX);

/* Access 25 values using the normal [] operator */
for (size_t i = 0; i < buf_size(values); i++)
    printf("values[%zu] = %f\n", i, values[i]);

/* Destroy/reset the buffer */
buf_free(values);

Purpose

This library is inspired by stb stretchy_buffer.h. The difference is that it's written in C99 so that it doesn't need to rely on undefined behavior. This does so by using a flexible array member and the offsetof() macro. It also checks for integer overflows before allocating any memory, making it safer.