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 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);
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
69static SELF NS(SELF, new)(ALLOC* alloc) {
70 return (SELF){
71 .front = NS(ITEM_VECTORS, new)(alloc),
72 .back = NS(ITEM_VECTORS, new)(alloc),
73 .derive_c_deque = dc_gdb_marker_new(),
74 .iterator_invalidation_tracker = mutation_tracker_new(),
75 };
76}
77
78static SELF NS(SELF, new_with_capacity)(size_t front_and_back_capacity, ALLOC* alloc) {
79 return (SELF){
80 .front = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc),
81 .back = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc),
82 .derive_c_deque = dc_gdb_marker_new(),
83 .iterator_invalidation_tracker = mutation_tracker_new(),
84 };
85}
86
87static SELF NS(SELF, clone)(SELF const* other) {
88 INVARIANT_CHECK(other);
89 return (SELF){
90 .front = NS(ITEM_VECTORS, clone)(&other->front),
91 .back = NS(ITEM_VECTORS, clone)(&other->back),
92 .derive_c_deque = dc_gdb_marker_new(),
93 .iterator_invalidation_tracker = mutation_tracker_new(),
94 };
95}
96
97static size_t NS(SELF, size)(SELF const* self) {
98 INVARIANT_CHECK(self);
99 return NS(ITEM_VECTORS, size)(&self->front) + NS(ITEM_VECTORS, size)(&self->back);
100}
101
102static bool NS(SELF, empty)(SELF const* self) {
103 INVARIANT_CHECK(self);
104 return NS(ITEM_VECTORS, size)(&self->front) == 0 && NS(ITEM_VECTORS, size)(&self->back) == 0;
105}
106
107static void NS(SELF, rebalance)(SELF* self) {
108 INVARIANT_CHECK(self);
109 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
110
111 size_t const front_size = NS(ITEM_VECTORS, size)(&self->front);
112 size_t const back_size = NS(ITEM_VECTORS, size)(&self->back);
113 size_t const total_size = front_size + back_size;
114
115 if (!dc_deque_rebalance_policy(total_size, front_size)) {
116 return;
117 }
118
119 ITEM_VECTORS* source;
120 ITEM_VECTORS* target;
121 size_t source_size;
122 size_t target_size;
123
124 if (front_size > back_size + 1) {
125 source = &self->front;
126 target = &self->back;
127 source_size = front_size;
128 target_size = back_size;
129 } else {
130 DC_ASSUME(back_size > front_size + 1);
131 source = &self->back;
132 target = &self->front;
133 source_size = back_size;
134 target_size = front_size;
135 }
136
137 size_t const to_move = (source_size - target_size) / 2;
138 NS(ITEM_VECTORS, transfer_reverse)(source, target, to_move);
139}
140
141static ITEM const* NS(SELF, try_read_from_front)(SELF const* self, size_t index) {
142 INVARIANT_CHECK(self);
143
144 if (index < NS(ITEM_VECTORS, size)(&self->front)) {
145 size_t front_index = NS(ITEM_VECTORS, size)(&self->front) - 1 - index;
146 return NS(ITEM_VECTORS, read)(&self->front, front_index);
147 }
148
149 size_t back_index = index - NS(ITEM_VECTORS, size)(&self->front);
150 return NS(ITEM_VECTORS, try_read)(&self->back, back_index);
151}
152
153static ITEM const* NS(SELF, try_read_from_back)(SELF const* self, size_t index) {
154 return NS(SELF, try_read_from_front)(self, NS(SELF, size)(self) - 1 - index);
155}
156
157static ITEM* NS(SELF, try_write_from_front)(SELF* self, size_t index) {
158 return (ITEM*)NS(SELF, try_read_from_front)(self, index);
159}
160
161static ITEM* NS(SELF, try_write_from_back)(SELF* self, size_t index) {
162 return (ITEM*)NS(SELF, try_read_from_back)(self, index);
163}
164
165static void NS(SELF, push_front)(SELF* self, ITEM item) {
166 INVARIANT_CHECK(self);
167 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
168 NS(ITEM_VECTORS, push)(&self->front, item);
169 NS(SELF, rebalance)(self);
170}
171
172static void NS(SELF, push_back)(SELF* self, ITEM item) {
173 INVARIANT_CHECK(self);
174 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
175 NS(ITEM_VECTORS, push)(&self->back, item);
176 NS(SELF, rebalance)(self);
177}
178
179static ITEM NS(SELF, pop_front)(SELF* self) {
180 INVARIANT_CHECK(self);
181 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
182 if (NS(ITEM_VECTORS, size)(&self->front) > 0) {
183 ITEM result = NS(ITEM_VECTORS, pop)(&self->front);
184 NS(SELF, rebalance)(self);
185 return result;
186 }
187
188 ITEM result = NS(ITEM_VECTORS, pop_front)(&self->back);
189 NS(SELF, rebalance)(self);
190 return result;
191}
192
193static ITEM NS(SELF, pop_back)(SELF* self) {
194 INVARIANT_CHECK(self);
195 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
196 if (NS(ITEM_VECTORS, size)(&self->back) > 0) {
197 ITEM result = NS(ITEM_VECTORS, pop)(&self->back);
198 NS(SELF, rebalance)(self);
199 return result;
200 }
201
202 ITEM result = NS(ITEM_VECTORS, pop_front)(&self->front);
203 NS(SELF, rebalance)(self);
204 return result;
205}
206
207#define ITER NS(SELF, iter)
208typedef ITEM* NS(ITER, item);
209
210static bool NS(ITER, empty_item)(ITEM* const* item) { return *item == NULL; }
211
212typedef struct {
214 size_t pos;
216} ITER;
217
218static ITEM* NS(ITER, next)(ITER* iter) {
219 DC_ASSUME(iter);
220 mutation_version_check(&iter->version);
221 size_t const front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
222 size_t const back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
223 size_t const total_size = front_size + back_size;
224
225 if (iter->pos < total_size) {
226 ITEM* item;
227 if (iter->pos < front_size) {
228 item = NS(ITEM_VECTORS, write)(&iter->deque->front, front_size - 1 - iter->pos);
229 } else {
230 item = NS(ITEM_VECTORS, write)(&iter->deque->back, iter->pos - front_size);
231 }
232 iter->pos++;
233 return item;
234 }
235 return NULL;
236}
237
238static bool NS(ITER, empty)(ITER const* iter) {
239 mutation_version_check(&iter->version);
240 DC_ASSUME(iter);
241 return iter->pos >=
242 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
243}
244
245static ITER NS(SELF, get_iter)(SELF* self) {
246 DC_ASSUME(self);
247 return (ITER){.deque = 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* deque;
261 size_t pos;
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 size_t const front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
269 size_t const back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
270 size_t const total_size = front_size + back_size;
271
272 if (iter->pos < total_size) {
273 ITEM const* item;
274 if (iter->pos < front_size) {
275 item = NS(ITEM_VECTORS, read)(&iter->deque->front, front_size - 1 - iter->pos);
276 } else {
277 item = NS(ITEM_VECTORS, read)(&iter->deque->back, iter->pos - front_size);
278 }
279 iter->pos++;
280 return item;
281 }
282 return NULL;
283}
284
285static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
286 DC_ASSUME(iter);
287 mutation_version_check(&iter->version);
288 return iter->pos >=
289 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
290}
291
292static ITER_CONST NS(SELF, get_iter_const)(SELF const* self) {
293 DC_ASSUME(self);
294 return (ITER_CONST){
295 .deque = self,
296 .pos = 0,
297 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
298 };
299}
300
301#undef ITER_CONST
302
303static void NS(SELF, delete)(SELF* self) {
304 INVARIANT_CHECK(self);
305 NS(ITEM_VECTORS, delete)(&self->front);
306 NS(ITEM_VECTORS, delete)(&self->back);
307}
308
309static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
310 fprintf(stream, EXPAND_STRING(SELF) "@%p {\n", self);
311 fmt = dc_debug_fmt_scope_begin(fmt);
312 dc_debug_fmt_print(fmt, stream, "size: %lu,\n", NS(SELF, size)(self));
313
314 dc_debug_fmt_print(fmt, stream, "front: ");
315 NS(ITEM_VECTORS, debug)(&self->front, fmt, stream);
316 fprintf(stream, ",\n");
317
318 dc_debug_fmt_print(fmt, stream, "back: ");
319 NS(ITEM_VECTORS, debug)(&self->back, fmt, stream);
320 fprintf(stream, ",\n");
321
322 fmt = dc_debug_fmt_scope_end(fmt);
323 dc_debug_fmt_print(fmt, stream, "}\n");
324}
325
326#undef INVARIANT_CHECK
327#undef ITEM_VECTORS
328#undef ITEM_DEBUG
329#undef ITEM_CLONE
330#undef ITEM_DELETE
331#undef ITEM
332
334
static void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:62
#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 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
ALLOC alloc_t
Definition template.h:61
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
static ITEM pop_front(SELF *self)
Definition template.h:216
static ITEM * try_write_from_back(SELF *self, size_t index)
Definition template.h:281
#define ITEM_DELETE
Definition template.h:20
static ITEM pop_back(SELF *self)
Definition template.h:235
static ITEM * try_write_from_front(SELF *self, size_t index)
Definition template.h:277
static void push_back(SELF *self, ITEM item)
Definition template.h:184
#define ITEM_CLONE
Definition template.h:22
static ITEM const * try_read_from_back(SELF const *self, size_t index)
Definition template.h:265
static ITEM const * try_read_from_front(SELF const *self, size_t index)
Definition template.h:255
#define ITEM_DEBUG
Definition template.h:24
static void push_front(SELF *self, ITEM item)
Definition template.h:198
#define ITEM_VECTORS
Definition template.h:44
static SELF new_with_capacity(size_t front_and_back_capacity, ALLOC *alloc)
Definition template.h:78
static void rebalance(SELF *self)
Definition template.h:107
#define DC_TRAIT_QUEUE(SELF)
Definition trait.h:5
static ITEM * push(SELF *self, ITEM item)
Definition template.h:216
static ITEM pop(SELF *self)
Definition template.h:266
static void transfer_reverse(SELF *source, SELF *target, size_t to_move)
Definition template.h:323
dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
Definition fmt.h:39
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_ASSUME(expr,...)
Definition panic.h:56
static bool dc_deque_rebalance_policy(size_t total_size, size_t front_size)
Definition utils.h:6
#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
SELF const * deque
Definition template.h:260
mutation_version version
Definition template.h:404
mutation_version version
Definition template.h:326
SELF * deque
Definition template.h:213
size_t pos
Definition template.h:214
mutation_tracker iterator_invalidation_tracker
Definition template.h:85
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: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