Derive-C
Loading...
Searching...
No Matches
template.h File Reference

Go to the source code of this file.

Data Structures

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...
struct  ITER
struct  ITER_CONST

Macros

#define ITEM   item_t
#define ITEM_DELETE   item_delete
#define ITEM_CLONE   item_clone
#define ITEM_DEBUG   item_debug
#define INVARIANT_CHECK(self)
#define ITER   NS(SELF, iter)
#define ITER_CONST   NS(SELF, iter_const)

Typedefs

typedef ITEM item_t
typedef ITEMitem

Functions

static void ITEM_DELETE (item_t *)
static item_t ITEM_CLONE (item_t const *self)
static void ITEM_DEBUG (ITEM const *, dc_debug_fmt, FILE *)
static DC_PUBLIC SELF new (ref alloc_ref)
static DC_PUBLIC SELF new_with_capacity_for (size_t capacity_for, ref alloc_ref)
static DC_PUBLIC bool empty (SELF const *self)
static DC_PUBLIC size_t size (SELF const *self)
static void PRIV set_inaccessible_memory_caps (SELF *self, dc_memory_tracker_capability cap)
static DC_PUBLIC void reserve (SELF *self, size_t new_capacity_for)
static DC_PUBLIC void push_back (SELF *self, ITEM item)
static DC_PUBLIC void push_front (SELF *self, ITEM item)
static DC_PUBLIC ITEM pop_front (SELF *self)
static DC_PUBLIC ITEM pop_back (SELF *self)
static DC_PUBLIC ITEM const * try_read_from_front (SELF const *self, size_t index)
static DC_PUBLIC ITEM const * try_read_from_back (SELF const *self, size_t index)
static DC_PUBLIC ITEMtry_write_from_front (SELF *self, size_t index)
static DC_PUBLIC ITEMtry_write_from_back (SELF *self, size_t index)
static DC_PUBLIC bool empty_item (ITEM *const *item)
static DC_PUBLIC bool empty (ITER const *iter)
static DC_PUBLIC ITEMnext (ITER *iter)
static DC_PUBLIC ITER get_iter (SELF *self)
static DC_PUBLIC void delete (SELF *self)
static DC_PUBLIC bool empty_item (ITEM const *const *item)
static DC_PUBLIC bool empty (ITER_CONST const *iter)
static DC_PUBLIC ITEM const * next (ITER_CONST *iter)
static DC_PUBLIC ITER_CONST get_iter_const (SELF const *self)
static DC_PUBLIC SELF clone (SELF const *self)
static DC_PUBLIC void debug (SELF const *self, dc_debug_fmt fmt, FILE *stream)
 DC_TRAIT_QUEUE (SELF)

Macro Definition Documentation

◆ INVARIANT_CHECK

#define INVARIANT_CHECK ( self)
Value:
DC_ASSUME(self); \
DC_ASSUME(DC_WHEN(!(self)->empty, \
(self)->head < (self)->capacity && (self)->tail < (self)->capacity)); \
DC_ASSUME(DC_WHEN((self)->empty, (self)->head == (self)->tail)); \
DC_ASSUME(DC_WHEN(!(self)->data, (self)->head == 0 && (self)->tail == 0));
static DC_PUBLIC bool empty(ITER const *iter)
Definition template.h:349
static DC_PUBLIC ITEM * data(SELF *self)
Definition template.h:284
#define DC_WHEN(cond, expr)
Definition panic.h:52
#define DC_ASSUME(expr,...)
Definition panic.h:57

Definition at line 55 of file template.h.

55#define INVARIANT_CHECK(self) \
56 DC_ASSUME(self); \
57 DC_ASSUME(DC_WHEN(!(self)->empty, \
58 (self)->head < (self)->capacity && (self)->tail < (self)->capacity)); \
59 DC_ASSUME(DC_WHEN((self)->empty, (self)->head == (self)->tail)); \
60 DC_ASSUME(DC_WHEN(!(self)->data, (self)->head == 0 && (self)->tail == 0));

