Derive-C
Loading...
Searching...
No Matches
template.h File Reference
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <derive-c/container/vector/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  item_t
 A queue comprised of an extendable circular buffer. More...
struct  SELF
 An allocator that prints to stdout when it allocates or frees memory. More...

Macros

#define ITEM   item_t
#define ITEM_DELETE   item_delete
#define ITEM_CLONE   item_clone
#define INVARIANT_CHECK(self)

Typedefs

typedef size_t index_t
typedef ITEMitem

Functions

static void item_delete (item_t *t)
static item_t item_clone (item_t const *i)
static SELF new (ALLOC *alloc)
static SELF new_with_capacity (size_t capacity, ALLOC *alloc)
static SELF new_with_defaults (size_t size, ITEM default_item, ALLOC *alloc)
static void reserve (SELF *self, size_t new_capacity)
static SELF clone (SELF const *self)
static ITEM const * try_read (SELF const *self, size_t index)
static ITEM const * read (SELF const *self, size_t index)
static ITEMtry_write (SELF *self, size_t index)
static ITEMwrite (SELF *self, size_t index)
static void insert_at (SELF *self, size_t at, ITEM const *items, size_t count)
static void remove_at (SELF *self, size_t at, size_t count)
static ITEMpush (SELF *self, ITEM item)
static bool try_pop (SELF *self, ITEM *destination)
static ITEMdata (SELF *self)
static ITEM pop (SELF *self)
static ITEM pop_front (SELF *self)
static size_t size (SELF const *self)
static void delete (SELF *self)
static void transfer_reverse (SELF *source, SELF *target, size_t to_move)
static bool empty_item (ITEM *const *item)
static ITEMnext (ITER *iter)
static size_t position (ITER const *iter)
static bool empty (ITER const *iter)
static ITER get_iter (SELF *self)
static bool empty_item (ITEM const *const *item)
static ITEM const * next (ITER_CONST *iter)
static size_t position (ITER_CONST const *iter)
static bool empty (ITER_CONST const *iter)
static ITER_CONST get_iter_const (SELF const *self)
 TRAIT_VECTOR (SELF)

Macro Definition Documentation

◆ INVARIANT_CHECK

#define INVARIANT_CHECK ( self)
Value:
ASSUME(self); \
ASSUME((self)->size <= (self)->capacity); \
ASSUME((self->alloc)); \
ASSUME(WHEN(!((self)->data), (self)->capacity == 0 && (self)->size == 0));
static INDEX_TYPE size(SELF const *self)
Definition template.h:275
static ITEM * data(SELF *self)
Definition template.h:259
#define ASSUME(expr,...)
Definition macros.h:62
#define WHEN(cond, expr)
Definition macros.h:57

Definition at line 52 of file template.h.

52#define INVARIANT_CHECK(self) \
53 ASSUME(self); \
54 ASSUME((self)->size <= (self)->capacity); \
55 ASSUME((self->alloc)); \
56 ASSUME(WHEN(!((self)->data), (self)->capacity == 0 && (self)->size == 0));

◆ ITEM

#define ITEM   item_t

Definition at line 25 of file template.h.

◆ ITEM_CLONE

#define ITEM_CLONE   item_clone

Definition at line 29 of file template.h.

◆ ITEM_DELETE

#define ITEM_DELETE   item_delete

Definition at line 27 of file template.h.

Typedef Documentation

◆ index_t

typedef size_t index_t

Definition at line 40 of file template.h.

◆ item

typedef ITEM const* item

Definition at line 344 of file template.h.

Function Documentation

◆ clone()

SELF clone ( SELF const * self)
static

Definition at line 130 of file template.h.

130 {
131 INVARIANT_CHECK(self);
132 ITEM* data = (ITEM*)NS(ALLOC, malloc)(self->alloc, self->capacity * sizeof(ITEM));
133 ASSERT(data);
134 for (size_t index = 0; index < self->size; index++) {
135 data[index] = ITEM_CLONE(&self->data[index]);
136 }
138 (self->capacity - self->size) * sizeof(ITEM));
139 return (SELF){
140 .size = self->size,
141 .capacity = self->capacity,
142 .data = data,
143 .alloc = self->alloc,
144 .derive_c_vector_marker = gdb_marker_new(),
145 .iterator_invalidation_tracker = mutation_tracker_new(),
146 };
147}
static void * malloc(SELF *self, size_t size)
Definition template.h:25
#define ALLOC
Definition template.h:59
#define ITEM
Definition template.h:58
#define INVARIANT_CHECK(self)
Definition template.h:142
#define ITEM_CLONE
Definition template.h:29
static gdb_marker gdb_marker_new()
Definition gdb_marker.h:7
#define ASSERT(expr,...)
Definition macros.h:42
@ 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
static mutation_tracker mutation_tracker_new()
#define NS(pre, post)
Definition namespace.h:4
#define SELF
Definition def.h:52
Here is the call graph for this function:

