commit 28f7eb446774c5515b93509d3c9664c94314f5f6 Author: krzosa Date: Sun Mar 8 23:10:38 2026 +0000 array.h diff --git a/array.h b/array.h new file mode 100644 index 0000000..131df34 --- /dev/null +++ b/array.h @@ -0,0 +1,251 @@ +typedef struct { size_t len; size_t cap; } array_header_t; +#define array_header(x) ((x) ? (((array_header_t *)(x)) - 1) : 0) +#define arrlen(x) ((x) ? array_header(x)->len : 0) +#define arrleni(x) ((int)arrlen(x)) +#define arrcap(x) ((x) ? array_header(x)->cap : 0) +#define arrpush(x, i) (array_grow((void **)&(x), sizeof((x)[0]), 1), (x)[array_header(x)->len++] = (i)) +#define arrpop(x) (assert(arrlen(x) > 0), (x)[--array_header(x)->len]) +#define arrlast(x) (assert(x), ((x) + arrlen(x) - 1)) +#define arrend(x) ((x) + arrlen(x)) +#define arrdelswap(x, i) (assert((i) < arrlen(x)), (x)[(i)] = (x)[--array_header(x)->len]) +#define arrdeln(x, i, n) (assert(arrlen(x) > 0), assert((n) > 0), assert((i) < arrlen(x)), assert((i) + (n) <= arrlen(x)), memmove((x) + (i), (x) + (i) + (n), (arrlen(x) - (i) - (n)) * sizeof((x)[0])), array_header(x)->len -= (n)) +#define arrdel(x, i) arrdeln((x), (i), 1) +#define arrfree(x) (free(array_header(x)), (x) = NULL) +#define arrsetcap(x,v) array_set_cap((void **)&(x), sizeof((x)[0]), (v)) +#define arrsetlen(x,v) array_set_len((void **)&(x), sizeof((x)[0]), (v)) +#define arrgrow(x,len) array_grow((void **)&(x), sizeof((x)[0]), (len)) +#define arrforex(T, arr, it) for (T *it = (arr); it != arrend(arr); it += 1) +#define arrfor(T, arr) arrforex(T, arr, it) +#define arrins(x,i,v) (array_make_space_insert((void **)&(x), sizeof((x)[0]), (i)), (x)[(i)] = (v), array_header(x)->len+=1) + +static void array_set_cap(void **p, size_t sizeof_elem, size_t cap) { + assert(cap < INT_MAX); + assert(sizeof_elem < INT_MAX); + if (arrcap(*p) != cap) { + array_header_t *new_head = realloc(array_header(*p), sizeof(array_header_t) + sizeof_elem * cap); + new_head->cap = cap; + if (new_head->len > new_head->cap) { + new_head->len = new_head->cap; + } + *p = new_head + 1; + } +} + +static void array_set_len(void **p, size_t sizeof_elem, size_t len) { + assert(len < INT_MAX); + assert(sizeof_elem < INT_MAX); + if (len > arrcap(*p)) { + array_set_cap(p, sizeof_elem, len); + } + array_header(*p)->len = len; +} + +static void array_grow(void **p, size_t sizeof_element, size_t add_len) { + size_t cap = arrcap(*p); + if (arrlen(*p) + add_len > cap) { + size_t cap_check0 = (cap ? cap : 8); + size_t new_cap = (cap_check0 + add_len - 1) * 2; + assert(new_cap >= cap); + array_header_t *new_head = realloc(array_header(*p), sizeof_element * new_cap + sizeof(array_header_t)); + assert(new_head); + new_head->cap = new_cap; + if (cap == 0) { + new_head->len = 0; + } + *p = new_head + 1; + } +} + +void print_int_array(int *arr) { + printf("len: %zu cap: %zu data: [", arrlen(arr), arrcap(arr)); + for (size_t i = 0; i < arrlen(arr); i += 1) { + printf("%d ", arr[i]); + } + printf("]\n"); +} + +static void array_make_space_insert(void **p, size_t sizeof_elem, size_t i) { + assert(i < arrlen(*p)+1); + array_grow(p, sizeof_elem, 1); + void *source = *p + (i * sizeof_elem); + void *dest = *p + ((i + 1) * sizeof_elem); + size_t move_size = (arrlen(*p) - i) * sizeof_elem; + memmove(dest, source, move_size); +} + +static void test_array(void) { + // basic push/pop + { + int *arr = NULL; + for (int i = 0; i < 65; i += 1) { + arrpush(arr, i); + } + { + int i = 0; + for (int *it = arr; it != arrend(arr); it += 1, i += 1) { + assert(*it == i); + } + i = 0; + arrfor(int, arr) { + assert(*it == i); + i += 1; + } + assert(i == 65); + } + for (int i = 64; i >= 0; i -= 1) { + int val = arrpop(arr); + assert(val == i); + } + assert(arrlen(arr) == 0); + assert(arrcap(arr) == 128); + arrfree(arr); + } + + { + int *arr = NULL; + arrfor(int, arr) { + assert(0); + } + } + + // delswap + { + int *arr = NULL; + arrpush(arr, 0); + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrdelswap(arr, 1); + assert(arrlen(arr) == 3); + assert(arr[0] == 0); + assert(arr[1] == 3); + assert(arr[2] == 2); + arrfree(arr); + } + + // setlen + { + int *arr = NULL; + arrsetlen(arr, 5); + assert(arrlen(arr) == 5); + assert(arrcap(arr) == 5); + arr[0] = 10; + arr[1] = 11; + arr[2] = 12; + arr[3] = 13; + arr[4] = 14; + arrsetlen(arr, 2); + assert(arrlen(arr) == 2); + assert(arr[0] == 10); + assert(arr[1] == 11); + arrsetlen(arr, 8); + assert(arrlen(arr) == 8); + assert(arrcap(arr) == 8); + arr[7] = 99; + assert(arr[7] == 99); + arrfree(arr); + } + + // setcap + { + int *arr = NULL; + arrsetcap(arr, 16); + assert(arrcap(arr) == 16); + assert(arrlen(arr) == 0); + for (int i = 0; i < 8; i += 1) { + arrpush(arr, i); + } + assert(arrlen(arr) == 8); + assert(arrcap(arr) == 16); + arrsetcap(arr, 64); + assert(arrcap(arr) == 64); + assert(arrlen(arr) == 8); + assert(arr[0] == 0); + assert(arr[7] == 7); + arrsetcap(arr, 4); + assert(arrlen(arr) == 4); + assert(arrcap(arr) == 4); + arrfor(int, arr) *it = 1; + arrfree(arr); + } + + // arrins + { + int *arr = NULL; + arrins(arr,0,0); + arrins(arr,0,1); + arrins(arr,0,2); + assert(arrlen(arr) == 3); + assert(arrcap(arr) == 16); + assert(arr[0] == 2); + assert(arr[1] == 1); + assert(arr[2] == 0); + arrins(arr,1,5); + assert(arr[1] == 5); + assert(arr[2] == 1); + // print_int_array(arr); + } + + // arrdeln + { + int *arr = NULL; + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrpush(arr, 4); + arrdeln(arr, 0, 2); + assert(arrlen(arr) == 2); + assert(arr[0] == 3); + assert(arr[1] == 4); + arrdeln(arr, 0, 2); + assert(arrlen(arr) == 0); + arrfree(arr); + } + + // arrdeln + { + int *arr = NULL; + arrpush(arr, 0); + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrdeln(arr, 2, 1); + arrdeln(arr, 0, 1); + assert(arrlen(arr) == 2); + assert(arr[0] == 1); + assert(arr[1] == 3); + arrfree(arr); + } + + // arrins + arrdeln/arrdel overlap + { + // 1, 2, 3, 4, 5, 6 + int *arr = NULL; + for (int i = 0; i < 6; i += 1) { + arrins(arr, i, i + 1); + } + for (int i = 0; i < 6; i += 1) { + assert(arr[i] == i + 1); + } + + // len=9 cap=16 + // $8 = {100, 1, 101, 2, 102, 3, 4, 5, 6} + for (int i = 0; i < 3; i += 1) { + int idx = (i * 2) % (arrlen(arr) + 1); + arrins(arr, idx, 100 + i); + } + assert(arrlen(arr) == 9); + arrdeln(arr, 2, 2); + assert(arrlen(arr) == 7); + arrdel(arr, arrlen(arr) - 1); + assert(arrlen(arr) == 6); + + for (int i = 0; i < arrleni(arr); i += 1) { + if (i > 0) { + assert(arr[i] != arr[i - 1]); + } + assert(arr[i] > 0); + } + arrfree(arr); + } +}