◆ ITEM

#define ITEM   item_t

Definition at line 19 of file template.h.

◆ ITEM_CLONE

#define ITEM_CLONE   item_clone

Definition at line 22 of file template.h.

◆ ITEM_DEBUG

#define ITEM_DEBUG   item_debug

Definition at line 24 of file template.h.

◆ ITEM_DELETE

#define ITEM_DELETE   item_delete

Definition at line 20 of file template.h.

◆ ITER

#define ITER   NS(SELF, iter)

Definition at line 292 of file template.h.

◆ ITER_CONST

#define ITER_CONST   NS(SELF, iter_const)

Definition at line 348 of file template.h.

Typedef Documentation

◆ item

typedef ITEM const* item

Definition at line 293 of file template.h.

◆ item_t

typedef ITEM item_t

Definition at line 40 of file template.h.

Function Documentation

◆ clone()

DC_PUBLIC SELF clone ( SELF const * self)
static

Definition at line 385 of file template.h.

385 {
386 INVARIANT_CHECK(self);
387 ITEM* new_data = NULL;
388 size_t tail = 0;
389 size_t new_capacity = 0;
390 size_t const old_size = self->size;
391
392 if (old_size > 0) {
393 new_capacity = dc_math_next_power_of_2(old_size);
394 new_data = (ITEM*)NS(ALLOC, allocate_uninit)(self->alloc_ref, new_capacity * sizeof(ITEM));
395
396 ITER_CONST iter = NS(SELF, get_iter_const)(self);
397 ITEM const* item;
398 while ((item = NS(ITER_CONST, next)(&iter))) {
399 new_data[tail] = ITEM_CLONE(item);
400 tail++;
401 }
402 tail--;
403 }
404 SELF new_self = {
405 .data = new_data,
406 .capacity = new_capacity,
407 .size = old_size,
408 .head = 0,
409 .tail = tail,
410 .empty = self->empty,
411 .alloc_ref = self->alloc_ref,
412 .derive_c_circular = dc_gdb_marker_new(),
413 .iterator_invalidation_tracker = mutation_tracker_new(),
414 };
416 return new_self;
417}
#define ITEM
Definition template.h:36
static DC_PUBLIC void * allocate_uninit(SELF *self, size_t size)
Definition template.h:92
#define ALLOC
Definition template.h:31
#define INVARIANT_CHECK(self)
Definition template.h:90
static DC_PUBLIC IV_PAIR next(ITER *iter)
Definition template.h:355
#define ITER_CONST
Definition template.h:411
static DC_PUBLIC ITER_CONST get_iter_const(SELF const *self)
Definition template.h:464
IV_PAIR item
Definition template.h:281
#define ITEM_CLONE
Definition template.h:22
static void PRIV set_inaccessible_memory_caps(SELF *self, dc_memory_tracker_capability cap)
Definition template.h:114
#define SELF
Definition def.h:52
static DC_PUBLIC dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:8
static DC_INLINE DC_CONST size_t dc_math_next_power_of_2(size_t x)
Definition math.h:46
@ DC_MEMORY_TRACKER_CAP_NONE
static DC_PUBLIC mutation_tracker mutation_tracker_new()
#define NS(pre, post)
Definition namespace.h:14
#define PRIV(name)
Definition namespace.h:20

◆ DC_TRAIT_QUEUE()

DC_TRAIT_QUEUE ( SELF )

◆ debug()

DC_PUBLIC void debug ( SELF const * self,
dc_debug_fmt fmt,
FILE * stream )
static

Definition at line 419 of file template.h.

