Derive-C
Loading...
Searching...
No Matches
template.h File Reference
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <derive-c/container/arena/trait.h>
#include <derive-c/core/debug/gdb_marker.h>
#include <derive-c/core/debug/memory_tracker.h>
#include <derive-c/core/debug/mutation_tracker.h>
#include <derive-c/core/prelude.h>
#include <derive-c/core/alloc/def.h>
#include <derive-c/core/self/def.h>
#include <derive-c/core/alloc/undef.h>
#include <derive-c/core/self/undef.h>
Include dependency graph for template.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  value_t
struct  INDEX
struct  SLOT
struct  SELF
 An allocator that prints to stdout when it allocates or frees memory. More...
struct  IV_PAIR
struct  IV_PAIR_CONST

Macros

#define INDEX_BITS   32
 A vector-backed arena, with support for small indices.
#define VALUE   value_t
#define VALUE_DELETE   value_delete
#define VALUE_CLONE   value_clone
#define SLOT   NS(SELF, slot)
#define CHECK_ACCESS_INDEX(self, index)
#define RESIZE_FACTOR   2
#define INDEX   NS(SELF, index_t)
#define INVARIANT_CHECK(self)
#define IV_PAIR   NS(SELF, iv)
#define IV_PAIR_CONST   NS(SELF, iv_const)

Typedefs

typedef VALUE value_t
typedef ALLOC alloc_t
typedef IV_PAIR const * item

Functions

static void value_delete (value_t *self)
static value_t value_clone (value_t const *self)
 STATIC_ASSERT (sizeof(VALUE), "VALUE must be a non-zero sized type")
static void memory_tracker_empty (SLOT const *slot)
static void memory_tracker_present (SLOT const *slot)
static SELF new_with_capacity_for (INDEX_TYPE items, ALLOC *alloc)
static INDEX insert (SELF *self, VALUE value)
static VALUEtry_write (SELF *self, INDEX index)
static VALUEwrite (SELF *self, INDEX index)
static VALUE const * try_read (SELF const *self, INDEX index)
static VALUE const * read (SELF const *self, INDEX index)
static SELF clone (SELF const *self)
static INDEX_TYPE size (SELF const *self)
static bool full (SELF const *self)
static bool try_remove (SELF *self, INDEX index, VALUE *destination)
static VALUE remove (SELF *self, INDEX index)
static bool delete_entry (SELF *self, INDEX index)
static bool empty_item (IV_PAIR const *const *item)
static bool empty (ITER const *iter)
static IV_PAIR const * next (ITER *iter)
static ITER get_iter (SELF *self)
static void delete (SELF *self)
static bool empty_item (IV_PAIR_CONST const *const *item)
static bool empty (ITER_CONST const *iter)
static IV_PAIR_CONST const * next (ITER_CONST *iter)
static ITER_CONST get_iter_const (SELF const *self)
 TRAIT_ARENA (SELF)

Variables

static size_t max_entries = MAX_INDEX
static IV_PAIR_CONST iv_const_empty

Macro Definition Documentation

◆ CHECK_ACCESS_INDEX

#define CHECK_ACCESS_INDEX ( self,
index )
Value:
((index).index < (self)->exclusive_end)

Definition at line 75 of file template.h.

◆ INDEX

#define INDEX   NS(SELF, index_t)

Definition at line 82 of file template.h.

◆ INDEX_BITS

#define INDEX_BITS   32

A vector-backed arena, with support for small indices.

Definition at line 23 of file template.h.

◆ INVARIANT_CHECK

#define INVARIANT_CHECK ( self)
Value:
ASSUME(self); \
ASSUME((self)->count <= (self)->capacity); \
ASSUME((self)->exclusive_end >= (self)->count); \
ASSUME((self)->count <= MAX_INDEX);
#define ASSUME(expr,...)
Definition macros.h:62

Definition at line 142 of file template.h.

142#define INVARIANT_CHECK(self) \
143 ASSUME(self); \
144 ASSUME((self)->count <= (self)->capacity); \
145 ASSUME((self)->exclusive_end >= (self)->count); \
146 ASSUME((self)->count <= MAX_INDEX);

◆ IV_PAIR

#define IV_PAIR   NS(SELF, iv)

