This module provides growing arrays with items of an arbitrary type. (Alternatively, you might want to use growing mempool buffers, or the somewhat obsolete growing buffers.)
From the user’s point of view, the array is represented as a pointer to its first element, so it can be indexed by the usual [] operator. Please keep in mind that this pointer can change, whenever the array is resized.
Additional book-keeping information is stored before the first element and it can be accessed using the macros below.
ucw/gary.h
#define GARY_INIT(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n), &ucw_allocator_std)
Create a new growing array, initially containing n elements, and let ptr point to its first element. The memory used by the array is allocated by xmalloc().
#define GARY_INIT_ZERO(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n), &ucw_allocator_zeroed)
Create a growing array like GARY_INIT() does, but all newly allocated elements will be automatically zeroed.
#define GARY_INIT_ALLOC(ptr, n, a) (ptr) = gary_init(sizeof(*(ptr)), (n), (a))
Create a growing array like GARY_INIT() does, but based upon the given generic allocator.
#define GARY_INIT_SPACE(ptr, n) do { GARY_INIT(ptr, n); (GARY_HDR(ptr))->num_elts = 0; } while (0)
Create a growing array, initially containing 0 elements, but with enough space to keep n of them without needing reallocation. The ptr variable will point to the first element of the array.
#define GARY_INIT_SPACE_ZERO(ptr, n) do { GARY_INIT_ZERO(ptr, n); (GARY_HDR(ptr))->num_elts = 0; } while (0)
A combination of GARY_INIT_ZERO() and GARY_INIT_SPACE().
#define GARY_INIT_SPACE_ALLOC(ptr, n, a) do { GARY_INIT_ALLOC(ptr, n, a); (GARY_HDR(ptr))->num_elts = 0; } while (0)
A combination of GARY_INIT_ALLOC() and GARY_INIT_SPACE().
#define GARY_FREE(ptr) gary_free(ptr)
Destroy a growing array and free memory used by it. If ptr is NULL, nothing happens.
#define GARY_SIZE(ptr) (GARY_HDR(ptr)->num_elts)
Return the current number elements of the given growing array.
#define GARY_RESIZE(ptr, n) ((ptr) = gary_set_size((ptr), (n)))
Resize the given growing array to n elements. The ptr can change, if the array has to be re-allocated.
#define GARY_INIT_OR_RESIZE(ptr, n) (ptr) = (ptr) ? gary_set_size((ptr), (n)) : gary_init(sizeof(*(ptr)), (n), &ucw_allocator_std)
Create a new growing array, or resize it if it already exists.
#define GARY_PUSH_MULTI(ptr, n) ({ \ struct gary_hdr *_h = GARY_HDR(ptr); \ typeof(*(ptr)) *_c = &(ptr)[_h->num_elts]; \ size_t _n = n; \ _h->num_elts += _n; \ if (_h->num_elts > _h->have_space) \ (ptr) = gary_push_helper((ptr), _n, (byte **) &_c); \ _c; })
Push n elements to a growing array. That is, make space for n more elements at the end of the array and return a pointer to the first of these elements. The ptr can change, if the array has to be re-allocated.
#define GARY_PUSH(ptr) GARY_PUSH_MULTI(ptr, 1)
Push a single element at the end of a growing array and return a pointer to it. The ptr can change, if the array has to be re-allocated.
#define GARY_POP_MULTI(ptr, n) GARY_HDR(ptr)->num_elts -= (n)
Pop n elements from the end of a growing array. The ptr can change, if the array has to be re-allocated.
#define GARY_POP(ptr) GARY_POP_MULTI(ptr, 1)
Pop a single element from the end of a growing array. The ptr can change, if the array has to be re-allocated.
#define GARY_FIX(ptr) (ptr) = gary_fix((ptr))
Fix size of a growing array, returning all unused memory to the system (or more precisely, to the underlying allocator). The ptr can change.