419 {
420 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", (void*)self);
421 fmt = dc_debug_fmt_scope_begin(fmt);
422 dc_debug_fmt_print(fmt, stream, "capacity: %lu,\n", self->capacity);
423 dc_debug_fmt_print(fmt, stream, "size: %lu,\n", self->size);
424 dc_debug_fmt_print(fmt, stream, "head: %lu,\n", self->head);
425 dc_debug_fmt_print(fmt, stream, "tail: %lu,\n", self->tail);
426
427 dc_debug_fmt_print(fmt, stream, "alloc: ");
428 NS(ALLOC, debug)(NS(NS(ALLOC, ref), deref)(self->alloc_ref), fmt, stream);
429 fprintf(stream, ",\n");
430
431 dc_debug_fmt_print(fmt, stream, "queue: @%p [\n", (void*)self->data);
432 fmt = dc_debug_fmt_scope_begin(fmt);
433
434 ITER_CONST iter = NS(SELF, get_iter_const)(self);
435 ITEM const* item;
436 while ((item = NS(ITER_CONST, next)(&iter))) {
438 ITEM_DEBUG(item, fmt, stream);
439 fprintf(stream, ",\n");
440 }
441 fmt = dc_debug_fmt_scope_end(fmt);
442 dc_debug_fmt_print(fmt, stream, "],\n");
443 fmt = dc_debug_fmt_scope_end(fmt);
444 dc_debug_fmt_print(fmt, stream, "}");
445}
static DC_PUBLIC void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:212
#define ITEM_DEBUG
Definition template.h:24
static DC_PUBLIC void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
Definition fmt.h:32
static DC_PUBLIC void dc_debug_fmt_print_indents(dc_debug_fmt fmt, FILE *stream)
Definition fmt.h:20
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
Definition fmt.h:57
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
Definition fmt.h:50
#define DC_EXPAND_STRING(NAME)
Definition namespace.h:6
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108

◆ delete()

DC_PUBLIC void delete ( SELF * self)
static

Definition at line 329 of file template.h.

329 {
330 INVARIANT_CHECK(self);
331 if (self->data) {
332 ITER iter = NS(SELF, get_iter)(self);
333 ITEM* item;
334 while ((item = NS(ITER, next)(&iter))) {
337 sizeof(ITEM));
338 }
339 size_t const size = self->capacity * sizeof(ITEM);
341 self->data, size);
342 NS(ALLOC, deallocate)(self->alloc_ref, self->data, size);
343 }
344}
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
Definition template.h:127
#define ITER
Definition template.h:322
static DC_PUBLIC ITER get_iter(SELF *self)
Definition template.h:373
static DC_PUBLIC size_t size(SELF const *self)
Definition template.h:252
#define ITEM_DELETE
Definition template.h:20
static DC_PUBLIC void dc_memory_tracker_set(dc_memory_tracker_level level, dc_memory_tracker_capability cap, const volatile void *addr, size_t size)
@ DC_MEMORY_TRACKER_LVL_CONTAINER
@ DC_MEMORY_TRACKER_CAP_WRITE
size_t capacity
Definition template.h:72
ITEM * data
Definition template.h:44
ref alloc_ref
Definition template.h:49

◆ empty() [1/3]

DC_PUBLIC bool empty ( ITER const * iter)
static

Definition at line 303 of file template.h.

303 {
304 DC_ASSUME(iter);
305 mutation_version_check(&iter->version);
306 return !NS(SELF, try_read_from_front)(iter->circular, iter->position);
307}
static DC_PUBLIC ITEM const * try_read_from_front(SELF const *self, size_t index)
Definition template.h:262
static DC_PUBLIC void mutation_version_check(mutation_version const *self)

◆ empty() [2/3]

DC_PUBLIC bool empty ( ITER_CONST const * iter)
static

Definition at line 359 of file template.h.

359 {
360 DC_ASSUME(iter);
361 mutation_version_check(&iter->version);
362 return !NS(SELF, try_read_from_front)(iter->circular, iter->position);
363}

◆ empty() [3/3]

DC_PUBLIC bool empty ( SELF const * self)
static

Definition at line 101 of file template.h.

101 {
102 DC_ASSUME(self);
103 if (self->empty) {
104 DC_ASSUME(self->head == self->tail);
105 }
106 return self->empty;
107}

◆ empty_item() [1/2]

