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 *self)
static item_t ITEM_CLONE (item_t const *self)
static void ITEM_DEBUG (ITEM const *self, dc_debug_fmt fmt, FILE *stream)
static SELF new (ALLOC *alloc)
static SELF new_with_capacity_for (size_t capacity_for, ALLOC *alloc)
static bool empty (SELF const *self)
static size_t size (SELF const *self)
static void PRIV set_inaccessible_memory_caps (SELF *self, dc_memory_tracker_capability cap)
static void reserve (SELF *self, size_t new_capacity_for)
static void push_back (SELF *self, ITEM item)
static void push_front (SELF *self, ITEM item)
static ITEM pop_front (SELF *self)
static ITEM pop_back (SELF *self)
static ITEM const * try_read_from_front (SELF const *self, size_t index)
static ITEM const * try_read_from_back (SELF const *self, size_t index)
static ITEMtry_write_from_front (SELF *self, size_t index)
static ITEMtry_write_from_back (SELF *self, size_t index)
static bool empty_item (ITEM *const *item)
static bool empty (ITER const *iter)
static ITEMnext (ITER *iter)
static ITER get_iter (SELF *self)
static void delete (SELF *self)
static bool empty_item (ITEM const *const *item)
static bool empty (ITER_CONST const *iter)
static ITEM const * next (ITER_CONST *iter)
static ITER_CONST get_iter_const (SELF const *self)
static SELF clone (SELF const *self)
static 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((self)->alloc); \
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 bool empty(ITER const *iter)
Definition template.h:346
static size_t capacity()
Definition template.h:66
static ITEM * data(SELF *self)
Definition template.h:261
#define DC_WHEN(cond, expr)
Definition panic.h:51
#define DC_ASSUME(expr,...)
Definition panic.h:56

Definition at line 54 of file template.h.

54#define INVARIANT_CHECK(self) \
55 DC_ASSUME(self); \
56 DC_ASSUME((self)->alloc); \
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 285 of file template.h.

◆ ITER_CONST

#define ITER_CONST   NS(SELF, iter_const)

Definition at line 340 of file template.h.

Typedef Documentation

◆ item

typedef ITEM const* item

Definition at line 286 of file template.h.

◆ item_t

typedef ITEM item_t

Definition at line 40 of file template.h.

Function Documentation

◆ clone()

SELF clone ( SELF const * self)
static

Definition at line 377 of file template.h.

377 {
378 INVARIANT_CHECK(self);
379 ITEM* new_data = NULL;
380 size_t tail = 0;
381 size_t new_capacity = 0;
382 size_t const old_size = NS(SELF, size)(self);
383
384 if (old_size > 0) {
385 new_capacity = dc_math_next_power_of_2(old_size);
386 new_data = (ITEM*)NS(ALLOC, malloc)(self->alloc, new_capacity * sizeof(ITEM));
387 DC_ASSERT(new_data);
388
389 ITER_CONST iter = NS(SELF, get_iter_const)(self);
390 ITEM const* item;
391 while ((item = NS(ITER_CONST, next)(&iter))) {
392 new_data[tail] = ITEM_CLONE(item);
393 tail++;
394 }
395 tail--;
396 }
397 SELF new_self = {
398 .data = new_data,
399 .capacity = new_capacity,
400 .head = 0,
401 .tail = tail,
402 .empty = self->empty,
403 .alloc = self->alloc,
404 .derive_c_circular = dc_gdb_marker_new(),
405 .iterator_invalidation_tracker = mutation_tracker_new(),
406 };
408 return new_self;
409}
static void * malloc(SELF *self, size_t size)
Definition template.h:23
#define ALLOC
Definition template.h:64
#define ITEM
Definition template.h:63
static ITER_CONST get_iter_const(SELF const *self)
Definition template.h:449
static IV_PAIR next(ITER *iter)
Definition template.h:352
static INDEX_TYPE size(SELF const *self)
Definition template.h:252
#define INVARIANT_CHECK(self)
Definition template.h:88
SLOT PRIV(block)[DC_ARENA_CHUNKED_BLOCK_SIZE(BLOCK_INDEX_BITS)]
Definition template.h:73
#define ITER_CONST
Definition template.h:398
IV_PAIR item
Definition template.h:283
#define ITEM_CLONE
Definition template.h:22
static void PRIV set_inaccessible_memory_caps(SELF *self, dc_memory_tracker_capability cap)
Definition template.h:119
static dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:7
static DC_INLINE DC_CONST size_t dc_math_next_power_of_2(size_t x)
Definition math.h:48
@ DC_MEMORY_TRACKER_CAP_NONE
static mutation_tracker mutation_tracker_new()
#define NS(pre, post)
Definition namespace.h:4
#define DC_ASSERT(expr,...)
Definition panic.h:36
#define SELF
Definition def.h:52

