Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
2
3#include <stdbool.h>
4#include <stddef.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include <string.h>
8
10#include <derive-c/core/panic.h>
11
14
15#if !defined INDEX_BITS
16 #if !defined __clang_analyzer__
17 #error "The number of bits (8,16,32,64) to use for the arena's key"
18 #endif
19 #define INDEX_BITS 32
20#endif
21
22#if !defined VALUE
23 #if !defined __clang_analyzer__
24 #error "The value type to place in the arena must be defined"
25 #endif
26typedef struct {
27 int x;
28} value_t;
29 #define VALUE value_t
30static void value_delete(value_t* UNUSED(self)) {}
31 #define VALUE_DELETE value_delete
32static value_t value_clone(value_t const* self) { return *self; }
33 #define VALUE_CLONE value_clone
34#endif
35
36#if !defined VALUE_DELETE
37 #define VALUE_DELETE(value) (void)value
38#endif
39
40#if !defined VALUE_CLONE
41 #define VALUE_CLONE(value) (*(value))
42#endif
43
44#if INDEX_BITS == 8
45 #define INDEX_TYPE uint8_t
46 #define MAX_CAPACITY (UINT8_MAX + 1ULL)
47 #define MAX_INDEX (UINT8_MAX - 1ULL)
48 #define INDEX_NONE UINT8_MAX
49#elif INDEX_BITS == 16
50 #define INDEX_TYPE uint16_t
51 #define MAX_CAPACITY (UINT16_MAX + 1ULL)
52 #define MAX_INDEX (UINT16_MAX - 1ULL)
53 #define INDEX_NONE UINT16_MAX
54#elif INDEX_BITS == 32
55 #define INDEX_TYPE uint32_t
56 #define MAX_CAPACITY (UINT32_MAX + 1ULL)
57 #define MAX_INDEX (UINT32_MAX - 1ULL)
58 #define INDEX_NONE UINT32_MAX
59#elif INDEX_BITS == 64
60 #define INDEX_TYPE uint64_t
61 // JUSTIFY: Special case, we cannot store the max capacity as a size_t integer
62 #define MAX_CAPACITY UINT64_MAX
63 #define MAX_INDEX (UINT64_MAX - 1ULL)
64 #define INDEX_NONE UINT64_MAX
65#endif
66
67#define SLOT NS(SELF, slot)
68
69#define CHECK_ACCESS_INDEX(self, index) ((index).index < (self)->exclusive_end)
70
71// JUSTIFY: Macro rather than static
72// - Avoids the need to cast to the INDEX_TYPE
73#define RESIZE_FACTOR 2
74
75// INVARIANT: < MAX_CAPACITY
76#define INDEX NS(SELF, index)
77
78typedef struct {
79 INDEX_TYPE index;
80} INDEX;
81
82typedef struct {
83 union {
85 INDEX_TYPE next_free;
86 };
87
88 // JUSTIFY: Present flag last
89 // - Reduces size, C ABI orders fields, placing it before a larger
90 // (aligned) value would add (alignment - 1 byte) of unecessary
91 // padding
92 bool present;
93} SLOT;
94
95typedef struct {
97 size_t capacity;
98 INDEX_TYPE free_list;
99
100 // JUSTIFY: Separately recording the first_uninit_entry
101 // - Allows us to not use calloc for the buffer (for < first_uninit_entry
102 // we can check represent, for >= first_uninit_entry we know none are
103 // present so having uninitialised entries is fine)
105
106 // INVARIANT: If free_list == EMPTY_INDEX, then all values from [0, count)
107 // are present
108 size_t count;
109
110 ALLOC* alloc;
111} SELF;
112
113static SELF NS(SELF, new_with_capacity_for)(INDEX_TYPE items, ALLOC* alloc) {
114 DEBUG_ASSERT(items > 0);
115 size_t capacity = next_power_of_2(items);
116 ASSERT(capacity <= MAX_CAPACITY);
117 SLOT* slots = (SLOT*)NS(ALLOC, calloc)(alloc, capacity, sizeof(SLOT));
118 ASSERT(slots);
119 return (SELF){
120 .slots = slots,
121 .capacity = (INDEX_TYPE)capacity,
122 .free_list = INDEX_NONE,
123 .exclusive_end = 0,
124 .count = 0,
125 .alloc = alloc,
126 };
127}
128
129static INDEX NS(SELF, insert)(SELF* self, VALUE value) {
130 DEBUG_ASSERT(self);
131 if (self->free_list != INDEX_NONE) {
132 INDEX_TYPE free_index = self->free_list;
133 SLOT* slot = &self->slots[free_index];
134 DEBUG_ASSERT(!slot->present);
135 self->free_list = slot->next_free;
136 slot->present = true;
137 slot->value = value;
138 self->count++;
139 return (INDEX){.index = free_index};
140 }
141
142 if (self->exclusive_end == self->capacity) {
143 ASSERT(self->capacity <= (MAX_CAPACITY / RESIZE_FACTOR));
144 self->capacity *= RESIZE_FACTOR;
145 SLOT* new_alloc = (SLOT*)realloc(self->slots, self->capacity * sizeof(SLOT));
146 ASSERT(new_alloc);
147 self->slots = new_alloc;
148 }
149
150 INDEX_TYPE new_index = self->exclusive_end;
151 SLOT* slot = &self->slots[new_index];
152 slot->present = true;
153 slot->value = value;
154 self->count++;
155 self->exclusive_end++;
156 return (INDEX){.index = new_index};
157}
158
159static VALUE* NS(SELF, try_write)(SELF* self, INDEX index) {
160 DEBUG_ASSERT(self);
161 if (!CHECK_ACCESS_INDEX(self, index)) {
162 return NULL;
163 }
164 SLOT* slot = &self->slots[index.index];
165 if (!slot->present) {
166 return NULL;
167 }
168 return &slot->value;
169}
170
171static VALUE* NS(SELF, write)(SELF* self, INDEX index) {
172 VALUE* value = NS(SELF, try_write)(self, index);
173 ASSERT(value);
174 return value;
175}
176
177static VALUE const* NS(SELF, try_read)(SELF const* self, INDEX index) {
178 DEBUG_ASSERT(self);
179 if (!CHECK_ACCESS_INDEX(self, index)) {
180 return NULL;
181 }
182 SLOT* slot = &self->slots[index.index];
183 if (!slot->present) {
184 return NULL;
185 }
186 return &slot->value;
187}
188
189static VALUE const* NS(SELF, read)(SELF const* self, INDEX index) {
190 VALUE const* value = NS(SELF, try_read)(self, index);
191 ASSERT(value);
192 return value;
193}
194
195static SELF NS(SELF, clone)(SELF const* self) {
196 DEBUG_ASSERT(self);
197 SLOT* slots = (SLOT*)NS(ALLOC, calloc)(self->alloc, self->capacity, sizeof(SLOT));
198 ASSERT(slots);
199
200 for (INDEX_TYPE index = 0; index < self->exclusive_end; index++) {
201 if (self->slots[index].present) {
202 slots[index].present = true;
203 slots[index].value = VALUE_CLONE(&self->slots[index].value);
204 } else {
205 slots[index].present = false;
206 slots[index].next_free = self->slots[index].next_free;
207 }
208 }
209
210 return (SELF){
211 .slots = slots,
212 .capacity = self->capacity,
213 .free_list = self->free_list,
214 .exclusive_end = self->exclusive_end,
215 .count = self->count,
216 .alloc = self->alloc,
217 };
218}
219
220static INDEX_TYPE NS(SELF, size)(SELF const* self) {
221 DEBUG_ASSERT(self);
222 return self->count;
223}
224
225static bool NS(SELF, full)(SELF const* self) {
226 DEBUG_ASSERT(self);
227 if (self->capacity == MAX_CAPACITY) {
228 if (self->free_list == INDEX_NONE) {
229 return true;
230 }
231 }
232 return false;
233}
234
236static size_t NS(SELF, max_index) = MAX_INDEX;
237
238static bool NS(SELF, try_remove)(SELF* self, INDEX index, VALUE* destination) {
239 DEBUG_ASSERT(self);
240 if (!CHECK_ACCESS_INDEX(self, index)) {
241 return false;
242 }
243
244 SLOT* entry = &self->slots[index.index];
245 if (entry->present) {
246 *destination = entry->value;
247 entry->present = false;
248 entry->next_free = self->free_list;
249 self->free_list = index.index;
250 self->count--;
251 return true;
252 }
253 return false;
254}
255
256static VALUE NS(SELF, remove)(SELF* self, INDEX index) {
257 VALUE value;
258 ASSERT(NS(SELF, try_remove)(self, index, &value));
259 return value;
260}
261
262static bool NS(SELF, delete_entry)(SELF* self, INDEX index) {
263 DEBUG_ASSERT(self);
264 if (!CHECK_ACCESS_INDEX(self, index)) {
265 return false;
266 }
267
268 SLOT* entry = &self->slots[index.index];
269 if (entry->present) {
270 VALUE_DELETE(&entry->value);
271 entry->present = false;
272 entry->next_free = self->free_list;
273 self->free_list = index.index;
274 self->count--;
275 return true;
276 }
277 return false;
278}
279
280#define IV_PAIR NS(SELF, iv)
281typedef struct {
284} IV_PAIR;
285
286#define ITER NS(SELF, iter)
287typedef struct {
288 SELF* arena;
289 INDEX_TYPE next_index;
290 IV_PAIR curr;
291} ITER;
292
293static bool NS(ITER, empty)(ITER const* iter) {
294 DEBUG_ASSERT(iter);
295 // JUSTIFY: If no entries are left, then the previous '.._next' call moved
296 // the index to the exclusive end
297 // NOTE: `index + 1 > exclusive_end` implies `index >= exclusive_end`
298 return iter->next_index == INDEX_NONE || iter->next_index >= iter->arena->exclusive_end;
299}
300
301static IV_PAIR const* NS(ITER, next)(ITER* iter) {
302 DEBUG_ASSERT(iter);
303
304 if (NS(ITER, empty)(iter)) {
305 return NULL;
306 }
307 iter->curr = (IV_PAIR){.index = (INDEX){.index = iter->next_index},
308 .value = &iter->arena->slots[iter->next_index].value};
309 iter->next_index++;
310 while (iter->next_index < INDEX_NONE && iter->next_index < iter->arena->exclusive_end &&
311 !iter->arena->slots[iter->next_index].present) {
312 iter->next_index++;
313 }
314
315 return &iter->curr;
316}
317
318static ITER NS(SELF, get_iter)(SELF* self) {
319 DEBUG_ASSERT(self);
320 INDEX_TYPE index = 0;
321 while (index < INDEX_NONE && index < self->exclusive_end && !self->slots[index].present) {
322 index++;
323 }
324
325 return (ITER){
326 .arena = self,
327 .next_index = index,
328 .curr = (IV_PAIR){.index = (INDEX){.index = INDEX_NONE}, .value = NULL},
329 };
330}
331
332static void NS(SELF, delete)(SELF* self) {
333 DEBUG_ASSERT(self);
334 ITER iter = NS(SELF, get_iter)(self);
335 IV_PAIR const* entry;
336 while ((entry = NS(ITER, next)(&iter))) {
337 VALUE_DELETE(entry->value);
338 }
339
340 NS(ALLOC, free)(self->alloc, self->slots);
341}
342
343#undef ITER
344#undef IV_PAIR
345
346#define IV_PAIR_CONST NS(SELF, iv_const)
347typedef struct {
349 VALUE const* value;
351
353 .index = {.index = INDEX_NONE},
354 .value = NULL,
355};
356
357#define ITER_CONST NS(SELF, iter_const)
358typedef struct {
359 SELF const* arena;
360 INDEX_TYPE next_index;
361 IV_PAIR_CONST curr;
362} ITER_CONST;
363
364static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
365 DEBUG_ASSERT(iter);
366 return iter->next_index == INDEX_NONE || iter->next_index >= iter->arena->exclusive_end;
367}
368
369static IV_PAIR_CONST const* NS(ITER_CONST, next)(ITER_CONST* iter) {
370 DEBUG_ASSERT(iter);
371
372 if (NS(ITER_CONST, empty)(iter)) {
373 return NULL;
374 }
375
376 iter->curr = (IV_PAIR_CONST){.index = (INDEX){.index = iter->next_index},
377 .value = &iter->arena->slots[iter->next_index].value};
378 iter->next_index++;
379 while (iter->next_index != INDEX_NONE && iter->next_index < iter->arena->exclusive_end &&
380 !iter->arena->slots[iter->next_index].present) {
381 iter->next_index++;
382 }
383
384 return &iter->curr;
385}
386
387static ITER_CONST NS(SELF, get_iter_const)(SELF const* self) {
388 DEBUG_ASSERT(self);
389 INDEX_TYPE index = 0;
390 while (index < INDEX_NONE && index < self->exclusive_end && !self->slots[index].present) {
391 index++;
392 }
393
394 return (ITER_CONST){
395 .arena = self,
396 .next_index = index,
397 .curr = (IV_PAIR_CONST){.index = (INDEX){.index = INDEX_NONE}, .value = NULL},
398 };
399}
400
401#undef ITER_CONST
402#undef IV_PAIR_CONST
403
404#undef ALLOC
405#undef INDEX_BITS
406#undef VALUE
407#undef VALUE_DELETE
408#undef VALUE_CLONE
409
410#undef INDEX_TYPE
411#undef MAX_CAPACITY
412#undef MAX_INDEX
413#undef INDEX_NONE
414
415#undef SLOT
416#undef CHECK_ACCESS_INDEX
417#undef RESIZE_FACTOR
418#undef INDEX
419
static void free(SELF *self, void *ptr)
Definition template.h:56
static void * realloc(SELF *self, void *ptr, size_t size)
Definition template.h:45
static void * calloc(SELF *self, size_t count, size_t size)
Definition template.h:34
#define ALLOC
Definition template.h:56
#define UNUSED(ident)
Definition helpers.h:16
#define NS(pre, post)
Definition helpers.h:6
static size_t next_power_of_2(size_t x)
Definition helpers.h:31
#define ASSERT(expr,...)
Definition panic.h:15
#define DEBUG_ASSERT(expr)
Definition panic.h:34
#define SELF
Definition def.h:51
#define MAX_CAPACITY
Definition staticvec.c:9
INDEX_TYPE index
Definition template.h:79
VALUE const * value
Definition template.h:349
VALUE * value
Definition template.h:283
INDEX index
Definition template.h:282
size_t capacity
Definition template.h:97
INDEX_TYPE free_list
Definition template.h:98
size_t exclusive_end
Definition template.h:104
SLOT * slots
Definition template.h:96
size_t count
Definition template.h:108
ALLOC * alloc
Definition template.h:63
VALUE value
Definition template.h:84
INDEX_TYPE next_free
Definition template.h:85
bool present
Definition template.h:92
static INDEX insert(SELF *self, VALUE value)
Definition template.h:129
static bool full(SELF const *self)
Definition template.h:225
static ITER_CONST get_iter_const(SELF const *self)
Definition template.h:387
static bool empty(ITER const *iter)
Definition template.h:293
static ITER get_iter(SELF *self)
Definition template.h:318
static SELF new_with_capacity_for(INDEX_TYPE items, ALLOC *alloc)
Definition template.h:113
static size_t max_capacity
Definition template.h:235
#define IV_PAIR
Definition template.h:280
static INDEX_TYPE size(SELF const *self)
Definition template.h:220
static IV_PAIR const * next(ITER *iter)
Definition template.h:301
#define SLOT
Definition template.h:67
static VALUE remove(SELF *self, INDEX index)
Definition template.h:256
#define CHECK_ACCESS_INDEX(self, index)
Definition template.h:69
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:159
static IV_PAIR_CONST iv_const_empty
Definition template.h:352
#define IV_PAIR_CONST
Definition template.h:346
static bool delete_entry(SELF *self, INDEX index)
Definition template.h:262
static VALUE const * read(SELF const *self, INDEX index)
Definition template.h:189
static VALUE * write(SELF *self, INDEX index)
Definition template.h:171
#define VALUE
Definition template.h:29
static value_t value_clone(value_t const *self)
Definition template.h:32
#define RESIZE_FACTOR
Definition template.h:73
static void value_delete(value_t *UNUSED(self))
Definition template.h:30
static size_t max_index
Definition template.h:236
#define VALUE_CLONE
Definition template.h:33
#define VALUE_DELETE
Definition template.h:31
static bool try_remove(SELF *self, INDEX index, VALUE *destination)
Definition template.h:238
#define INDEX
Definition template.h:76
static SELF clone(SELF const *self)
Definition template.h:195
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:177
int x
Definition template.h:27