MULE 0.0.1
Multi-Use Library Essentials
Loading...
Searching...
No Matches
arr.h
1#pragma once
2/**
3 * @defgroup mod_arr Arr
4 * @brief A growable array of any element type.
5 *
6 * Arr(T) is a struct with the same layout and rules as a Str, for any
7 * element type. The operations are macros, because only a macro can work
8 * for every `T`.
9 *
10 * @snippet{trimleft} test_arr.c arr
11 *
12 * - Name each array type once with a typedef: `typedef Arr(int) IntArr;`.
13 * Every spelling of `Arr(...)` is a distinct type, so use the name.
14 * - A zero-initialised array (`IntArr xs = { 0 };`) is valid, empty, and
15 * owns no memory.
16 * - The fields are `data`, `len`, `capacity` and `alloc`, where a null
17 * `alloc` means the libc heap. Index `data` directly to read and write
18 * elements, and pass it to qsort or memcpy.
19 * - Calls that may allocate return `bool`. On false the array is
20 * unchanged.
21 * - Growing may move `data`, so pointers into it do not survive arr_push(),
22 * arr_insert() or arr_reserve().
23 *
24 * @warning The macros evaluate the array argument more than once. Pass a
25 * variable or a plain pointer, never an expression with side effects.
26 * @{
27 */
28
29#include "base/base.h"
30#include "mem/mem.h"
31
32#include <assert.h>
33#include <string.h>
34
35/** A growable array of @p T. Declare it with a typedef before use. */
36#define Arr(T) \
37 struct { \
38 T *data; \
39 size_t len; \
40 size_t capacity; \
41 const Allocator *alloc; \
42 }
43
44/** @name Growing
45 * Add elements. Each call may move `data`.
46 * @{ */
47
48/** Make room for @p n more elements without another allocation.
49 * @return False when out of memory or the size overflows. The array is
50 * then unchanged. */
51#define arr_reserve(a, n) \
52 arr_reserve_(&(a)->data, &(a)->capacity, (a)->len, (n), sizeof *(a)->data, \
53 (a)->alloc)
54
55/** Append @p v. @p v is evaluated after any growth and before `len`
56 * changes, so it may read the array itself, as in `arr_push(&xs,
57 * xs.data[0])` or `arr_push(&xs, xs.len)`.
58 * @return False when out of memory. The array is then unchanged. */
59#define arr_push(a, v) \
60 (arr_reserve((a), 1) ? ((a)->data[(a)->len] = (v), (a)->len++, true) \
61 : false)
62
63/** Insert @p v before index @p i, shifting the rest up. @p i may equal len.
64 * @return False when out of memory. The array is then unchanged.
65 * @pre `i <= len`. An assert checks it. */
66#define arr_insert(a, i, v) \
67 (assert(arr_index_ok_((i), (a)->len)), \
68 arr_reserve((a), 1) ? (memmove((a)->data + (i) + 1, (a)->data + (i), \
69 ((a)->len - (i)) * sizeof *(a)->data), \
70 (a)->data[(i)] = (v), (a)->len++, true) \
71 : false)
72
73/** @} */
74
75/** @name Shrinking
76 * Remove elements. None of these allocate or move `data`.
77 * @{ */
78
79/** Remove the element at index @p i, shifting the rest down.
80 * @pre `i < len`. An assert checks it. */
81#define arr_remove(a, i) \
82 (assert((i) < (a)->len), \
83 memmove((a)->data + (i), (a)->data + (i) + 1, \
84 ((a)->len - (i) - 1) * sizeof *(a)->data), \
85 (void)(a)->len--)
86
87/** Remove and return the last element.
88 * @pre The array is not empty. An assert checks it. */
89#define arr_pop(a) (assert((a)->len > 0), (a)->data[--(a)->len])
90
91/** Set the length to zero. Keeps the allocation for reuse. */
92#define arr_clear(a) ((void)((a)->len = 0))
93
94/** Free the elements' memory and reset to empty. Keeps `alloc`, and is safe
95 * to call twice. */
96#define arr_free(a) \
97 (arr_free_(&(a)->data, (a)->capacity * sizeof *(a)->data, (a)->alloc), \
98 (a)->len = 0, (void)((a)->capacity = 0))
99
100/** @} */
101
102/** @cond */
103/* A function, so a literal 0 index does not trip gcc's -Wtype-limits. */
104static inline bool arr_index_ok_(size_t i, size_t len) {
105 return i <= len;
106}
107
108MULE_NODISCARD bool arr_reserve_(void *data_field, size_t *capacity, size_t len,
109 size_t add, size_t elem,
110 const Allocator *alloc);
111void arr_free_(void *data_field, size_t bytes, const Allocator *alloc);
112/** @endcond */
113
114/** @} */
Where a module gets its memory.
Definition mem.h:56