Definition at line 343 of file template.h.

◆ IV_PAIR_CONST

#define IV_PAIR_CONST   NS(SELF, iv_const)

Definition at line 417 of file template.h.

◆ RESIZE_FACTOR

#define RESIZE_FACTOR   2

Definition at line 79 of file template.h.

◆ SLOT

#define SLOT   NS(SELF, slot)

Definition at line 73 of file template.h.

◆ VALUE

#define VALUE   value_t

Definition at line 33 of file template.h.

◆ VALUE_CLONE

#define VALUE_CLONE   value_clone

Definition at line 37 of file template.h.

◆ VALUE_DELETE

#define VALUE_DELETE   value_delete

Definition at line 35 of file template.h.

Typedef Documentation

◆ alloc_t

typedef ALLOC alloc_t

Definition at line 85 of file template.h.

◆ item

typedef ITEM const * item
Examples
container/vector/dynamic.c, and container/vector/static.c.

Definition at line 350 of file template.h.

◆ value_t

typedef VALUE value_t

Definition at line 84 of file template.h.

Function Documentation

◆ clone()

SELF clone ( SELF const * self)
static

Definition at line 246 of file template.h.

246 {
247 INVARIANT_CHECK(self);
248 SLOT* slots = (SLOT*)NS(ALLOC, calloc)(self->alloc, self->capacity, sizeof(SLOT));
249 ASSERT(slots);
250
251 for (INDEX_TYPE index = 0; index < self->exclusive_end; index++) {
252 if (self->slots[index].present) {
253 NS(SLOT, memory_tracker_present)(&slots[index]);
254 slots[index].present = true;
255 slots[index].value = VALUE_CLONE(&self->slots[index].value);
256 } else {
257 NS(SLOT, memory_tracker_empty)(&slots[index]);
258 slots[index].present = false;
259 slots[index].next_free = self->slots[index].next_free;
260 }
261 }
262
263 return (SELF){
264 .slots = slots,
265 .capacity = self->capacity,
266 .free_list = self->free_list,
267 .exclusive_end = self->exclusive_end,
268 .count = self->count,
269 .alloc = self->alloc,
270 .derive_c_arena_basic = gdb_marker_new(),
271 .iterator_invalidation_tracker = mutation_tracker_new(),
272 };
273}
static void * calloc(SELF *self, size_t count, size_t size)
Definition template.h:36
#define ALLOC
Definition template.h:59
#define SLOT
Definition template.h:73
#define INVARIANT_CHECK(self)
Definition template.h:142
static void memory_tracker_present(SLOT const *slot)
Definition template.h:113
#define VALUE_CLONE
Definition template.h:37
static void memory_tracker_empty(SLOT const *slot)
Definition template.h:104
#define INDEX_TYPE
Definition template.h:46
static gdb_marker gdb_marker_new()
Definition gdb_marker.h:7
#define ASSERT(expr,...)
Definition macros.h:42
static mutation_tracker mutation_tracker_new()
#define NS(pre, post)
Definition namespace.h:4
#define SELF
Definition def.h:52
VALUE value
Definition template.h:93
INDEX_TYPE next_free
Definition template.h:94
bool present
Definition template.h:101
Here is the call graph for this function:
Here is the caller graph for this function:

◆ delete()

void delete ( SELF * self)
static

Definition at line 403 of file template.h.

403 {
404 INVARIANT_CHECK(self);
405 ITER iter = NS(SELF, get_iter)(self);
406 IV_PAIR const* entry;
407 while ((entry = NS(ITER, next)(&iter))) {
408 VALUE_DELETE(entry->value);
409 }
410
411 NS(ALLOC, free)(self->alloc, self->slots);
412}
static void free(SELF *self, void *ptr)
Definition template.h:58
static ITER get_iter(SELF *self)
Definition template.h:388
#define IV_PAIR
Definition template.h:343
static IV_PAIR const * next(ITER *iter)
Definition template.h:370
#define VALUE_DELETE
Definition template.h:35
VALUE * value
Definition template.h:346
SLOT * slots
Definition template.h:123
ALLOC * alloc
Definition template.h:66
Here is the call graph for this function:

◆ delete_entry()

bool delete_entry ( SELF * self,
INDEX index )
static