◆ DC_TRAIT_QUEUE()

DC_TRAIT_QUEUE ( SELF )

◆ debug()

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

Definition at line 411 of file template.h.

411 {
412 fprintf(stream, EXPAND_STRING(SELF) "@%p {\n", self);
413 fmt = dc_debug_fmt_scope_begin(fmt);
414 dc_debug_fmt_print(fmt, stream, "capacity: %lu,\n", self->capacity);
415 dc_debug_fmt_print(fmt, stream, "size: %lu,\n", NS(SELF, size)(self));
416 dc_debug_fmt_print(fmt, stream, "head: %lu,\n", self->head);
417 dc_debug_fmt_print(fmt, stream, "tail: %lu,\n", self->tail);
418
419 dc_debug_fmt_print(fmt, stream, "alloc: ");
420 NS(ALLOC, debug)(self->alloc, fmt, stream);
421 fprintf(stream, ",\n");
422
423 dc_debug_fmt_print(fmt, stream, "queue: @%p [\n", self->data);
424 fmt = dc_debug_fmt_scope_begin(fmt);
425
426 ITER_CONST iter = NS(SELF, get_iter_const)(self);
427 ITEM const* item;
428 while ((item = NS(ITER_CONST, next)(&iter))) {
430 ITEM_DEBUG(item, fmt, stream);
431 fprintf(stream, ",\n");
432 }
433 fmt = dc_debug_fmt_scope_end(fmt);
434 dc_debug_fmt_print(fmt, stream, "],\n");
435 fmt = dc_debug_fmt_scope_end(fmt);
436 dc_debug_fmt_print(fmt, stream, "}\n");
437}
static void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:62
#define ITEM_DEBUG
Definition template.h:24
dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
Definition fmt.h:39
static void dc_debug_fmt_print_indents(dc_debug_fmt fmt, FILE *stream)
Definition fmt.h:16
dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
Definition fmt.h:33
static void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
Definition fmt.h:22
#define EXPAND_STRING(NAME)
Definition namespace.h:8
static FILE * stream(SELF *self)
Opens a file for.
Definition template.h:107

◆ delete()

void delete ( SELF * self)
static

Definition at line 322 of file template.h.

322 {
323 INVARIANT_CHECK(self);
324 if (self->data) {
325 ITER iter = NS(SELF, get_iter)(self);
326 ITEM* item;
327 while ((item = NS(ITER, next)(&iter))) {
330 sizeof(ITEM));
331 }
333 self->data, self->capacity * sizeof(ITEM));
334 NS(ALLOC, free)(self->alloc, self->data);
335 }
336}
static void free(SELF *self, void *ptr)
Definition template.h:56
static ITER get_iter(SELF *self)
Definition template.h:370
#define ITER
Definition template.h:320
#define ITEM_DELETE
Definition template.h:20
static 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
ALLOC * alloc
Definition template.h:71

◆ empty() [1/3]

bool empty ( ITER const * iter)
static

Definition at line 296 of file template.h.

296 {
297 DC_ASSUME(iter);
298 mutation_version_check(&iter->version);
299 return !NS(SELF, try_read_from_front)(iter->circular, iter->position);
300}
static ITEM const * try_read_from_front(SELF const *self, size_t index)
Definition template.h:255
static void mutation_version_check(mutation_version const *self)