DC_PUBLIC bool empty_item ( ITEM *const * item)
static

Definition at line 295 of file template.h.

295{ return *item == NULL; }

◆ empty_item() [2/2]

DC_PUBLIC bool empty_item ( ITEM const *const * item)
static

Definition at line 351 of file template.h.

351{ return *item == NULL; }

◆ get_iter()

DC_PUBLIC ITER get_iter ( SELF * self)
static

Definition at line 320 of file template.h.

320 {
321 INVARIANT_CHECK(self);
322 return (ITER){
323 .circular = self,
324 .position = 0,
326 };
327}
static DC_PUBLIC mutation_version mutation_tracker_get(mutation_tracker const *self)
mutation_tracker iterator_invalidation_tracker
Definition template.h:87

◆ get_iter_const()

DC_PUBLIC ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 376 of file template.h.

376 {
377 INVARIANT_CHECK(self);
378 return (ITER_CONST){
379 .circular = self,
380 .position = 0,
381 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
382 };
383}

◆ ITEM_CLONE()

item_t ITEM_CLONE ( item_t const * self)
static

Definition at line 23 of file template.h.

23{ return *self; }

◆ ITEM_DEBUG()

void ITEM_DEBUG ( ITEM const * ,
dc_debug_fmt ,
FILE *  )
static

Definition at line 25 of file template.h.

25{}

◆ ITEM_DELETE()

void ITEM_DELETE ( item_t * )
static

Definition at line 21 of file template.h.

21{}

◆ new()

DC_PUBLIC SELF new ( ref alloc_ref)
static

Definition at line 62 of file template.h.

62 {
63 return (SELF){
64 .data = NULL,
65 .capacity = 0,
66 .size = 0,
67 .head = 0,
68 .tail = 0,
69 .empty = true,
70 .alloc_ref = alloc_ref,
71 .derive_c_circular = dc_gdb_marker_new(),
72 .iterator_invalidation_tracker = mutation_tracker_new(),
73 };
74}

◆ new_with_capacity_for()

DC_PUBLIC SELF new_with_capacity_for ( size_t capacity_for,
ref alloc_ref )
static

Definition at line 76 of file template.h.

77 {
78 if (capacity_for == 0) {
79 return NS(SELF, new)(alloc_ref);
80 }
81 size_t const capacity = dc_math_next_power_of_2(capacity_for);
83 ITEM* data = (ITEM*)NS(ALLOC, allocate_uninit)(alloc_ref, capacity * sizeof(ITEM));
84
86 capacity * sizeof(ITEM));
87
88 return (SELF){
89 .data = data,
90 .capacity = capacity,
91 .size = 0,
92 .head = 0,
93 .tail = 0,
94 .empty = true,
95 .alloc_ref = alloc_ref,
96 .derive_c_circular = dc_gdb_marker_new(),
97 .iterator_invalidation_tracker = mutation_tracker_new(),
98 };
99}
#define DC_MATH_IS_POWER_OF_2(x)
Definition math.h:14

◆ next() [1/2]

DC_PUBLIC ITEM * next ( ITER * iter)
static

Definition at line 309 of file template.h.

309 {
310 DC_ASSUME(iter);
313 if (!item) {
314 return NULL;
315 }
316 iter->position++;
317 return item;
318}
static DC_PUBLIC ITEM * try_write_from_front(SELF *self, size_t index)
Definition template.h:284
SELF * circular
Definition template.h:298
mutation_version version
Definition template.h:328
size_t position
Definition template.h:299

◆ next() [2/2]

DC_PUBLIC ITEM const * next ( ITER_CONST * iter)
static

Definition at line 365 of file template.h.

365 {
366 DC_ASSUME(iter);
368 ITEM const* item = NS(SELF, try_read_from_front)(iter->circular, iter->position);
369 if (!item) {
370 return NULL;
371 }
372 iter->position++;
373 return item;
374}
size_t position
Definition template.h:355
SELF const * circular
Definition template.h:354
mutation_version version
Definition template.h:417

