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