Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
3
5#if !defined(SKIP_INCLUDES)
6 #include "includes.h"
7#endif
8
9// JUSTIFY: No memory tracking
10// - The vector is in-place, inside the vector object itself
11// - poisoning this makes memcopying the struct throw in asan
12// On balance, the likelihood of hitting frustrating issues (e.g. from cpp copying objects, C
13// structs trivially copyable) is high, and the benefit of catching improper usage of vector
14// elements is not high enough to overcome.
15
17
18#if !defined ITEM
19 #if !defined DC_PLACEHOLDERS
20TEMPLATE_ERROR("No ITEM")
21 #endif
22typedef struct {
23 int x;
24} item_t;
25 #define ITEM item_t
26 #define ITEM_DELETE item_delete
27static void ITEM_DELETE(item_t* /* self */) {}
28 #define ITEM_CLONE item_clone
29static item_t ITEM_CLONE(item_t const* self) { return *self; }
30 #define ITEM_DEBUG item_debug
31static void ITEM_DEBUG(ITEM const* /* self */, dc_debug_fmt /* fmt */, FILE* /* stream */) {}
32#endif
33
34#if !defined ITEM_DELETE
35 #define ITEM_DELETE DC_NO_DELETE
36#endif
37
38#if !defined ITEM_CLONE
39 #define ITEM_CLONE DC_COPY_CLONE
40#endif
41
42#if !defined ITEM_DEBUG
43 #define ITEM_DEBUG DC_DEFAULT_DEBUG
44#endif
45
46#if !defined CAPACITY
47 #if !defined DC_PLACEHOLDERS
48TEMPLATE_ERROR("The CAPACITY must be defined")
49 #endif
50 #define CAPACITY 8
51#endif
52#if CAPACITY == 0
53TEMPLATE_ERROR("CAPACITY must be greater than 0")
54#elif CAPACITY <= 255
55 #define INDEX_TYPE uint8_t
56#elif CAPACITY <= 65535
57 #define INDEX_TYPE uint16_t
58#else
59TEMPLATE_ERROR("CAPACITY must be less than or equal to 65535")
60 #define INDEX_TYPE size_t
61#endif
62
63typedef INDEX_TYPE NS(SELF, index_t);
64typedef ITEM NS(SELF, item_t);
65
66typedef struct {
67 INDEX_TYPE size;
69 dc_gdb_marker derive_c_staticvec;
71} SELF;
72
73#define INVARIANT_CHECK(self) \
74 DC_ASSUME(self); \
75 DC_ASSUME((self->size) <= CAPACITY);
76
77static SELF NS(SELF, new)() {
78 SELF self = {
79 .size = 0,
80 .derive_c_staticvec = dc_gdb_marker_new(),
81 .iterator_invalidation_tracker = mutation_tracker_new(),
82 };
83 return self;
84}
85
87
88DC_PUBLIC static SELF NS(SELF, clone)(SELF const* self) {
89 SELF new_self = NS(SELF, new)();
90 new_self.size = self->size;
91
92 for (INDEX_TYPE i = 0; i < self->size; i++) {
93 new_self.data[i] = ITEM_CLONE(&self->data[i]);
94 }
95
96 return new_self;
97}
98
99DC_PUBLIC static ITEM const* NS(SELF, try_read)(SELF const* self, INDEX_TYPE index) {
100 INVARIANT_CHECK(self);
101 if (DC_LIKELY(index < self->size)) {
102 return &self->data[index];
103 }
104 return NULL;
105}
106
107DC_PUBLIC static ITEM const* NS(SELF, read)(SELF const* self, INDEX_TYPE index) {
108 ITEM const* value = NS(SELF, try_read)(self, index);
109 DC_ASSERT(value, "Cannot read, index out of bounds {index=%lu, size=%lu}", (size_t)index,
110 (size_t)self->size);
111 return value;
112}
113
114DC_PUBLIC static ITEM* NS(SELF, try_write)(SELF* self, INDEX_TYPE index) {
115 INVARIANT_CHECK(self);
116 if (DC_LIKELY(index < self->size)) {
117 return &self->data[index];
118 }
119 return NULL;
120}
121
122DC_PUBLIC static ITEM* NS(SELF, write)(SELF* self, INDEX_TYPE index) {
123 ITEM* value = NS(SELF, try_write)(self, index);
124 DC_ASSERT(value, "Cannot write, index out of bounds {index=%lu, size=%lu}", (size_t)index,
125 (size_t)self->size);
126 return value;
127}
128
130 INVARIANT_CHECK(self);
131 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
132 if (self->size < CAPACITY) {
133 ITEM* slot = &self->data[self->size];
134 *slot = item;
135 self->size++;
136 return slot;
137 }
138 return NULL;
139}
140
141DC_PUBLIC static ITEM* NS(SELF, try_insert_at)(SELF* self, INDEX_TYPE at, ITEM const* items,
142 INDEX_TYPE count) {
143 INVARIANT_CHECK(self);
144 DC_ASSUME(items);
145 DC_ASSERT(at <= self->size, "Cannot insert at, index out of bounds {at=%lu, size=%lu}",
146 (size_t)at, (size_t)self->size);
147 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
148
149 if (self->size + count > CAPACITY) {
150 return NULL;
151 }
152
153 if (count == 0) {
154 return NULL;
155 }
156
157 memmove(&self->data[at + count], &self->data[at], (self->size - at) * sizeof(ITEM));
158 memcpy(&self->data[at], items, count * sizeof(ITEM));
159 self->size += count;
160 return &self->data[at];
161}
162
163DC_PUBLIC static void NS(SELF, remove_at)(SELF* self, INDEX_TYPE at, INDEX_TYPE count) {
164 INVARIANT_CHECK(self);
165 DC_ASSERT(at + count <= self->size,
166 "Cannot remove at, index out of bounds {at=%lu, count=%lu, size=%lu}", (size_t)at,
167 (size_t)count, (size_t)self->size);
168
169 if (count == 0) {
170 return;
171 }
172
173 for (INDEX_TYPE i = at; i < at + count; i++) {
174 ITEM_DELETE(&self->data[i]);
175 }
176
177 memmove(&self->data[at], &self->data[at + count], (self->size - (at + count)) * sizeof(ITEM));
178 self->size -= count;
179}
180
181DC_PUBLIC static ITEM* NS(SELF, push)(SELF* self, ITEM item) {
182 ITEM* slot = NS(SELF, try_push)(self, item);
183 DC_ASSERT(slot, "Cannot push, already at max capacity {capacity=%d, item=%s}", CAPACITY,
185 return slot;
186}
187
188DC_PUBLIC static bool NS(SELF, try_pop)(SELF* self, ITEM* destination) {
189 INVARIANT_CHECK(self);
190 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
191 if (DC_LIKELY(self->size > 0)) {
192 self->size--;
193 *destination = self->data[self->size];
194 return true;
195 }
196 return false;
197}
198
199DC_PUBLIC static ITEM NS(SELF, pop)(SELF* self) {
200 ITEM entry;
201 DC_ASSERT(NS(SELF, try_pop)(self, &entry), "Cannot pop, already empty {size=%lu}",
202 (size_t)self->size);
203 return entry;
204}
205
206DC_PUBLIC static INDEX_TYPE NS(SELF, size)(SELF const* self) {
207 INVARIANT_CHECK(self);
208 return self->size;
209}
210
211DC_PUBLIC static void NS(SELF, delete)(SELF* self) {
212 INVARIANT_CHECK(self);
213 for (INDEX_TYPE i = 0; i < self->size; i++) {
214 ITEM_DELETE(&self->data[i]);
215 }
216}
217
218#define ITER NS(SELF, iter)
219typedef ITEM* NS(ITER, item);
220
221DC_PUBLIC static bool NS(ITER, empty_item)(ITEM* const* item) { return *item == NULL; }
222
223typedef struct {
225 INDEX_TYPE pos;
227} ITER;
228
229DC_PUBLIC static ITEM* NS(ITER, next)(ITER* iter) {
230 DC_ASSUME(iter);
231 mutation_version_check(&iter->version);
232 if (iter->pos < iter->vec->size) {
233 ITEM* item = &iter->vec->data[iter->pos];
234 iter->pos++;
235 return item;
236 }
237 return NULL;
238}
239
240DC_PUBLIC static INDEX_TYPE NS(ITER, position)(ITER const* iter) {
241 DC_ASSUME(iter);
242 mutation_version_check(&iter->version);
243 return iter->pos;
244}
245
246DC_PUBLIC static bool NS(ITER, empty)(ITER const* iter) {
247 DC_ASSUME(iter);
248 mutation_version_check(&iter->version);
249 return iter->pos >= iter->vec->size;
250}
251
253 DC_ASSUME(self);
254 return (ITER){.vec = self,
255 .pos = 0,
256 .version = mutation_tracker_get(&self->iterator_invalidation_tracker)};
257}
258
259#undef ITER
260
261#define ITER_CONST NS(SELF, iter_const)
262typedef ITEM const* NS(ITER_CONST, item);
263
264DC_PUBLIC static bool NS(ITER_CONST, empty_item)(ITEM const* const* item) { return *item == NULL; }
265
266typedef struct {
267 SELF const* vec;
268 INDEX_TYPE pos;
270} ITER_CONST;
271
272DC_PUBLIC static ITEM const* NS(ITER_CONST, next)(ITER_CONST* iter) {
273 DC_ASSUME(iter);
274 mutation_version_check(&iter->version);
275 if (iter->pos < iter->vec->size) {
276 ITEM const* item = &iter->vec->data[iter->pos];
277 iter->pos++;
278 return item;
279 }
280 return NULL;
281}
282
283DC_PUBLIC static INDEX_TYPE NS(ITER_CONST, position)(ITER_CONST const* iter) {
284 DC_ASSUME(iter);
285 mutation_version_check(&iter->version);
286 return iter->pos;
287}
288
289DC_PUBLIC static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
290 DC_ASSUME(iter);
291 mutation_version_check(&iter->version);
292 return iter->pos >= iter->vec->size;
293}
294
296 DC_ASSUME(self);
297 return (ITER_CONST){
298 .vec = self,
299 .pos = 0,
300 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
301 };
302}
303
304DC_PUBLIC static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
305 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", (void*)self);
306 fmt = dc_debug_fmt_scope_begin(fmt);
307 dc_debug_fmt_print(fmt, stream, "capacity: %lu,\n", (size_t)CAPACITY);
308 dc_debug_fmt_print(fmt, stream, "size: %lu,\n", (size_t)self->size);
309
310 dc_debug_fmt_print(fmt, stream, "items: @%p [\n", (void*)self->data);
311 fmt = dc_debug_fmt_scope_begin(fmt);
312 ITER_CONST iter = NS(SELF, get_iter_const)(self);
313 ITEM const* item;
314 while ((item = NS(ITER_CONST, next)(&iter))) {
316 ITEM_DEBUG(item, fmt, stream);
317 fprintf(stream, ",\n");
318 }
319 fmt = dc_debug_fmt_scope_end(fmt);
320 dc_debug_fmt_print(fmt, stream, "],\n");
321 fmt = dc_debug_fmt_scope_end(fmt);
322 dc_debug_fmt_print(fmt, stream, "}");
323}
324
325#undef ITER_CONST
326#undef INVARIANT_CHECK
327#undef INDEX_TYPE
328#undef CAPACITY
329#undef ITEM_DEBUG
330#undef ITEM_CLONE
331#undef ITEM_DELETE
332#undef ITEM
333
335
static DC_PUBLIC void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:212
#define ITEM
Definition template.h:36
#define ITEM_DEBUG
Definition template.h:39
#define CAPACITY
A hybrid of a bump allocator on a statically allocated buffer, and any other allocator.
Definition template.h:18
#define DC_STATIC_CONSTANT
Definition attributes.h:23
static DC_PUBLIC VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180
static DC_PUBLIC VALUE * try_write(SELF *self, INDEX index)
Definition template.h:205
#define INVARIANT_CHECK(self)
Definition template.h:90
static DC_PUBLIC IV_PAIR next(ITER *iter)
Definition template.h:355
static DC_PUBLIC bool empty(ITER const *iter)
Definition template.h:349
static DC_PUBLIC VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static DC_PUBLIC VALUE * write(SELF *self, INDEX index)
Definition template.h:209
static DC_PUBLIC bool empty_item(IV_PAIR const *item)
Definition template.h:347
#define ITER
Definition template.h:322
static DC_PUBLIC ITER get_iter(SELF *self)
Definition template.h:373
#define ITER_CONST
Definition template.h:411
static DC_PUBLIC ITER_CONST get_iter_const(SELF const *self)
Definition template.h:464
static DC_PUBLIC size_t size(SELF const *self)
Definition template.h:252
static DC_PUBLIC SELF clone(SELF const *self)
Definition template.h:215
IV_PAIR item
Definition template.h:281
INDEX_TYPE index_t
Definition template.h:26
#define ITEM_DELETE
Definition template.h:20
#define ITEM_CLONE
Definition template.h:22
#define ITEM_DEBUG
Definition template.h:24
static DC_PUBLIC ITEM * try_push(SELF *self, ITEM item)
Definition template.h:232
DC_STATIC_CONSTANT size_t max_size
Definition template.h:56
static DC_PUBLIC bool try_pop(SELF *self, ITEM *destination)
Definition template.h:270
static DC_PUBLIC ITEM * try_insert_at(SELF *self, size_t at, ITEM const *items, size_t count)
Definition template.h:190
static DC_PUBLIC void remove_at(SELF *self, size_t at, size_t count)
Definition template.h:211
static DC_PUBLIC ITEM * push(SELF *self, ITEM item)
Definition template.h:263
static DC_PUBLIC DC_INLINE size_t position(ITER const *DC_RESTRICT iter)
Definition template.h:394
static DC_PUBLIC ITEM pop(SELF *self)
Definition template.h:289
#define DC_TRAIT_VECTOR(SELF)
Definition trait.h:5
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
Definition def.h:56
#define SELF
Definition def.h:52
#define DC_DEBUG(DEBUG_FN, DEBUG_PTR)
Definition dump.h:92
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
static DC_PUBLIC dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:8
static DC_PUBLIC void mutation_tracker_mutate(mutation_tracker *self)
static DC_PUBLIC void mutation_version_check(mutation_version const *self)
static DC_PUBLIC mutation_tracker mutation_tracker_new()
static DC_PUBLIC mutation_version mutation_tracker_get(mutation_tracker const *self)
#define DC_PUBLIC
Definition namespace.h:25
#define NS(pre, post)
Definition namespace.h:14
#define DC_EXPAND_STRING(NAME)
Definition namespace.h:6
#define DC_ASSERT(expr,...)
Definition panic.h:37
#define DC_ASSUME(expr,...)
Definition panic.h:57
#define DC_LIKELY(x)
Definition panic.h:48
size_t pos
Definition template.h:280
mutation_version version
Definition template.h:417
SELF const * vec
Definition template.h:267
mutation_version version
Definition template.h:328
SELF * vec
Definition template.h:224
size_t pos
Definition template.h:233
mutation_tracker iterator_invalidation_tracker
Definition template.h:87
size_t size
Definition template.h:75
ITEM * data
Definition template.h:44
dc_gdb_marker derive_c_staticvec
Definition template.h:69
Debug format helpers for debug printin data structures.
Definition fmt.h:11
A queue comprised of an extendable circular buffer.
Definition template.h:16
tracks a specific version of a value, so that this can be compared later to check modification For ex...
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108