Definition at line 322 of file template.h.

322 {
323 INVARIANT_CHECK(self);
325
326 if (!CHECK_ACCESS_INDEX(self, index)) {
327 return false;
328 }
329
330 SLOT* entry = &self->slots[index.index];
331 if (entry->present) {
332 VALUE_DELETE(&entry->value);
333 entry->present = false;
335 entry->next_free = self->free_list;
336 self->free_list = index.index;
337 self->count--;
338 return true;
339 }
340 return false;
341}
#define CHECK_ACCESS_INDEX(self, index)
Definition template.h:75
static void mutation_tracker_mutate(mutation_tracker *self)
INDEX_TYPE index
Definition template.h:88
mutation_tracker iterator_invalidation_tracker
Definition template.h:139
INDEX_TYPE free_list
Definition template.h:125
size_t count
Definition template.h:135
Here is the call graph for this function:
Here is the caller graph for this function:

◆ empty() [1/2]

bool empty ( ITER const * iter)
static

Definition at line 361 of file template.h.

361 {
362 ASSUME(iter);
363 mutation_version_check(&iter->version);
364 // JUSTIFY: If no entries are left, then the previous '.._next' call moved
365 // the index to the exclusive end
366 // NOTE: `index + 1 > exclusive_end` implies `index >= exclusive_end`
367 return iter->next_index == INDEX_NONE || iter->next_index >= iter->arena->exclusive_end;
368}
static void mutation_version_check(mutation_version const *self)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ empty() [2/2]

bool empty ( ITER_CONST const * iter)
static

Definition at line 440 of file template.h.

440 {
441 ASSUME(iter);
442 mutation_version_check(&iter->version);
443 return iter->next_index == INDEX_NONE || iter->next_index >= iter->arena->exclusive_end;
444}
Here is the call graph for this function:

◆ empty_item() [1/2]

bool empty_item ( IV_PAIR const *const * item)
static

Definition at line 352 of file template.h.

352{ return *item == NULL; }
IV_PAIR const * item
Definition template.h:350
Here is the call graph for this function:
Here is the caller graph for this function:

◆ empty_item() [2/2]

bool empty_item ( IV_PAIR_CONST const *const * item)
static

Definition at line 431 of file template.h.

431{ return *item == NULL; }
Here is the call graph for this function:

◆ full()

bool full ( SELF const * self)
static

Definition at line 280 of file template.h.

280 {
281 INVARIANT_CHECK(self);
282 if (self->capacity == CAPACITY_EXCLUSIVE_UPPER) {
283 if (self->free_list == INDEX_NONE) {
284 return true;
285 }
286 }
287 return false;
288}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_iter()

ITER get_iter ( SELF * self)
static

Definition at line 388 of file template.h.

388 {
389 INVARIANT_CHECK(self);
390 INDEX_TYPE index = 0;
391 while (index < INDEX_NONE && index < self->exclusive_end && !self->slots[index].present) {
392 index++;
393 }
394
395 return (ITER){
396 .arena = self,
397 .next_index = index,
398 .curr = (IV_PAIR){.index = (INDEX){.index = INDEX_NONE}, .value = NULL},
400 };
401}
#define INDEX
Definition template.h:82
static mutation_version mutation_tracker_get(mutation_tracker const *self)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_iter_const()

ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 465 of file template.h.

465 {
466 INVARIANT_CHECK(self);
467 INDEX_TYPE index = 0;
468 while (index < INDEX_NONE && index < self->exclusive_end && !self->slots[index].present) {
469 index++;
470 }
471
472 return (ITER_CONST){
473 .arena = self,
474 .next_index = index,
475 .curr = (IV_PAIR_CONST){.index = (INDEX){.index = INDEX_NONE}, .value = NULL},
476 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
477 };
478}
#define IV_PAIR_CONST
Definition template.h:417
Here is the call graph for this function:
Here is the caller graph for this function:

◆ insert()

INDEX insert ( SELF * self,
VALUE value )
static

Definition at line 171 of file template.h.