◆ empty() [2/3]

bool empty ( ITER_CONST const * iter)
static

Definition at line 351 of file template.h.

351 {
352 DC_ASSUME(iter);
353 mutation_version_check(&iter->version);
354 return !NS(SELF, try_read_from_front)(iter->circular, iter->position);
355}

◆ empty() [3/3]

bool empty ( SELF const * self)
static

Definition at line 98 of file template.h.

98 {
99 DC_ASSUME(self);
100 if (self->empty) {
101 DC_ASSUME(self->head == self->tail);
102 }
103 return self->empty;
104}

◆ empty_item() [1/2]

bool empty_item ( ITEM *const * item)
static

Definition at line 288 of file template.h.

288{ return *item == NULL; }

◆ empty_item() [2/2]

bool empty_item ( ITEM const *const * item)
static

Definition at line 343 of file template.h.

343{ return *item == NULL; }

◆ get_iter()

ITER get_iter ( SELF * self)
static

Definition at line 313 of file template.h.

313 {
314 INVARIANT_CHECK(self);
315 return (ITER){
316 .circular = self,
317 .position = 0,
319 };
320}
static mutation_version mutation_tracker_get(mutation_tracker const *self)
mutation_tracker iterator_invalidation_tracker
Definition template.h:85

◆ get_iter_const()

ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 368 of file template.h.

368 {
369 INVARIANT_CHECK(self);
370 return (ITER_CONST){
371 .circular = self,
372 .position = 0,
373 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
374 };
375}

◆ ITEM_CLONE()

item_t ITEM_CLONE ( item_t const * self)
static

◆ ITEM_DEBUG()

void ITEM_DEBUG ( ITEM const * self,
dc_debug_fmt fmt,
FILE * stream )
static

◆ ITEM_DELETE()

void ITEM_DELETE ( item_t * self)
static

◆ new()

SELF new ( ALLOC * alloc)
static

Definition at line 62 of file template.h.

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

◆ new_with_capacity_for()

SELF new_with_capacity_for ( size_t capacity_for,
ALLOC * alloc )
static

Definition at line 74 of file template.h.

74 {
75 if (capacity_for == 0) {
76 return NS(SELF, new)(alloc);
77 }
78 size_t const capacity = dc_math_next_power_of_2(capacity_for);
80 ITEM* data = (ITEM*)NS(ALLOC, malloc)(alloc, capacity * sizeof(ITEM));
82
84 capacity * sizeof(ITEM));
85
86 return (SELF){
87 .data = data,
88 .capacity = capacity,
89 .head = 0,
90 .tail = 0,
91 .empty = true,
92 .alloc = alloc,
93 .derive_c_circular = dc_gdb_marker_new(),
94 .iterator_invalidation_tracker = mutation_tracker_new(),
95 };
96}
#define DC_MATH_IS_POWER_OF_2(x)
Definition math.h:12

◆ next() [1/2]

ITEM * next ( ITER * iter)
static

Definition at line 302 of file template.h.

302 {
303 DC_ASSUME(iter);
306 if (!item) {
307 return NULL;
308 }
309 iter->position++;
310 return item;
311}
static ITEM * try_write_from_front(SELF *self, size_t index)
Definition template.h:277
SELF * circular
Definition template.h:291
mutation_version version
Definition template.h:326
size_t position
Definition template.h:292

◆ next() [2/2]

ITEM const * next ( ITER_CONST * iter)
static

Definition at line 357 of file template.h.

357 {
358 DC_ASSUME(iter);
360 ITEM const* item = NS(SELF, try_read_from_front)(iter->circular, iter->position);
361 if (!item) {
362 return NULL;
363 }
364 iter->position++;
365 return item;
366}
size_t position
Definition template.h:347
SELF const * circular
Definition template.h:346
mutation_version version
Definition template.h:404

◆ pop_back()

ITEM pop_back ( SELF * self)
static