◆ pop_back()

DC_PUBLIC ITEM pop_back ( SELF * self)
static

Definition at line 240 of file template.h.

240 {
241 INVARIANT_CHECK(self);
243 DC_ASSERT(!NS(SELF, empty)(self), "Cannot pop back, already empty {size=%lu}",
244 (size_t)self->size);
245
246 ITEM value = self->data[self->tail];
248 &self->data[self->tail], sizeof(ITEM));
249 self->size--;
250 if (self->head == self->tail) {
251 self->empty = true;
252 } else {
253 if (self->tail == 0) {
254 self->tail = self->capacity - 1;
255 } else {
256 self->tail--;
257 }
258 }
259 return value;
260}
static DC_PUBLIC void mutation_tracker_mutate(mutation_tracker *self)
#define DC_ASSERT(expr,...)
Definition panic.h:37
size_t head
Definition template.h:47
size_t size
Definition template.h:75
bool empty
Definition template.h:49
size_t tail
Definition template.h:48

◆ pop_front()

DC_PUBLIC ITEM pop_front ( SELF * self)
static

Definition at line 219 of file template.h.

219 {
220 INVARIANT_CHECK(self);
222 DC_ASSERT(!NS(SELF, empty)(self), "Cannot pop front, already empty {size=%lu}",
223 (size_t)self->size);
224
225 ITEM value = self->data[self->head];
227 &self->data[self->head], sizeof(ITEM));
229 &self->data[self->head], sizeof(ITEM));
230
231 self->size--;
232 if (self->head == self->tail) {
233 self->empty = true;
234 } else {
235 self->head = dc_math_modulus_power_of_2_capacity(self->head + 1, self->capacity);
236 }
237 return value;
238}
static DC_PUBLIC size_t DC_INLINE DC_CONST dc_math_modulus_power_of_2_capacity(size_t index, size_t capacity)
Definition math.h:61
static DC_PUBLIC void dc_memory_tracker_check(dc_memory_tracker_level level, dc_memory_tracker_capability cap, const void *addr, size_t size)

◆ push_back()

DC_PUBLIC void push_back ( SELF * self,
ITEM item )
static

Definition at line 185 of file template.h.

185 {
186 INVARIANT_CHECK(self);
188 NS(SELF, reserve)(self, self->size + 1);
189
190 if (!self->empty) {
191 self->tail = dc_math_modulus_power_of_2_capacity(self->tail + 1, self->capacity);
192 }
194 &self->data[self->tail], sizeof(ITEM));
195 self->data[self->tail] = item;
196 self->empty = false;
197 self->size++;
198}
static DC_PUBLIC void reserve(SELF *self, size_t new_capacity_for)
Definition template.h:130

◆ push_front()

DC_PUBLIC void push_front ( SELF * self,
ITEM item )
static

Definition at line 200 of file template.h.

200 {
201 INVARIANT_CHECK(self);
203 NS(SELF, reserve)(self, self->size + 1);
204
205 if (!self->empty) {
206 if (self->head == 0) {
207 self->head = self->capacity - 1;
208 } else {
209 self->head--;
210 }
211 }
213 &self->data[self->head], sizeof(ITEM));
214 self->data[self->head] = item;
215 self->empty = false;
216 self->size++;
217}

◆ reserve()

DC_PUBLIC void reserve ( SELF * self,
size_t new_capacity_for )
static

Definition at line 130 of file template.h.