171 {
172 INVARIANT_CHECK(self);
173 ASSERT(self->count < MAX_INDEX);
174
176 if (self->free_list != INDEX_NONE) {
177 INDEX_TYPE free_index = self->free_list;
178 SLOT* slot = &self->slots[free_index];
179 ASSUME(!slot->present);
180 self->free_list = slot->next_free;
181 slot->present = true;
183 slot->value = value;
184 self->count++;
185 return (INDEX){.index = free_index};
186 }
187
188 if (self->exclusive_end == self->capacity) {
189 ASSERT(self->capacity <= (CAPACITY_EXCLUSIVE_UPPER / RESIZE_FACTOR));
190 self->capacity *= RESIZE_FACTOR;
191 SLOT* new_alloc = (SLOT*)realloc(self->slots, self->capacity * sizeof(SLOT));
192 ASSERT(new_alloc);
193 self->slots = new_alloc;
194
195 for (size_t index = self->exclusive_end; index < self->capacity; index++) {
196 NS(SLOT, memory_tracker_empty)(&self->slots[index]);
197 }
198 }
199
200 INDEX_TYPE new_index = self->exclusive_end;
201 SLOT* slot = &self->slots[new_index];
202 slot->present = true;
204 slot->value = value;
205 self->count++;
206 self->exclusive_end++;
207 return (INDEX){.index = new_index};
208}
static void * realloc(SELF *self, void *ptr, size_t size)
Definition template.h:47
#define RESIZE_FACTOR
Definition template.h:79
size_t capacity
Definition template.h:124
size_t exclusive_end
Definition template.h:131
Here is the call graph for this function:
Here is the caller graph for this function:

◆ memory_tracker_empty()

void memory_tracker_empty ( SLOT const * slot)
static

Definition at line 104 of file template.h.

104 {
106 sizeof(VALUE));
108 sizeof(INDEX_TYPE));
110 sizeof(bool));
111}
#define VALUE
Definition template.h:33
@ MEMORY_TRACKER_LVL_CONTAINER
static void memory_tracker_set(memory_tracker_level level, memory_tracker_capability cap, const volatile void *addr, size_t size)
@ MEMORY_TRACKER_CAP_NONE
@ MEMORY_TRACKER_CAP_WRITE
@ MEMORY_TRACKER_CAP_READ_WRITE
Here is the call graph for this function:
Here is the caller graph for this function:

◆ memory_tracker_present()

void memory_tracker_present ( SLOT const * slot)
static

Definition at line 113 of file template.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ new_with_capacity_for()

SELF new_with_capacity_for ( INDEX_TYPE items,
ALLOC * alloc )
static

Definition at line 148 of file template.h.

148 {
149 ASSERT(items > 0);
150 size_t capacity = next_power_of_2(items);
151 ASSERT(capacity <= CAPACITY_EXCLUSIVE_UPPER);
152 SLOT* slots = (SLOT*)NS(ALLOC, calloc)(alloc, capacity, sizeof(SLOT));
153 ASSERT(slots);
154
155 for (INDEX_TYPE index = 0; index < capacity; index++) {
156 NS(SLOT, memory_tracker_empty)(&slots[index]);
157 }
158
159 return (SELF){
160 .slots = slots,
161 .capacity = (INDEX_TYPE)capacity,
162 .free_list = INDEX_NONE,
163 .exclusive_end = 0,
164 .count = 0,
165 .alloc = alloc,
166 .derive_c_arena_basic = gdb_marker_new(),
167 .iterator_invalidation_tracker = mutation_tracker_new(),
168 };
169}
static INLINE CONST size_t next_power_of_2(size_t x)
Definition math.h:8
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next() [1/2]

IV_PAIR const * next ( ITER * iter)
static

Definition at line 370 of file template.h.

370 {
371 ASSUME(iter);
372 mutation_version_check(&iter->version);
373
374 if (NS(ITER, empty)(iter)) {
375 return NULL;
376 }
377 iter->curr = (IV_PAIR){.index = (INDEX){.index = iter->next_index},
378 .value = &iter->arena->slots[iter->next_index].value};
379 iter->next_index++;
380 while (iter->next_index < INDEX_NONE && iter->next_index < iter->arena->exclusive_end &&
381 !iter->arena->slots[iter->next_index].present) {
382 iter->next_index++;
383 }
384
385 return &iter->curr;
386}
static bool empty(ITER const *iter)
Definition template.h:361
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next() [2/2]