◆ data()

ITEM * data ( SELF * self)
static
Examples
complex/employees.c.

Definition at line 259 of file template.h.

259 {
260 INVARIANT_CHECK(self);
261 return self->data;
262}
ITEM * data
Definition template.h:44
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 287 of file template.h.

287 {
288 INVARIANT_CHECK(self);
289 if (self->data) {
290 for (size_t i = 0; i < self->size; i++) {
291 ITEM_DELETE(&self->data[i]);
292 // JUSTIFY: Setting items as inaccessible
293 // - Incase a destructor of one item accesses the memory of another.
295 &self->data[i], sizeof(ITEM));
296 }
297
298 // JUSTIFY: Return to write level before passing to allocator
299 // - Is uninitialised, but still valid memory
301 self->capacity * sizeof(ITEM));
302 NS(ALLOC, free)(self->alloc, self->data);
303 }
304}
static void free(SELF *self, void *ptr)
Definition template.h:58
#define ITEM_DELETE
Definition template.h:27
@ MEMORY_TRACKER_CAP_WRITE
size_t capacity
Definition template.h:124
size_t size
Definition template.h:44
ALLOC * alloc
Definition template.h:66
Here is the call graph for this function:

◆ empty() [1/2]

bool empty ( ITER const * iter)
static

Definition at line 372 of file template.h.

372 {
373 ASSUME(iter);
374 mutation_version_check(&iter->version);
375 return iter->pos >= iter->vec->size;
376}
static void mutation_version_check(mutation_version const *self)
Here is the call graph for this function:

◆ empty() [2/2]

bool empty ( ITER_CONST const * iter)
static

Definition at line 416 of file template.h.

416 {
417 ASSUME(iter);
418 mutation_version_check(&iter->vec_version);
419 return iter->pos >= iter->vec->size;
420}
Here is the call graph for this function:

◆ empty_item() [1/2]

bool empty_item ( ITEM *const * item)
static

Definition at line 346 of file template.h.

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

◆ empty_item() [2/2]

bool empty_item ( ITEM const *const * item)
static

Definition at line 391 of file template.h.

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

◆ get_iter()

ITER get_iter ( SELF * self)
static

Definition at line 378 of file template.h.

378 {
379 ASSUME(self);
380 return (ITER){
381 .vec = self,
382 .pos = 0,
384 };
385}
static mutation_version mutation_tracker_get(mutation_tracker const *self)
mutation_tracker iterator_invalidation_tracker
Definition template.h:139
Here is the call graph for this function:

◆ get_iter_const()

ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 422 of file template.h.

422 {
423 ASSUME(self);
424 return (ITER_CONST){
425 .vec = self,
426 .pos = 0,
427 .vec_version = mutation_tracker_get(&self->iterator_invalidation_tracker),
428 };
429}
Here is the call graph for this function:

◆ insert_at()

void insert_at ( SELF * self,
size_t at,
ITEM const * items,
size_t count )
static

Definition at line 177 of file template.h.

177 {
178 INVARIANT_CHECK(self);
179 ASSUME(items);
180 ASSERT(at <= self->size);
182
183 if (count == 0) {
184 return;
185 }
186
187 NS(SELF, reserve)(self, self->size + count);
189 &self->data[self->size], count * sizeof(ITEM));
190 memmove(&self->data[at + count], &self->data[at], (self->size - at) * sizeof(ITEM));
191 memcpy(&self->data[at], items, count * sizeof(ITEM));
192 self->size += count;
193}
static void reserve(SELF *self, size_t new_capacity_for)
Definition template.h:135
static void mutation_tracker_mutate(mutation_tracker *self)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ item_clone()

item_t item_clone ( item_t const * i)
static

Definition at line 28 of file template.h.

28{ return *i; }

◆ item_delete()

void item_delete ( item_t * t)
static

Definition at line 26 of file template.h.

26{ (void)t; }

◆ new()

SELF new ( ALLOC * alloc)
static

Definition at line 58 of file template.h.

58 {
59 SELF self = (SELF){
60 .size = 0,
61 .capacity = 0,
62 .data = NULL,
63 .alloc = alloc,
64 .derive_c_vector_marker = gdb_marker_new(),
65 .iterator_invalidation_tracker = mutation_tracker_new(),
66 };
67 return self;
68}
Here is the call graph for this function:

◆ new_with_capacity()

SELF new_with_capacity ( size_t capacity,
ALLOC * alloc )
static

