Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
2
3#include <stdbool.h>
4#include <stddef.h>
5#include <stdint.h>
6#include <string.h>
7
8#include "utils.h"
9
14
17
18// JUSTIFY: No custom memory tracking
19// - already done by the contained vectors
20
21#if !defined ITEM
22 #if !defined PLACEHOLDERS
23 #error "The contained type must be defined for a deque template"
24 #endif
25
26typedef struct {
27 int x;
28} item_t;
29 #define ITEM item_t
30
31static void item_delete(item_t* a) { (void)a; }
32 #define ITEM_DELETE item_delete
33static item_t item_clone(item_t const* a) { return *a; }
34 #define ITEM_CLONE item_clone
35#endif
36
37#if !defined ITEM_DELETE
38 #define ITEM_DELETE(value)
39#endif
40
41#if !defined ITEM_CLONE
42 #define ITEM_CLONE(value) (*(value))
43#endif
44
45typedef ITEM NS(SELF, item_t);
46typedef ALLOC NS(SELF, alloc_t);
47
48#define ITEM_VECTORS NS(NAME, item_vectors)
49
50#pragma push_macro("ALLOC")
51#pragma push_macro("ITEM")
52#pragma push_macro("ITEM_CLONE")
53#pragma push_macro("ITEM_DELETE")
54
55// ITEM is already defined
56#define INTERNAL_NAME ITEM_VECTORS
58
59#pragma pop_macro("ALLOC")
60#pragma pop_macro("ITEM")
61#pragma pop_macro("ITEM_CLONE")
62#pragma pop_macro("ITEM_DELETE")
63
64typedef struct {
67 ALLOC* alloc;
68 gdb_marker derive_c_deque;
70} SELF;
71
72#define INVARIANT_CHECK(self) \
73 ASSUME(self); \
74 ASSUME((self)->alloc);
75
76static SELF NS(SELF, new)(ALLOC* alloc) {
77 return (SELF){
78 .front = NS(ITEM_VECTORS, new)(alloc),
79 .back = NS(ITEM_VECTORS, new)(alloc),
80 .alloc = alloc,
81 .derive_c_deque = gdb_marker_new(),
82 .iterator_invalidation_tracker = mutation_tracker_new(),
83 };
84}
85
86static SELF NS(SELF, new_with_capacity)(size_t front_and_back_capacity, ALLOC* alloc) {
87 return (SELF){
88 .front = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc),
89 .back = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc),
90 .alloc = alloc,
91 .derive_c_deque = gdb_marker_new(),
92 .iterator_invalidation_tracker = mutation_tracker_new(),
93 };
94}
95
96static SELF NS(SELF, clone)(SELF const* other) {
97 INVARIANT_CHECK(other);
98 return (SELF){
99 .front = NS(ITEM_VECTORS, clone)(&other->front),
100 .back = NS(ITEM_VECTORS, clone)(&other->back),
101 .alloc = other->alloc,
102 .derive_c_deque = gdb_marker_new(),
103 .iterator_invalidation_tracker = mutation_tracker_new(),
104 };
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 (!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 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, peek_front_read)(SELF const* self) {
142 INVARIANT_CHECK(self);
143
144 size_t const front_size = NS(ITEM_VECTORS, size)(&self->front);
145 if (front_size > 0) {
146 return NS(ITEM_VECTORS, read)(&self->front, front_size - 1);
147 }
148
149 return NS(ITEM_VECTORS, try_read)(&self->back, 0);
150}
151
152static ITEM* NS(SELF, peek_front_write)(SELF* self) {
153 INVARIANT_CHECK(self);
154
155 size_t const front_size = NS(ITEM_VECTORS, size)(&self->front);
156 if (front_size > 0) {
157 return NS(ITEM_VECTORS, write)(&self->front, front_size - 1);
158 }
159
160 return NS(ITEM_VECTORS, try_write)(&self->back, 0);
161}
162
163static ITEM const* NS(SELF, peek_back_read)(SELF const* self) {
164 INVARIANT_CHECK(self);
165
166 size_t const back_size = NS(ITEM_VECTORS, size)(&self->back);
167 if (back_size > 0) {
168 return NS(ITEM_VECTORS, read)(&self->back, back_size - 1);
169 }
170
171 return NS(ITEM_VECTORS, try_read)(&self->front, 0);
172}
173
174static ITEM* NS(SELF, peek_back_write)(SELF* self) {
175 INVARIANT_CHECK(self);
176
177 size_t const back_size = NS(ITEM_VECTORS, size)(&self->back);
178 if (back_size > 0) {
179 return NS(ITEM_VECTORS, write)(&self->back, back_size - 1);
180 }
181
182 return NS(ITEM_VECTORS, try_write)(&self->front, 0);
183}
184
185static void NS(SELF, push_front)(SELF* self, ITEM item) {
186 INVARIANT_CHECK(self);
187 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
188 NS(ITEM_VECTORS, push)(&self->front, item);
189 NS(SELF, rebalance)(self);
190}
191
192static void NS(SELF, push_back)(SELF* self, ITEM item) {
193 INVARIANT_CHECK(self);
194 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
195 NS(ITEM_VECTORS, push)(&self->back, item);
196 NS(SELF, rebalance)(self);
197}
198
199static ITEM NS(SELF, pop_front)(SELF* self) {
200 INVARIANT_CHECK(self);
201 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
202 if (NS(ITEM_VECTORS, size)(&self->front) > 0) {
203 ITEM result = NS(ITEM_VECTORS, pop)(&self->front);
204 NS(SELF, rebalance)(self);
205 return result;
206 }
207
208 ITEM result = NS(ITEM_VECTORS, pop_front)(&self->back);
209 NS(SELF, rebalance)(self);
210 return result;
211}
212
213static ITEM NS(SELF, pop_back)(SELF* self) {
214 INVARIANT_CHECK(self);
215 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
216 if (NS(ITEM_VECTORS, size)(&self->back) > 0) {
217 ITEM result = NS(ITEM_VECTORS, pop)(&self->back);
218 NS(SELF, rebalance)(self);
219 return result;
220 }
221
222 ITEM result = NS(ITEM_VECTORS, pop_front)(&self->front);
223 NS(SELF, rebalance)(self);
224 return result;
225}
226
227static size_t NS(SELF, size)(SELF const* self) {
228 INVARIANT_CHECK(self);
229 return NS(ITEM_VECTORS, size)(&self->front) + NS(ITEM_VECTORS, size)(&self->back);
230}
231
232static bool NS(SELF, empty)(SELF const* self) {
233 INVARIANT_CHECK(self);
234 return NS(ITEM_VECTORS, size)(&self->front) == 0 && NS(ITEM_VECTORS, size)(&self->back) == 0;
235}
236
237#define ITER NS(SELF, iter)
238typedef ITEM* NS(ITER, item);
239
240static bool NS(ITER, empty_item)(ITEM* const* item) { return *item == NULL; }
241
242typedef struct {
243 SELF* deque;
244 size_t pos;
245 mutation_version version;
246} ITER;
247
248static ITEM* NS(ITER, next)(ITER* iter) {
249 ASSUME(iter);
250 mutation_version_check(&iter->version);
251 size_t const front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
252 size_t const back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
253 size_t const total_size = front_size + back_size;
254
255 if (iter->pos < total_size) {
256 ITEM* item;
257 if (iter->pos < front_size) {
258 item = NS(ITEM_VECTORS, write)(&iter->deque->front, front_size - 1 - iter->pos);
259 } else {
260 item = NS(ITEM_VECTORS, write)(&iter->deque->back, iter->pos - front_size);
261 }
262 iter->pos++;
263 return item;
264 }
265 return NULL;
266}
267
268static bool NS(ITER, empty)(ITER const* iter) {
269 mutation_version_check(&iter->version);
270 ASSUME(iter);
271 return iter->pos >=
272 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
273}
274
275static ITER NS(SELF, get_iter)(SELF* self) {
276 ASSUME(self);
277 return (ITER){.deque = self,
278 .pos = 0,
279 .version = mutation_tracker_get(&self->iterator_invalidation_tracker)};
280}
281
282#undef ITER
283
284#define ITER_CONST NS(SELF, iter_const)
285typedef ITEM const* NS(ITER_CONST, item);
286
287static bool NS(ITER_CONST, empty_item)(ITEM const* const* item) { return *item == NULL; }
288
289typedef struct {
290 SELF const* deque;
291 size_t pos;
292 mutation_version version;
293} ITER_CONST;
294
295static ITEM const* NS(ITER_CONST, next)(ITER_CONST* iter) {
296 ASSUME(iter);
297 mutation_version_check(&iter->version);
298 size_t const front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
299 size_t const back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
300 size_t const total_size = front_size + back_size;
301
302 if (iter->pos < total_size) {
303 ITEM const* item;
304 if (iter->pos < front_size) {
305 item = NS(ITEM_VECTORS, read)(&iter->deque->front, front_size - 1 - iter->pos);
306 } else {
307 item = NS(ITEM_VECTORS, read)(&iter->deque->back, iter->pos - front_size);
308 }
309 iter->pos++;
310 return item;
311 }
312 return NULL;
313}
314
315static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
316 ASSUME(iter);
317 mutation_version_check(&iter->version);
318 return iter->pos >=
319 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
320}
321
322static ITER_CONST NS(SELF, get_iter_const)(SELF const* self) {
323 ASSUME(self);
324 return (ITER_CONST){
325 .deque = self,
326 .pos = 0,
327 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
328 };
329}
330
331#undef ITER_CONST
332
333static void NS(SELF, delete)(SELF* self) {
334 INVARIANT_CHECK(self);
335 NS(ITEM_VECTORS, delete)(&self->front);
336 NS(ITEM_VECTORS, delete)(&self->back);
337}
338
339#undef INVARIANT_CHECK
340
343
#define ALLOC
Definition template.h:59
#define ITEM
Definition template.h:58
static bool empty_item(IV_PAIR const *const *item)
Definition template.h:352
static ITER_CONST get_iter_const(SELF const *self)
Definition template.h:465
IV_PAIR const * item
Definition template.h:350
static bool empty(ITER const *iter)
Definition template.h:361
static ITER get_iter(SELF *self)
Definition template.h:388
static INDEX_TYPE size(SELF const *self)
Definition template.h:275
static IV_PAIR const * next(ITER *iter)
Definition template.h:370
#define INVARIANT_CHECK(self)
Definition template.h:142
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:210
ALLOC alloc_t
Definition template.h:85
static VALUE const * read(SELF const *self, INDEX index)
Definition template.h:240
static VALUE * write(SELF *self, INDEX index)
Definition template.h:222
static SELF clone(SELF const *self)
Definition template.h:246
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:228
static ITEM pop_front(SELF *self)
Definition template.h:216
static ITEM pop_back(SELF *self)
Definition template.h:235
static void push_back(SELF *self, ITEM item)
Definition template.h:184
static void item_delete(item_t *self)
Definition template.h:26
static item_t item_clone(item_t const *self)
Definition template.h:28
static void push_front(SELF *self, ITEM item)
Definition template.h:198
static ITEM const * peek_front_read(SELF const *self)
Definition template.h:141
#define ITEM_VECTORS
Definition template.h:48
static SELF new_with_capacity(size_t front_and_back_capacity, ALLOC *alloc)
Definition template.h:86
static ITEM * peek_front_write(SELF *self)
Definition template.h:152
static ITEM * peek_back_write(SELF *self)
Definition template.h:174
static void rebalance(SELF *self)
Definition template.h:107
static ITEM const * peek_back_read(SELF const *self)
Definition template.h:163
#define TRAIT_QUEUE(SELF)
Definition trait.h:6
static ITEM * push(SELF *self, ITEM item)
Definition template.h:214
static ITEM pop(SELF *self)
Definition template.h:264
static void transfer_reverse(SELF *source, SELF *target, size_t to_move)
Definition template.h:321
static gdb_marker gdb_marker_new()
Definition gdb_marker.h:7
#define ASSUME(expr,...)
Definition macros.h:62
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 NS(pre, post)
Definition namespace.h:4
static bool deque_rebalance_policy(size_t total_size, size_t front_size)
Definition utils.h:6
#define SELF
Definition def.h:52
mutation_tracker iterator_invalidation_tracker
Definition template.h:139
gdb_marker derive_c_deque
Definition template.h:68
ITEM_VECTORS back
Definition template.h:66
ITEM_VECTORS front
Definition template.h:65
ALLOC * alloc
Definition template.h:66
A queue comprised of an extendable circular buffer.
Definition template.h:22
tracks a specific version of a value, so that this can be compared later to check modification For ex...