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 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);
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 INPLACE_CAPACITY
47 #if !defined PLACEHOLDERS
48TEMPLATE_ERROR("The INPLACE_CAPACITY must be defined")
49 #endif
50 #define INPLACE_CAPACITY 8
51#endif
52#if INPLACE_CAPACITY == 0
53TEMPLATE_ERROR("INPLACE_CAPACITY must be greater than 0")
54#elif INPLACE_CAPACITY <= 255
55 #define INDEX_TYPE uint8_t
56#elif INPLACE_CAPACITY <= 65535
57 #define INDEX_TYPE uint16_t
58#else
59TEMPLATE_ERROR("INPLACE_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 {
69 dc_gdb_marker derive_c_staticvec;
71} SELF;
72
73#define INVARIANT_CHECK(self) \
74 DC_ASSUME(self); \
75 DC_ASSUME((self->size) <= INPLACE_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
86static size_t NS(SELF, max_size)() { return INPLACE_CAPACITY; }
87
88static 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
99static 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
107static 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);
110 return value;
111}
112
113static ITEM* NS(SELF, try_write)(SELF* self, INDEX_TYPE index) {
114 INVARIANT_CHECK(self);
115 if (DC_LIKELY(index < self->size)) {
116 return &self->data[index];
117 }
118 return NULL;
119}
120
121static ITEM* NS(SELF, write)(SELF* self, INDEX_TYPE index) {
122 ITEM* value = NS(SELF, try_write)(self, index);
123 DC_ASSERT(value);
124 return value;
125}
126
127static ITEM* NS(SELF, try_push)(SELF* self, ITEM item) {
128 INVARIANT_CHECK(self);
129 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
130 if (self->size < INPLACE_CAPACITY) {
131 ITEM* slot = &self->data[self->size];
132 *slot = item;
133 self->size++;
134 return slot;
135 }
136 return NULL;
137}
138
139static ITEM* NS(SELF, try_insert_at)(SELF* self, INDEX_TYPE at, ITEM const* items,
140 INDEX_TYPE count) {
141 INVARIANT_CHECK(self);
142 DC_ASSUME(items);
143 DC_ASSERT(at <= self->size);
144 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
145
146 if (self->size + count > INPLACE_CAPACITY) {
147 return NULL;
148 }
149
150 if (count == 0) {
151 return NULL;
152 }
153
154 memmove(&self->data[at + count], &self->data[at], (self->size - at) * sizeof(ITEM));
155 memcpy(&self->data[at], items, count * sizeof(ITEM));
156 self->size += count;
157 return &self->data[at];
158}
159
160static void NS(SELF, remove_at)(SELF* self, INDEX_TYPE at, INDEX_TYPE count) {
161 INVARIANT_CHECK(self);
162 DC_ASSERT(at + count <= self->size);
163
164 if (count == 0) {
165 return;
166 }
167
168 for (INDEX_TYPE i = at; i < at + count; i++) {
169 ITEM_DELETE(&self->data[i]);
170 }
171
172 memmove(&self->data[at], &self->data[at + count], (self->size - (at + count)) * sizeof(ITEM));
173 self->size -= count;
174}
175
176static ITEM* NS(SELF, push)(SELF* self, ITEM item) {
177 ITEM* slot = NS(SELF, try_push)(self, item);
178 DC_ASSERT(slot);
179 return slot;
180}
181
182static bool NS(SELF, try_pop)(SELF* self, ITEM* destination) {
183 INVARIANT_CHECK(self);
184 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
185 if (DC_LIKELY(self->size > 0)) {
186 self->size--;
187 *destination = self->data[self->size];
188 return true;
189 }
190 return false;
191}
192
193static ITEM NS(SELF, pop)(SELF* self) {
194 ITEM entry;
195 DC_ASSERT(NS(SELF, try_pop)(self, &entry));
196 return entry;
197}
198
199static INDEX_TYPE NS(SELF, size)(SELF const* self) {
200 INVARIANT_CHECK(self);
201 return self->size;
202}
203
204static void NS(SELF, delete)(SELF* self) {
205 INVARIANT_CHECK(self);
206 for (INDEX_TYPE i = 0; i < self->size; i++) {
207 ITEM_DELETE(&self->data[i]);
208 }
209}
210
211#define ITER NS(SELF, iter)
212typedef ITEM* NS(ITER, item);
213
214static bool NS(ITER, empty_item)(ITEM* const* item) { return *item == NULL; }
215
216typedef struct {
217 SELF* vec;
220} ITER;
221
222static ITEM* NS(ITER, next)(ITER* iter) {
223 DC_ASSUME(iter);
224 mutation_version_check(&iter->version);
225 if (iter->pos < iter->vec->size) {
226 ITEM* item = &iter->vec->data[iter->pos];
227 iter->pos++;
228 return item;
229 }
230 return NULL;
231}
232
233static INDEX_TYPE NS(ITER, position)(ITER const* iter) {
234 DC_ASSUME(iter);
235 mutation_version_check(&iter->version);
236 return iter->pos;
237}
238
239static bool NS(ITER, empty)(ITER const* iter) {
240 DC_ASSUME(iter);
241 mutation_version_check(&iter->version);
242 return iter->pos >= iter->vec->size;
243}
244
245static ITER NS(SELF, get_iter)(SELF* self) {
246 DC_ASSUME(self);
247 return (ITER){.vec = self,
248 .pos = 0,
249 .version = mutation_tracker_get(&self->iterator_invalidation_tracker)};
250}
251
252#undef ITER
253
254#define ITER_CONST NS(SELF, iter_const)
255typedef ITEM const* NS(ITER_CONST, item);
256
257static bool NS(ITER_CONST, empty_item)(ITEM const* const* item) { return *item == NULL; }
258
259typedef struct {
260 SELF const* vec;
263} ITER_CONST;
264
265static ITEM const* NS(ITER_CONST, next)(ITER_CONST* iter) {
266 DC_ASSUME(iter);
267 mutation_version_check(&iter->version);
268 if (iter->pos < iter->vec->size) {
269 ITEM const* item = &iter->vec->data[iter->pos];
270 iter->pos++;
271 return item;
272 }
273 return NULL;
274}
275
277 DC_ASSUME(iter);
278 mutation_version_check(&iter->version);
279 return iter->pos;
280}
281
282static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
283 DC_ASSUME(iter);
284 mutation_version_check(&iter->version);
285 return iter->pos >= iter->vec->size;
286}
287
288static ITER_CONST NS(SELF, get_iter_const)(SELF const* self) {
289 DC_ASSUME(self);
290 return (ITER_CONST){
291 .vec = self,
292 .pos = 0,
293 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
294 };
295}
296
297static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
298 fprintf(stream, EXPAND_STRING(SELF) "@%p {\n", self);
299 fmt = dc_debug_fmt_scope_begin(fmt);
300 dc_debug_fmt_print(fmt, stream, "capacity: %lu,\n", (size_t)INPLACE_CAPACITY);
301 dc_debug_fmt_print(fmt, stream, "size: %lu,\n", (size_t)self->size);
302
303 dc_debug_fmt_print(fmt, stream, "items: @%p [\n", self->data);
304 fmt = dc_debug_fmt_scope_begin(fmt);
305 ITER_CONST iter = NS(SELF, get_iter_const)(self);
306 ITEM const* item;
307 while ((item = NS(ITER_CONST, next)(&iter))) {
309 ITEM_DEBUG(item, fmt, stream);
310 fprintf(stream, ",\n");
311 }
312 fmt = dc_debug_fmt_scope_end(fmt);
313 dc_debug_fmt_print(fmt, stream, "],\n");
314 fmt = dc_debug_fmt_scope_end(fmt);
315 dc_debug_fmt_print(fmt, stream, "}\n");
316}
317
318#undef ITER_CONST
319#undef INVARIANT_CHECK
320#undef INDEX_TYPE
321#undef INPLACE_CAPACITY
322#undef ITEM_DEBUG
323#undef ITEM_CLONE
324#undef ITEM_DELETE
325#undef ITEM
326
328
static void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:62
#define ITEM
Definition template.h:63
static ITER_CONST get_iter_const(SELF const *self)
Definition template.h:449
static bool empty(ITER const *iter)
Definition template.h:346
static ITER get_iter(SELF *self)
Definition template.h:370
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
static bool empty_item(IV_PAIR const *item)
Definition template.h:344
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:205
static VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static VALUE * write(SELF *self, INDEX index)
Definition template.h:209
#define ITER
Definition template.h:320
#define ITER_CONST
Definition template.h:398
static SELF clone(SELF const *self)
Definition template.h:215
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180
IV_PAIR item
Definition template.h:283
INDEX_TYPE index_t
Definition template.h:32
#define INDEX_TYPE
Definition template.h:74
#define ITEM_DELETE
Definition template.h:20
#define ITEM_CLONE
Definition template.h:22
#define ITEM_DEBUG
Definition template.h:24
static void remove_at(SELF *self, size_t at, size_t count)
Definition template.h:197
static ITEM * push(SELF *self, ITEM item)
Definition template.h:216
static size_t max_size()
Definition template.h:57
static bool try_pop(SELF *self, ITEM *destination)
Definition template.h:247
static ITEM pop(SELF *self)
Definition template.h:266
static size_t position(ITER const *iter)
Definition template.h:368
static ITEM * try_insert_at(SELF *self, size_t at, ITEM const *items, size_t count)
Definition template.h:178
static ITEM * try_push(SELF *self, ITEM item)
Definition template.h:127
#define INPLACE_CAPACITY
Definition template.h:50
#define DC_TRAIT_VECTOR(SELF)
Definition trait.h:5
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
static dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:7
static mutation_tracker mutation_tracker_new()
static void mutation_version_check(mutation_version const *self)
static mutation_version mutation_tracker_get(mutation_tracker const *self)
static void mutation_tracker_mutate(mutation_tracker *self)
#define EXPAND_STRING(NAME)
Definition namespace.h:8
#define NS(pre, post)
Definition namespace.h:4
#define DC_ASSERT(expr,...)
Definition panic.h:36
#define DC_ASSUME(expr,...)
Definition panic.h:56
#define DC_LIKELY(x)
Definition panic.h:47
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
Definition def.h:56
#define SELF
Definition def.h:52
size_t pos
Definition template.h:261
mutation_version version
Definition template.h:404
mutation_version version
Definition template.h:326
size_t pos
Definition template.h:214
mutation_tracker iterator_invalidation_tracker
Definition template.h:85
size_t size
Definition template.h:43
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:10
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 FILE * stream(SELF *self)
Opens a file for.
Definition template.h:107