IV_PAIR_CONST const * next ( ITER_CONST * iter)
static

Definition at line 446 of file template.h.

446 {
447 ASSUME(iter);
448 mutation_version_check(&iter->version);
449
450 if (NS(ITER_CONST, empty)(iter)) {
451 return NULL;
452 }
453
454 iter->curr = (IV_PAIR_CONST){.index = (INDEX){.index = iter->next_index},
455 .value = &iter->arena->slots[iter->next_index].value};
456 iter->next_index++;
457 while (iter->next_index != INDEX_NONE && iter->next_index < iter->arena->exclusive_end &&
458 !iter->arena->slots[iter->next_index].present) {
459 iter->next_index++;
460 }
461
462 return &iter->curr;
463}
Here is the call graph for this function:

◆ read()

VALUE const * read ( SELF const * self,
INDEX index )
static

Definition at line 240 of file template.h.

240 {
241 VALUE const* value = NS(SELF, try_read)(self, index);
242 ASSERT(value);
243 return value;
244}
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:228
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove()

VALUE remove ( SELF * self,
INDEX index )
static

Definition at line 313 of file template.h.

313 {
314 INVARIANT_CHECK(self);
316
317 VALUE value;
318 ASSERT(NS(SELF, try_remove)(self, index, &value));
319 return value;
320}
static bool try_remove(SELF *self, INDEX index, VALUE *destination)
Definition template.h:292
Here is the call graph for this function:
Here is the caller graph for this function:

◆ size()

INDEX_TYPE size ( SELF const * self)
static
Examples
complex/prime_sieve.c.

Definition at line 275 of file template.h.

275 {
276 INVARIANT_CHECK(self);
277 return self->count;
278}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ STATIC_ASSERT()

STATIC_ASSERT ( sizeof(VALUE) ,
"VALUE must be a non-zero sized type"  )

◆ TRAIT_ARENA()

TRAIT_ARENA ( SELF )

◆ try_read()

VALUE const * try_read ( SELF const * self,
INDEX index )
static

Definition at line 228 of file template.h.

228 {
229 INVARIANT_CHECK(self);
230 if (!CHECK_ACCESS_INDEX(self, index)) {
231 return NULL;
232 }
233 SLOT* slot = &self->slots[index.index];
234 if (!slot->present) {
235 return NULL;
236 }
237 return &slot->value;
238}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_remove()

bool try_remove ( SELF * self,
INDEX index,
VALUE * destination )
static

Definition at line 292 of file template.h.

292 {
293 INVARIANT_CHECK(self);
295
296 if (!CHECK_ACCESS_INDEX(self, index)) {
297 return false;
298 }
299
300 SLOT* entry = &self->slots[index.index];
301 if (entry->present) {
302 *destination = entry->value;
303 entry->present = false;
305 entry->next_free = self->free_list;
306 self->free_list = index.index;
307 self->count--;
308 return true;
309 }
310 return false;
311}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_write()

VALUE * try_write ( SELF * self,
INDEX index )
static

Definition at line 210 of file template.h.

210 {
211 INVARIANT_CHECK(self);
212 if (!CHECK_ACCESS_INDEX(self, index)) {
213 return NULL;
214 }
215 SLOT* slot = &self->slots[index.index];
216 if (!slot->present) {
217 return NULL;
218 }
219 return &slot->value;
220}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_clone()

value_t value_clone ( value_t const * self)
static

Definition at line 36 of file template.h.

36{ return *self; }

◆ value_delete()

void value_delete ( value_t * self)
static

Definition at line 34 of file template.h.

34{ (void)self; }

◆ write()

VALUE * write ( SELF * self,
INDEX index )
static

Definition at line 222 of file template.h.

222 {
223 VALUE* value = NS(SELF, try_write)(self, index);
224 ASSERT(value);
225 return value;
226}
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:210
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ iv_const_empty

IV_PAIR_CONST iv_const_empty
static
Initial value:
= {
.index = {.index = INDEX_NONE},
.value = NULL,
}

Definition at line 423 of file template.h.

423 {
424 .index = {.index = INDEX_NONE},
425 .value = NULL,
426};

◆ max_entries

size_t max_entries = MAX_INDEX
static

Definition at line 290 of file template.h.