Definition at line 70 of file template.h.

70 {
71 if (capacity == 0) {
72 return NS(SELF, new)(alloc);
73 }
74
75 ITEM* data = (ITEM*)NS(ALLOC, malloc)(alloc, capacity * sizeof(ITEM));
78 capacity * sizeof(ITEM));
79 return (SELF){
80 .size = 0,
81 .capacity = capacity,
82 .data = data,
83 .alloc = alloc,
84 .derive_c_vector_marker = gdb_marker_new(),
85 .iterator_invalidation_tracker = mutation_tracker_new(),
86 };
87}
#define LIKELY(x)
Definition macros.h:53
Here is the call graph for this function:

◆ new_with_defaults()

SELF new_with_defaults ( size_t size,
ITEM default_item,
ALLOC * alloc )
static

Definition at line 89 of file template.h.

89 {
90 ITEM* data = (ITEM*)NS(ALLOC, malloc)(alloc, size * sizeof(ITEM));
91 if (size > 0) {
92 // JUSTIFY: We only need to copy size-1 entries - can move the first as default.
93 data[0] = default_item;
94 for (size_t i = 1; i < size; i++) {
95 data[i] = ITEM_CLONE(&default_item);
96 }
97 }
99 return (SELF){
100 .size = size,
101 .capacity = size,
102 .data = data,
103 .alloc = alloc,
104 .derive_c_vector_marker = gdb_marker_new(),
105 .iterator_invalidation_tracker = mutation_tracker_new(),
106 };
107}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next() [1/2]

ITEM * next ( ITER * iter)
static

Definition at line 354 of file template.h.

354 {
355 ASSUME(iter);
356 mutation_version_check(&iter->version);
357
358 if (iter->pos < iter->vec->size) {
359 ITEM* item = &iter->vec->data[iter->pos];
360 iter->pos++;
361 return item;
362 }
363 return NULL;
364}
Here is the call graph for this function:

◆ next() [2/2]

ITEM const * next ( ITER_CONST * iter)
static

Definition at line 399 of file template.h.

399 {
400 ASSUME(iter);
401 mutation_version_check(&iter->vec_version);
402 if (iter->pos < iter->vec->size) {
403 ITEM const* item = &iter->vec->data[iter->pos];
404 iter->pos++;
405 return item;
406 }
407 return NULL;
408}
Here is the call graph for this function:

◆ pop()

ITEM pop ( SELF * self)
static

Definition at line 264 of file template.h.

264 {
265 ITEM entry;
266 ASSERT(NS(SELF, try_pop)(self, &entry));
267 return entry;
268}
static bool try_pop(SELF *self, ITEM *destination)
Definition template.h:245
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pop_front()

ITEM pop_front ( SELF * self)
static

Definition at line 270 of file template.h.

270 {
271 INVARIANT_CHECK(self);
273 ASSERT(self->size > 0);
274 ITEM entry = self->data[0];
275 memmove(&self->data[0], &self->data[1], (self->size - 1) * sizeof(ITEM));
276 self->size--;
278 &self->data[self->size], sizeof(ITEM));
279 return entry;
280}
Here is the call graph for this function:

◆ position() [1/2]

size_t position ( ITER const * iter)
static

Definition at line 366 of file template.h.

366 {
367 ASSUME(iter);
368 mutation_version_check(&iter->version);
369 return iter->pos;
370}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ position() [2/2]

size_t position ( ITER_CONST const * iter)
static

Definition at line 410 of file template.h.

410 {
411 ASSUME(iter);
412 mutation_version_check(&iter->vec_version);
413 return iter->pos;
414}
Here is the call graph for this function:

◆ push()

ITEM * push ( SELF * self,
ITEM item )
static

Definition at line 214 of file template.h.

214 {
215 INVARIANT_CHECK(self);
217
218 if (self->size == self->capacity) {
219 size_t new_capacity;
220 if (self->data == NULL) {
221 ASSUME(self->capacity == 0);
222 // JUSTIFY: Allocating capacity of 4
223 // - Avoid repeat reallocations on growing a vector from
224 // size sero (from new)
225 // Otherwise an arbitrary choice (given we do not know the size of T)
226 new_capacity = 8;
227 } else {
228 // JUSTIFY: Growth factor of 2
229 // - Simple arithmetic (for debugging)
230 // - Same as used by GCC's std::vector implementation
231 new_capacity = self->capacity * 2;
232 }
233 NS(SELF, reserve)(self, new_capacity);
234 }
235
237 &self->data[self->size], sizeof(ITEM));
238
239 ITEM* entry = &self->data[self->size];
240 *entry = item;
241 self->size++;
242 return entry;
243}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read()

