Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
2
4#if !defined(SKIP_INCLUDES)
5 #include "includes.h"
6#endif
7
10
11#if !defined ITEM
12 #if !defined DC_PLACEHOLDERS
13TEMPLATE_ERROR("No ITEM")
14 #endif
15
16typedef struct {
17 int x;
18} item_t;
19 #define ITEM item_t
20
21 #define ITEM_DELETE item_delete
22static void ITEM_DELETE(item_t* /* self */) {}
23 #define ITEM_CLONE item_clone
24static item_t ITEM_CLONE(item_t const* self) { return *self; }
25 #define ITEM_DEBUG item_debug
26static void ITEM_DEBUG(ITEM const* /* self */, dc_debug_fmt /* fmt */, FILE* /* stream */) {}
27#endif
28
29#if !defined ITEM_DELETE
30 #define ITEM_DELETE DC_NO_DELETE
31#endif
32
33#if !defined ITEM_CLONE
34 #define ITEM_CLONE DC_COPY_CLONE
35#endif
36
37#if !defined ITEM_DEBUG
38 #define ITEM_DEBUG DC_DEFAULT_DEBUG
39#endif
40
41typedef ITEM NS(SELF, item_t);
42typedef ALLOC NS(SELF, alloc_t);
43
44#define ITEM_VECTORS NS(NAME, item_vectors)
45
46#pragma push_macro("ALLOC")
47#pragma push_macro("ITEM")
48#pragma push_macro("ITEM_CLONE")
49#pragma push_macro("ITEM_DELETE")
50
51// ITEM is already defined
52#define INTERNAL_NAME ITEM_VECTORS // [DERIVE-C] for template
54
55#pragma pop_macro("ALLOC")
56#pragma pop_macro("ITEM")
57#pragma pop_macro("ITEM_CLONE")
58#pragma pop_macro("ITEM_DELETE")
59
60typedef struct {
63 dc_gdb_marker derive_c_deque;
65} SELF;
66
67#define INVARIANT_CHECK(self) DC_ASSUME(self);
68
69DC_PUBLIC static SELF NS(SELF, new)(NS(ALLOC, ref) alloc_ref) {
70 return (SELF){
71 .front = NS(ITEM_VECTORS, new)(alloc_ref),
72 .back = NS(ITEM_VECTORS, new)(alloc_ref),
73 .derive_c_deque = dc_gdb_marker_new(),
74 .iterator_invalidation_tracker = mutation_tracker_new(),
75 };
76}
77
78DC_PUBLIC static SELF NS(SELF, new_with_capacity)(size_t front_and_back_capacity,
79 NS(ALLOC, ref) alloc_ref) {
80 return (SELF){
81 .front = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc_ref),
82 .back = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc_ref),
83 .derive_c_deque = dc_gdb_marker_new(),
84 .iterator_invalidation_tracker = mutation_tracker_new(),
85 };
86}
87
88DC_PUBLIC static SELF NS(SELF, clone)(SELF const* other) {
89 INVARIANT_CHECK(other);
90 return (SELF){
91 .front = NS(ITEM_VECTORS, clone)(&other->front),
92 .back = NS(ITEM_VECTORS, clone)(&other->back),
93 .derive_c_deque = dc_gdb_marker_new(),
94 .iterator_invalidation_tracker = mutation_tracker_new(),
95 };
96}
97
98DC_PUBLIC static size_t NS(SELF, size)(SELF const* self) {
99 INVARIANT_CHECK(self);
100 return NS(ITEM_VECTORS, size)(&self->front) + NS(ITEM_VECTORS, size)(&self->back);
101}
102
103DC_PUBLIC static bool NS(SELF, empty)(SELF const* self) {
104 INVARIANT_CHECK(self);
105 return NS(ITEM_VECTORS, size)(&self->front) == 0 && NS(ITEM_VECTORS, size)(&self->back) == 0;
106}
107
108DC_PUBLIC static void NS(SELF, rebalance)(SELF* self) {
109 INVARIANT_CHECK(self);
110 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
111
112 size_t const front_size = NS(ITEM_VECTORS, size)(&self->front);
113 size_t const back_size = NS(ITEM_VECTORS, size)(&self->back);
114 size_t const total_size = front_size + back_size;
115
116 // Let the rebalance policy decide if we should rebalance
117 if (!_dc_deque_rebalance_policy(total_size, front_size, back_size)) {
118 return;
119 }
120
121 ITEM_VECTORS* source;
122 ITEM_VECTORS* target;
123 size_t source_size;
124 size_t target_size;
125
126 if (front_size > back_size) {
127 source = &self->front;
128 target = &self->back;
129 source_size = front_size;
130 target_size = back_size;
131 } else {
132 source = &self->back;
133 target = &self->front;
134 source_size = back_size;
135 target_size = front_size;
136 }
137
138 size_t to_move = (source_size - target_size) / 2;
139 // If target is empty, we must move at least 1 element (or all if only 1 exists)
140 if (target_size == 0 && source_size > 0) {
141 to_move = (source_size + 1) / 2; // Move at least half, or 1 if only 1 element
142 }
143 NS(ITEM_VECTORS, transfer_reverse)(source, target, to_move);
144}
145
146DC_PUBLIC static ITEM const* NS(SELF, try_read_from_front)(SELF const* self, size_t index) {
147 INVARIANT_CHECK(self);
148
149 if (index < NS(ITEM_VECTORS, size)(&self->front)) {
150 size_t front_index = NS(ITEM_VECTORS, size)(&self->front) - 1 - index;
151 return NS(ITEM_VECTORS, read)(&self->front, front_index);
152 }
153
154 size_t back_index = index - NS(ITEM_VECTORS, size)(&self->front);
155 return NS(ITEM_VECTORS, try_read)(&self->back, back_index);
156}
157
158DC_PUBLIC static ITEM const* NS(SELF, try_read_from_back)(SELF const* self, size_t index) {
159 return NS(SELF, try_read_from_front)(self, NS(SELF, size)(self) - 1 - index);
160}
161
162DC_PUBLIC static ITEM* NS(SELF, try_write_from_front)(SELF* self, size_t index) {
163 return (ITEM*)NS(SELF, try_read_from_front)(self, index);
164}
165
166DC_PUBLIC static ITEM* NS(SELF, try_write_from_back)(SELF* self, size_t index) {
167 return (ITEM*)NS(SELF, try_read_from_back)(self, index);
168}
169
170DC_PUBLIC static void NS(SELF, push_front)(SELF* self, ITEM item) {
171 INVARIANT_CHECK(self);
172 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
173 NS(ITEM_VECTORS, push)(&self->front, item);
174 NS(SELF, rebalance)(self);
175}
176
177DC_PUBLIC static void NS(SELF, push_back)(SELF* self, ITEM item) {
178 INVARIANT_CHECK(self);
179 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
180 NS(ITEM_VECTORS, push)(&self->back, item);
181 NS(SELF, rebalance)(self);
182}
183
185 INVARIANT_CHECK(self);
186 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
187 if (NS(ITEM_VECTORS, size)(&self->front) > 0) {
188 ITEM result = NS(ITEM_VECTORS, pop)(&self->front);
189 NS(SELF, rebalance)(self);
190 return result;
191 }
192
193 // Front is empty, need to pop from back
194 // Rebalance first to move elements to front, then pop
195 // No need to rebalance again after pop since we just rebalanced
196 if (NS(ITEM_VECTORS, size)(&self->back) > 0) {
197 NS(SELF, rebalance)(self);
198 return NS(ITEM_VECTORS, pop)(&self->front);
199 }
200
201 // Both sides empty - should not happen if deque is non-empty
202 DC_UNREACHABLE("Cannot pop from empty deque");
203}
204
206 INVARIANT_CHECK(self);
207 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
208 if (NS(ITEM_VECTORS, size)(&self->back) > 0) {
209 ITEM result = NS(ITEM_VECTORS, pop)(&self->back);
210 NS(SELF, rebalance)(self);
211 return result;
212 }
213
214 // Back is empty, need to pop from front
215 // Rebalance first to move elements to back, then pop
216 // No need to rebalance again after pop since we just rebalanced
217 if (NS(ITEM_VECTORS, size)(&self->front) > 0) {
218 NS(SELF, rebalance)(self);
219 return NS(ITEM_VECTORS, pop)(&self->back);
220 }
221
222 // Both sides empty - should not happen if deque is non-empty
223 DC_UNREACHABLE("Cannot pop from empty deque");
224}
225
226#define ITER NS(SELF, iter)
227typedef ITEM* NS(ITER, item);
228
229DC_PUBLIC static bool NS(ITER, empty_item)(ITEM* const* item) { return *item == NULL; }
230
231typedef struct {
233 size_t pos;
235} ITER;
236
237DC_PUBLIC static ITEM* NS(ITER, next)(ITER* iter) {
238 DC_ASSUME(iter);
239 mutation_version_check(&iter->version);
240 size_t const front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
241 size_t const back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
242 size_t const total_size = front_size + back_size;
243
244 if (iter->pos < total_size) {
245 ITEM* item;
246 if (iter->pos < front_size) {
247 item = NS(ITEM_VECTORS, write)(&iter->deque->front, front_size - 1 - iter->pos);
248 } else {
249 item = NS(ITEM_VECTORS, write)(&iter->deque->back, iter->pos - front_size);
250 }
251 iter->pos++;
252 return item;
253 }
254 return NULL;
255}
256
257DC_PUBLIC static bool NS(ITER, empty)(ITER const* iter) {
258 mutation_version_check(&iter->version);
259 DC_ASSUME(iter);
260 return iter->pos >=
261 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
262}
263
265 DC_ASSUME(self);
266 return (ITER){.deque = self,
267 .pos = 0,
268 .version = mutation_tracker_get(&self->iterator_invalidation_tracker)};
269}
270
271#undef ITER
272
273#define ITER_CONST NS(SELF, iter_const)
274typedef ITEM const* NS(ITER_CONST, item);
275
276DC_PUBLIC static bool NS(ITER_CONST, empty_item)(ITEM const* const* item) { return *item == NULL; }
277
278typedef struct {
279 SELF const* deque;
280 size_t pos;
282} ITER_CONST;
283
284DC_PUBLIC static ITEM const* NS(ITER_CONST, next)(ITER_CONST* iter) {
285 DC_ASSUME(iter);
286 mutation_version_check(&iter->version);
287 size_t const front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
288 size_t const back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
289 size_t const total_size = front_size + back_size;
290
291 if (iter->pos < total_size) {
292 ITEM const* item;
293 if (iter->pos < front_size) {
294 item = NS(ITEM_VECTORS, read)(&iter->deque->front, front_size - 1 - iter->pos);
295 } else {
296 item = NS(ITEM_VECTORS, read)(&iter->deque->back, iter->pos - front_size);
297 }
298 iter->pos++;
299 return item;
300 }
301 return NULL;
302}
303
304DC_PUBLIC static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
305 DC_ASSUME(iter);
306 mutation_version_check(&iter->version);
307 return iter->pos >=
308 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
309}
310
312 DC_ASSUME(self);
313 return (ITER_CONST){
314 .deque = self,
315 .pos = 0,
316 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
317 };
318}
319
320#undef ITER_CONST
321
322DC_PUBLIC static void NS(SELF, delete)(SELF* self) {
323 INVARIANT_CHECK(self);
324 NS(ITEM_VECTORS, delete)(&self->front);
325 NS(ITEM_VECTORS, delete)(&self->back);
326}
327
328DC_PUBLIC static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
329 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", self);
330 fmt = dc_debug_fmt_scope_begin(fmt);
331 dc_debug_fmt_print(fmt, stream, "size: %lu,\n", NS(SELF, size)(self));
332
333 dc_debug_fmt_print(fmt, stream, "front: ");
334 NS(ITEM_VECTORS, debug)(&self->front, fmt, stream);
335 fprintf(stream, ",\n");
336
337 dc_debug_fmt_print(fmt, stream, "back: ");
338 NS(ITEM_VECTORS, debug)(&self->back, fmt, stream);
339 fprintf(stream, ",\n");
340
341 fmt = dc_debug_fmt_scope_end(fmt);
342 dc_debug_fmt_print(fmt, stream, "}");
343}
344
345#undef INVARIANT_CHECK
346#undef ITEM_VECTORS
347#undef ITEM_DEBUG
348#undef ITEM_CLONE
349#undef ITEM_DELETE
350#undef ITEM
351
353
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 ALLOC
Definition template.h:31
static DC_PUBLIC VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180
#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
ALLOC alloc_t
Definition template.h:63
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
#define ITEM_DELETE
Definition template.h:20
static DC_PUBLIC ITEM * try_write_from_back(SELF *self, size_t index)
Definition template.h:288
static DC_PUBLIC ITEM pop_front(SELF *self)
Definition template.h:219
static DC_PUBLIC ITEM const * try_read_from_front(SELF const *self, size_t index)
Definition template.h:262
static DC_PUBLIC ITEM * try_write_from_front(SELF *self, size_t index)
Definition template.h:284
static DC_PUBLIC void push_front(SELF *self, ITEM item)
Definition template.h:200
static DC_PUBLIC ITEM const * try_read_from_back(SELF const *self, size_t index)
Definition template.h:272
#define ITEM_CLONE
Definition template.h:22
#define ITEM_DEBUG
Definition template.h:24
static DC_PUBLIC void push_back(SELF *self, ITEM item)
Definition template.h:185
static DC_PUBLIC ITEM pop_back(SELF *self)
Definition template.h:240
#define ITEM_VECTORS
Definition template.h:44
static DC_PUBLIC void rebalance(SELF *self)
Definition template.h:108
static DC_PUBLIC SELF new_with_capacity(size_t front_and_back_capacity, ref alloc_ref)
Definition template.h:78
#define DC_TRAIT_QUEUE(SELF)
Definition trait.h:5
static DC_PUBLIC ITEM * push(SELF *self, ITEM item)
Definition template.h:263
static DC_PUBLIC ITEM pop(SELF *self)
Definition template.h:289
static DC_PUBLIC void transfer_reverse(SELF *source, SELF *target, size_t to_move)
Definition template.h:348
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
Definition def.h:56
#define SELF
Definition def.h:52
static DC_PUBLIC void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
Definition fmt.h:32
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_UNREACHABLE(...)
Definition panic.h:44
#define DC_ASSUME(expr,...)
Definition panic.h:57
static bool _dc_deque_rebalance_policy(size_t total_size, size_t front_size, size_t back_size)
Definition utils.h:6
size_t pos
Definition template.h:280
SELF const * deque
Definition template.h:279
mutation_version version
Definition template.h:417
mutation_version version
Definition template.h:328
SELF * deque
Definition template.h:232
size_t pos
Definition template.h:233
mutation_tracker iterator_invalidation_tracker
Definition template.h:87
dc_gdb_marker derive_c_deque
Definition template.h:63
ITEM_VECTORS back
Definition template.h:62
ITEM_VECTORS front
Definition template.h:61
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