130 {
131 INVARIANT_CHECK(self);
133
134 if (new_capacity_for > self->capacity) {
135 size_t const new_capacity = dc_math_next_power_of_2(new_capacity_for * 2);
136
137 // We set the capability to write for the allocator, and only touch the
138 // state for memory that is inaccessible
140
141 ITEM* new_data;
142 if (self->data == NULL) {
143 new_data =
144 (ITEM*)NS(ALLOC, allocate_uninit)(self->alloc_ref, new_capacity * sizeof(ITEM));
145 } else {
146 new_data = (ITEM*)NS(ALLOC, reallocate)(self->alloc_ref, self->data,
147 self->capacity * sizeof(ITEM),
148 new_capacity * sizeof(ITEM));
149 }
150
151 if (self->head > self->tail) {
152 // The queue wraps at the old end, so we need to either:
153 // - shift elements of the tail around into the new area at the end of the buffer
154 // - shift the head of the queue along to the new arena
155 // need to move the wrapped around part to the end of the new buffer
156 size_t const old_capacity = self->capacity;
157 size_t const additional_capacity = new_capacity - old_capacity;
158 size_t const front_tail_items = self->tail + 1;
159 size_t const back_head_items = old_capacity - self->head;
160
161 if (front_tail_items > back_head_items) {
162 size_t const new_head = self->head + additional_capacity;
163 memmove(&new_data[new_head], &new_data[self->head], back_head_items * sizeof(ITEM));
164 self->head = new_head;
165 } else {
166 // as we go to the next power of 2 each time, the additional capacity is always >=
167 // the number of items at the front. As a result, we never need to consider:
168 // - Only copying the first n from the front
169 // - Shifting some of the front items to the start of the buffer
170 DC_ASSUME(front_tail_items <= additional_capacity);
171
172 memcpy(&new_data[old_capacity], &new_data[0], front_tail_items * sizeof(ITEM));
173 self->tail = old_capacity + front_tail_items - 1;
174 }
175 }
176 self->capacity = new_capacity;
177 self->data = new_data;
178
179 // Set the new inaccessible memory
181 }
182 INVARIANT_CHECK(self);
183}
static DC_PUBLIC void * reallocate(SELF *self, void *ptr, size_t old_size, size_t new_size)
Definition template.h:137

◆ set_inaccessible_memory_caps()

void PRIV set_inaccessible_memory_caps ( SELF * self,
dc_memory_tracker_capability cap )
static

Definition at line 114 of file template.h.

115 {
116 if (self->empty) {
118 self->capacity * sizeof(ITEM));
119 } else if (self->head <= self->tail) {
121 (self->capacity - (self->tail + 1)) * sizeof(ITEM));
123 self->head * sizeof(ITEM));
124 } else {
126 (self->head - (self->tail + 1)) * sizeof(ITEM));
127 }
128}

◆ size()

DC_PUBLIC size_t size ( SELF const * self)
static

Definition at line 109 of file template.h.

109 {
110 DC_ASSUME(self);
111 return self->size;
112}

◆ try_read_from_back()

DC_PUBLIC ITEM const * try_read_from_back ( SELF const * self,
size_t index )
static

Definition at line 272 of file template.h.

272 {
273 INVARIANT_CHECK(self);
274 if (index >= self->size) {
275 return NULL;
276 }
277 if (index <= self->tail) {
278 return &self->data[self->tail - index];
279 }
280 size_t const from_end = index - self->tail;
281 return &self->data[self->capacity - from_end];
282}

◆ try_read_from_front()

DC_PUBLIC ITEM const * try_read_from_front ( SELF const * self,
size_t index )
static

Definition at line 262 of file template.h.

262 {
263 INVARIANT_CHECK(self);
264 if (index < self->size) {
265 size_t const real_index =
266 dc_math_modulus_power_of_2_capacity(self->head + index, self->capacity);
267 return &self->data[real_index];
268 }
269 return NULL;
270}

◆ try_write_from_back()

DC_PUBLIC ITEM * try_write_from_back ( SELF * self,
size_t index )
static

Definition at line 288 of file template.h.

288 {
289 return (ITEM*)NS(SELF, try_read_from_back)(self, index);
290}
static DC_PUBLIC ITEM const * try_read_from_back(SELF const *self, size_t index)
Definition template.h:272

◆ try_write_from_front()

DC_PUBLIC ITEM * try_write_from_front ( SELF * self,
size_t index )
static

Definition at line 284 of file template.h.

284 {
285 return (ITEM*)NS(SELF, try_read_from_front)(self, index);
286}