ITEM const * read ( SELF const * self,
size_t index )
static

Definition at line 157 of file template.h.

157 {
158 ITEM const* item = NS(SELF, try_read)(self, index);
159 ASSERT(item);
160 return item;
161}
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:228
Here is the call graph for this function:

◆ remove_at()

void remove_at ( SELF * self,
size_t at,
size_t count )
static

Definition at line 195 of file template.h.

195 {
196 INVARIANT_CHECK(self);
197 ASSERT(at + count <= self->size);
199
200 if (count == 0) {
201 return;
202 }
203
204 for (size_t i = at; i < at + count; i++) {
205 ITEM_DELETE(&self->data[i]);
206 }
207
208 memmove(&self->data[at], &self->data[at + count], (self->size - (at + count)) * sizeof(ITEM));
209 self->size -= count;
211 &self->data[self->size], count * sizeof(ITEM));
212}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reserve()

void reserve ( SELF * self,
size_t new_capacity )
static

Definition at line 109 of file template.h.

109 {
110 INVARIANT_CHECK(self);
111 if (new_capacity > self->capacity) {
112 const size_t capacity_increase = new_capacity - self->capacity;
113 const size_t uninit_elements = self->capacity - self->size;
114
115 // Set to writeable for allocator
117 &self->data[self->size], uninit_elements * sizeof(ITEM));
118
119 ITEM* new_data =
120 (ITEM*)NS(ALLOC, realloc)(self->alloc, self->data, new_capacity * sizeof(ITEM));
121 ASSERT(new_data);
122 self->data = new_data;
124 &self->data[self->size],
125 (uninit_elements + capacity_increase) * sizeof(ITEM));
126 self->capacity = new_capacity;
127 }
128}
static void * realloc(SELF *self, void *ptr, size_t size)
Definition template.h:47
Here is the call graph for this function:

◆ size()

size_t size ( SELF const * self)
static

Definition at line 282 of file template.h.

282 {
283 INVARIANT_CHECK(self);
284 return self->size;
285}
Here is the call graph for this function:

◆ TRAIT_VECTOR()

TRAIT_VECTOR ( SELF )

◆ transfer_reverse()

void transfer_reverse ( SELF * source,
SELF * target,
size_t to_move )
static

Moves to_move items from the beginning of source, to the end of target, shuffling elements in source forward appropriately.

  • Used for deque rebalancing
index: 0 1 2 3 4 5
source: [5, 4, 3, 2, 1, 0]
target: [6, 7, 8, 9]

Becomes:

index: 0 1 2 3 4 5
source: [3, 2, 1, 0]
target: [4, 5, 6, 7, 8, 9]

Definition at line 321 of file template.h.

321 {
322 INVARIANT_CHECK(source);
323 INVARIANT_CHECK(target);
324
325 NS(SELF, reserve)(target, target->size + to_move);
326
328 &target->data[target->size], to_move * sizeof(ITEM));
329 memmove(&target->data[to_move], target->data, target->size * sizeof(ITEM));
330
331 for (size_t i = 0; i < to_move; i++) {
332 target->data[to_move - 1 - i] = source->data[i];
333 }
334
335 memmove(source->data, &source->data[to_move], (source->size - to_move) * sizeof(ITEM));
336
337 source->size -= to_move;
338 target->size += to_move;
340 &source->data[source->size], to_move * sizeof(ITEM));
341}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_pop()

bool try_pop ( SELF * self,
ITEM * destination )
static

Definition at line 245 of file template.h.

245 {
246 INVARIANT_CHECK(self);
248
249 if (LIKELY(self->size > 0)) {
250 self->size--;
251 *destination = self->data[self->size];
253 &self->data[self->size + 1], sizeof(ITEM));
254 return true;
255 }
256 return false;
257}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_read()

ITEM const * try_read ( SELF const * self,
size_t index )
static

Definition at line 149 of file template.h.

149 {
150 INVARIANT_CHECK(self);
151 if (LIKELY(index < self->size)) {
152 return &self->data[index];
153 }
154 return NULL;
155}
Here is the call graph for this function:

◆ try_write()

ITEM * try_write ( SELF * self,
size_t index )
static

Definition at line 163 of file template.h.

163 {
164 INVARIANT_CHECK(self);
165 if (LIKELY(index < self->size)) {
166 return &self->data[index];
167 }
168 return NULL;
169}
Here is the call graph for this function:

◆ write()

ITEM * write ( SELF * self,
size_t index )
static

Definition at line 171 of file template.h.

171 {
172 ITEM* item = NS(SELF, try_write)(self, index);
173 ASSERT(item);
174 return item;
175}
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:210
Here is the call graph for this function: