aboutsummaryrefslogtreecommitdiff
path: root/include/array.h
blob: ba7fa8d4a5b9b21ff16de086d8cff924c56e0c2f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#ifndef MLIB_ARRAY_H
#define MLIB_ARRAY_H

#include <stdbit.h>
#include <stddef.h>
#include <string.h>

#include "_allocator.h"
#include "_attrs.h"

typedef struct {
	ptrdiff_t len, cap;
	allocator_t mem;
} _mlib_arr_hdr_t;

[[_mlib_inline]]
static inline _mlib_arr_hdr_t *
_mlib_array_hdr(void *p, ptrdiff_t align)
{
	ptrdiff_t pad = -sizeof(_mlib_arr_hdr_t) & (align - 1);
	return (_mlib_arr_hdr_t *)((char *)p - pad - sizeof(_mlib_arr_hdr_t));
}

#define array_hdr(p) (_mlib_array_hdr(p, alignof(typeof(*(p)))))
#define array_len(p) (_mlib_array_hdr(p, alignof(typeof(*(p))))->len)
#define array_cap(p) (_mlib_array_hdr(p, alignof(typeof(*(p))))->cap)

#define array_new(mem, T, n)                                                    \
	((T *)array_new((mem), (n), sizeof(T), alignof(T)))
#define array_resz(p, cap)                                                      \
	((typeof(p))array_resz((p), (cap), sizeof(*(p)), alignof(typeof(*(p)))))
#define array_free(p)                                                           \
	array_free((p), sizeof(*(p)), alignof(typeof(*(p))))

#define array_push(p, x)                                                        \
	do {                                                                        \
		_mlib_arr_hdr_t *hdr = _mlib_array_hdr(*(p), alignof(typeof(**(p))));   \
		if (hdr->len == hdr->cap) {                                             \
			*(p) = array_resz(*(p), hdr->len * 2);                              \
			hdr = _mlib_array_hdr(*(p), alignof(typeof(**(p))));                \
		}                                                                       \
		(*(p))[hdr->len++] = (x);                                               \
	} while (false)

#define array_extend(p, xs, n)                                                  \
	do {                                                                        \
		_mlib_arr_hdr_t *hdr = _mlib_array_hdr(*(p), alignof(typeof(**(p))));   \
		if (hdr->len + (n) >= hdr->cap) {                                       \
			*(p) = array_resz(*(p), stdc_bit_ceil((size_t)hdr->len + (n)));     \
			hdr = _mlib_array_hdr(*(p), alignof(typeof(**(p))));                \
		}                                                                       \
		memcpy(&(*(p))[hdr->len], (xs), (n) * sizeof(*xs));                     \
		hdr->len += (n);                                                        \
	} while (false)

#define array_foreach(p, i) for (typeof(p) i = (p); i < (p) + array_len(p); i++)

[[_mlib_inline]]
static inline void
array_set_size(void *p, ptrdiff_t size, ptrdiff_t align)
{
	_mlib_arr_hdr_t *hdr = _mlib_array_hdr(p, align);
	hdr->len = size;
}

#define array_set_size(p, size)                                                 \
	array_set_size((p), (size), alignof(typeof(*(p))))

void *(array_new)(allocator_t mem, ptrdiff_t nmemb, ptrdiff_t elemsz,
	ptrdiff_t align);
void *(array_resz)(void *ptr, ptrdiff_t ncap, ptrdiff_t elemsz, ptrdiff_t align);
void (array_free)(void *ptr, ptrdiff_t elemsz, ptrdiff_t align);

#endif /* !MLIB_ARRAY_H */