Definition at line 235 of file template.h.

235 {
236 INVARIANT_CHECK(self);
238 DC_ASSERT(!NS(SELF, empty)(self));
239
240 ITEM value = self->data[self->tail];
242 &self->data[self->tail], sizeof(ITEM));
243 if (self->head == self->tail) {
244 self->empty = true;
245 } else {
246 if (self->tail == 0) {
247 self->tail = self->capacity - 1;
248 } else {
249 self->tail--;
250 }
251 }
252 return value;
253}
static void mutation_tracker_mutate(mutation_tracker *self)
size_t head
Definition template.h:46
bool empty
Definition template.h:48
size_t tail
Definition template.h:47

◆ pop_front()

ITEM pop_front ( SELF * self)
static

Definition at line 216 of file template.h.

216 {
217 INVARIANT_CHECK(self);
219 DC_ASSERT(!NS(SELF, empty)(self));
220
221 ITEM value = self->data[self->head];
223 &self->data[self->head], sizeof(ITEM));
225 &self->data[self->head], sizeof(ITEM));
226
227 if (self->head == self->tail) {
228 self->empty = true;
229 } else {
230 self->head = dc_math_modulus_power_of_2_capacity(self->head + 1, self->capacity);
231 }
232 return value;
233}
static size_t DC_INLINE DC_CONST dc_math_modulus_power_of_2_capacity(size_t index, size_t capacity)
Definition math.h:63
static void dc_memory_tracker_check(dc_memory_tracker_level level, dc_memory_tracker_capability cap, const void *addr, size_t size)

◆ push_back()

void push_back ( SELF * self,
ITEM item )
static

Definition at line 184 of file template.h.

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

◆ push_front()

void push_front ( SELF * self,
ITEM item )
static

Definition at line 198 of file template.h.

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

◆ reserve()

void reserve ( SELF * self,
size_t new_capacity_for )
static

Definition at line 135 of file template.h.

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

◆ set_inaccessible_memory_caps()

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

Definition at line 119 of file template.h.

120 {
121 if (self->empty) {
123 self->capacity * sizeof(ITEM));
124 } else if (self->head <= self->tail) {
126 (self->capacity - (self->tail + 1)) * sizeof(ITEM));
128 self->head * sizeof(ITEM));
129 } else {
131 (self->head - (self->tail + 1)) * sizeof(ITEM));
132 }
133}

◆ size()

size_t size ( SELF const * self)
static

Definition at line 106 of file template.h.

106 {
107 DC_ASSUME(self);
108 if (self->empty) {
109 DC_ASSUME(self->tail == self->head);
110 return 0;
111 }
112
113 if (self->head <= self->tail) {
114 return (self->tail - self->head) + 1;
115 }
116 return (self->capacity - self->head) + self->tail + 1;
117}

◆ try_read_from_back()

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

Definition at line 265 of file template.h.

265 {
266 INVARIANT_CHECK(self);
267 if (index >= NS(SELF, size)(self)) {
268 return NULL;
269 }
270 if (index <= self->tail) {
271 return &self->data[self->tail - index];
272 }
273 size_t const from_end = index - self->tail;
274 return &self->data[self->capacity - from_end];
275}

◆ try_read_from_front()

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

Definition at line 255 of file template.h.

255 {
256 INVARIANT_CHECK(self);
257 if (index < NS(SELF, size)(self)) {
258 size_t const real_index =
259 dc_math_modulus_power_of_2_capacity(self->head + index, self->capacity);
260 return &self->data[real_index];
261 }
262 return NULL;
263}

◆ try_write_from_back()

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

Definition at line 281 of file template.h.

281 {
282 return (ITEM*)NS(SELF, try_read_from_back)(self, index);
283}
static ITEM const * try_read_from_back(SELF const *self, size_t index)
Definition template.h:265

◆ try_write_from_front()

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

Definition at line 277 of file template.h.

277 {
278 return (ITEM*)NS(SELF, try_read_from_front)(self, index);
279}