summaryrefslogtreecommitdiff
path: root/xar.h
blob: e448889094df8c937ba7eede10d5f9ac59356d87 (plain)
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
75
76
77
78
79
80
81
82
#ifndef XAR_H
#define XAR_H

/* inspired by andrew reece's "exponential array" */
/* see https://danielchasehooper.com/posts/segment_array/ */

#include <stdbit.h>
#include "arena.h"

#define XAR_INIT_SZ 8
#define XAR_MAX_DOUBLE 26

typedef struct {
	int n, chunks;
	void *chunk[XAR_MAX_DOUBLE];
} XarHdr;

#define XAR(T) struct { int n, chunks; T *chunk[XAR_MAX_DOUBLE]; }
#define XAR_GET_T(xar, T, idx) (T*)(xar_get((XarHdr*)(xar), idx, sizeof(T)))
#define XAR_PUT_T(xar, T, idx, a) (T*)(xar_put((XarHdr*)(xar), idx, sizeof(T), a))
#define XAR_GET(xar, idx) XAR_GET_T(xar, typeof(**(xar)->chunk), idx)
#define XAR_PUT(xar, idx, a) XAR_PUT_T(xar, typeof(**(xar)->chunk), idx, a)
#define XAR_PUSH(xar, v, a) (*XAR_PUT(xar, (xar)->n++, a) = (v))
#define XAR_PUSH_T(xar, T, v, a) (*XAR_PUT_T(xar, T, (xar)->n++, a) = (v))
#define XAR_CHUNK(idx) (unsigned)(31 - stdc_leading_zeros(((unsigned)(idx) / XAR_INIT_SZ) + 1))
#define XAR_CHUNK_SZ(chnk) (XAR_INIT_SZ << (chnk))
#define XAR_SLOT(chnk, idx) ((idx) - (XAR_CHUNK_SZ(chnk) - XAR_CHUNK_SZ(0)))

static inline void *xar_get(XarHdr *xar, uint32_t idx, size_t elsz) {
	uint32_t chnk = XAR_CHUNK(idx);
	uint32_t slot = XAR_SLOT(chnk, idx);
	return (char*)xar->chunk[chnk] + (slot * elsz);
}

static inline void *xar_put(XarHdr *xar, uint32_t idx, size_t elsz, Arena *a) {
	uint32_t chnk = XAR_CHUNK(idx);
	uint32_t slot = XAR_SLOT(chnk, idx);
	while (xar->chunks <= chnk) {
		xar->chunk[xar->chunks] = arena_alloc(a, elsz * XAR_CHUNK_SZ(xar->chunks), elsz);
		xar->chunks++;
	}
	return (char*)xar->chunk[chnk] + (slot * elsz);
}

#define XAR_FOR_IDX_PTR_T(x, T, i, v, ...)\
	do {\
		int i = 0;\
		for (int xar_for_chnk = 0; xar_for_chnk < (x)->chunks; xar_for_chnk++) {\
			T *v = (x)->chunk[xar_for_chnk];\
			T *xar_for_chnk_end = v + (xar_for_chnk == (x)->chunks - 1\
				? XAR_SLOT(xar_for_chnk, (x)->n)\
				: XAR_CHUNK_SZ(xar_for_chnk));\
			while (v != xar_for_chnk_end) {\
				__VA_ARGS__;\
				v++;\
				i++;\
			}\
		}\
	} while(0)

#define XAR_FOR_IDX_VAL_T(x, T, i, v, ...)\
	XAR_FOR_IDX_PTR_T(x, T, i, xar_for_chnk_##v##_ptr, {\
		T v = *xar_for_chnk_##v##_ptr;\
		__VA_ARGS__;\
	})

#define XAR_FOR_PTR_T(x, T, v, ...)\
	XAR_FOR_IDX_PTR_T(x, T, _xar_foreach_i, v, __VA_ARGS__)

#define XAR_FOR_VAL_T(x, T, v, ...)\
	XAR_FOR_IDX_VAL_T(x, T, _xar_foreach_i, v, __VA_ARGS__)

#define XAR_FOR_IDX_PTR(xar, i, v, ...)\
	XAR_FOR_IDX_PTR_T(xar, typeof(**(xar)->chunk), i, v, __VA_ARGS__)

#define XAR_FOR_IDX_VAL(xar, i, v, ...)\
	XAR_FOR_IDX_VAL_T(xar, typeof(**(xar)->chunk), i, v, __VA_ARGS__)

#define XAR_FOR_VAL(xar, v, ...)\
	XAR_FOR_VAL_T(xar, typeof(**(xar)->chunk), v, __VA_ARGS__)

#endif