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