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
11#include <derive-c/core/panic.h>
12
15
16#if !defined ITEM
17 #if !defined __clang_analyzer__
18 #error "The contained type must be defined for a deque template"
19 #endif
20
21typedef struct {
22 int x;
23} item_t;
24 #define ITEM item_t
25
26static void item_delete(item_t* UNUSED(a)) {}
27 #define ITEM_DELETE item_delete
28static item_t item_clone(item_t const* a) { return *a; }
29 #define ITEM_CLONE item_clone
30#endif
31
32#if !defined ITEM_DELETE
33 #define ITEM_DELETE(value)
34#endif
35
36#if !defined ITEM_CLONE
37 #define ITEM_CLONE(value) (*(value))
38#endif
39
40#define ITEM_VECTORS NS(NAME, item_vectors)
41
42#pragma push_macro("ALLOC")
43#pragma push_macro("ITEM")
44#pragma push_macro("ITEM_CLONE")
45#pragma push_macro("ITEM_DELETE")
46
47// ITEM is already defined
48#define INTERNAL_NAME ITEM_VECTORS
50
51#pragma pop_macro("ALLOC")
52#pragma pop_macro("ITEM")
53#pragma pop_macro("ITEM_CLONE")
54#pragma pop_macro("ITEM_DELETE")
55
56typedef struct {
59 ALLOC* alloc;
61} SELF;
62
63static SELF NS(SELF, new)(ALLOC* alloc) {
64 return (SELF){.front = NS(ITEM_VECTORS, new)(alloc),
65 .back = NS(ITEM_VECTORS, new)(alloc),
66 .alloc = alloc,
67 .derive_c_deque = (gdb_marker){}};
68}
69
70static SELF NS(SELF, new_with_capacity)(size_t front_and_back_capacity, ALLOC* alloc) {
71 return (SELF){.front = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc),
72 .back = NS(ITEM_VECTORS, new_with_capacity)(front_and_back_capacity, alloc),
73 .alloc = alloc,
74 .derive_c_deque = (gdb_marker){}};
75}
76
77static SELF NS(SELF, clone)(SELF const* other) {
78 DEBUG_ASSERT(other);
79 return (SELF){.front = NS(ITEM_VECTORS, clone)(&other->front),
80 .back = NS(ITEM_VECTORS, clone)(&other->back),
81 .alloc = other->alloc,
82 .derive_c_deque = (gdb_marker){}};
83}
84
85static void NS(SELF, rebalance)(SELF* self) {
86 DEBUG_ASSERT(self);
87
88 size_t front_size = NS(ITEM_VECTORS, size)(&self->front);
89 size_t back_size = NS(ITEM_VECTORS, size)(&self->back);
90 size_t total_size = front_size + back_size;
91
92 if (!deque_rebalance_policy(total_size, front_size)) {
93 return;
94 }
95
96 ITEM_VECTORS* source;
97 ITEM_VECTORS* target;
98 size_t source_size;
99 size_t target_size;
100
101 if (front_size > back_size + 1) {
102 source = &self->front;
103 target = &self->back;
104 source_size = front_size;
105 target_size = back_size;
106 } else {
107 DEBUG_ASSERT(back_size > front_size + 1)
108 source = &self->back;
109 target = &self->front;
110 source_size = back_size;
111 target_size = front_size;
112 }
113
114 size_t to_move = (source_size - target_size) / 2;
115
116 NS(ITEM_VECTORS, reserve)(target, target_size + to_move);
117
118 ITEM* source_data = NS(ITEM_VECTORS, data)(source);
119 ITEM* target_data = NS(ITEM_VECTORS, data)(target);
120
121 memmove(&target_data[to_move], target_data, target_size * sizeof(ITEM));
122
123 for (size_t i = 0; i < to_move; i++) {
124 target_data[to_move - 1 - i] = source_data[i];
125 }
126
127 memmove(source_data, &source_data[to_move], (source_size - to_move) * sizeof(ITEM));
128
129 target->size += to_move;
130 source->size -= to_move;
131}
132
133static ITEM const* NS(SELF, peek_front_read)(SELF const* self) {
134 DEBUG_ASSERT(self);
135
136 size_t front_size = NS(ITEM_VECTORS, size)(&self->front);
137 if (front_size > 0) {
138 return NS(ITEM_VECTORS, read)(&self->front, front_size - 1);
139 }
140
141 return NS(ITEM_VECTORS, try_read)(&self->back, 0);
142}
143
144static ITEM* NS(SELF, peek_front_write)(SELF* self) {
145 DEBUG_ASSERT(self);
146
147 size_t front_size = NS(ITEM_VECTORS, size)(&self->front);
148 if (front_size > 0) {
149 return NS(ITEM_VECTORS, write)(&self->front, front_size - 1);
150 }
151
152 return NS(ITEM_VECTORS, try_write)(&self->back, 0);
153}
154
155static ITEM const* NS(SELF, peek_back_read)(SELF const* self) {
156 DEBUG_ASSERT(self);
157
158 size_t back_size = NS(ITEM_VECTORS, size)(&self->back);
159 if (back_size > 0) {
160 return NS(ITEM_VECTORS, read)(&self->back, back_size - 1);
161 }
162
163 return NS(ITEM_VECTORS, try_read)(&self->front, 0);
164}
165
166static ITEM* NS(SELF, peek_back_write)(SELF* self) {
167 DEBUG_ASSERT(self);
168
169 size_t back_size = NS(ITEM_VECTORS, size)(&self->back);
170 if (back_size > 0) {
171 return NS(ITEM_VECTORS, write)(&self->back, back_size - 1);
172 }
173
174 return NS(ITEM_VECTORS, try_write)(&self->front, 0);
175}
176
177static void NS(SELF, push_front)(SELF* self, ITEM item) {
178 DEBUG_ASSERT(self);
179 NS(ITEM_VECTORS, push)(&self->front, item);
180 NS(SELF, rebalance)(self);
181}
182
183static void NS(SELF, push_back)(SELF* self, ITEM item) {
184 DEBUG_ASSERT(self);
185 NS(ITEM_VECTORS, push)(&self->back, item);
186 NS(SELF, rebalance)(self);
187}
188
189static ITEM NS(SELF, pop_front)(SELF* self) {
190 DEBUG_ASSERT(self);
191 if (NS(ITEM_VECTORS, size)(&self->front) > 0) {
192 ITEM result = NS(ITEM_VECTORS, pop)(&self->front);
193 NS(SELF, rebalance)(self);
194 return result;
195 }
196
197 ITEM result = NS(ITEM_VECTORS, pop_front)(&self->back);
198 NS(SELF, rebalance)(self);
199 return result;
200}
201
202static ITEM NS(SELF, pop_back)(SELF* self) {
203 DEBUG_ASSERT(self);
204 if (NS(ITEM_VECTORS, size)(&self->back) > 0) {
205 ITEM result = NS(ITEM_VECTORS, pop)(&self->back);
206 NS(SELF, rebalance)(self);
207 return result;
208 }
209
210 ITEM result = NS(ITEM_VECTORS, pop_front)(&self->front);
211 NS(SELF, rebalance)(self);
212 return result;
213}
214
215static size_t NS(SELF, size)(SELF const* self) {
216 DEBUG_ASSERT(self);
217 return NS(ITEM_VECTORS, size)(&self->front) + NS(ITEM_VECTORS, size)(&self->back);
218}
219
220static bool NS(SELF, empty)(SELF const* self) {
221 DEBUG_ASSERT(self);
222 return NS(ITEM_VECTORS, size)(&self->front) == 0 && NS(ITEM_VECTORS, size)(&self->back) == 0;
223}
224
225#define ITER NS(SELF, iter)
226
227typedef struct {
228 SELF* deque;
229 size_t pos;
230} ITER;
231
232static ITEM* NS(ITER, next)(ITER* iter) {
233 DEBUG_ASSERT(iter);
234 size_t front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
235 size_t back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
236 size_t total_size = front_size + back_size;
237
238 if (iter->pos < total_size) {
239 ITEM* item;
240 if (iter->pos < front_size) {
241 item = NS(ITEM_VECTORS, write)(&iter->deque->front, front_size - 1 - iter->pos);
242 } else {
243 item = NS(ITEM_VECTORS, write)(&iter->deque->back, iter->pos - front_size);
244 }
245 iter->pos++;
246 return item;
247 }
248 return NULL;
249}
250
251static bool NS(ITER, empty)(ITER const* iter) {
252 DEBUG_ASSERT(iter);
253 return iter->pos >=
254 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
255}
256
257static ITER NS(SELF, get_iter)(SELF* self) {
258 DEBUG_ASSERT(self);
259 return (ITER){
260 .deque = self,
261 .pos = 0,
262 };
263}
264
265#undef ITER
266
267#define ITER_CONST NS(SELF, iter_const)
268
269typedef struct {
270 SELF const* deque;
271 size_t pos;
272} ITER_CONST;
273
274static ITEM const* NS(ITER_CONST, next)(ITER_CONST* iter) {
275 DEBUG_ASSERT(iter);
276 size_t front_size = NS(ITEM_VECTORS, size)(&iter->deque->front);
277 size_t back_size = NS(ITEM_VECTORS, size)(&iter->deque->back);
278 size_t total_size = front_size + back_size;
279
280 if (iter->pos < total_size) {
281 ITEM const* item;
282 if (iter->pos < front_size) {
283 item = NS(ITEM_VECTORS, read)(&iter->deque->front, front_size - 1 - iter->pos);
284 } else {
285 item = NS(ITEM_VECTORS, read)(&iter->deque->back, iter->pos - front_size);
286 }
287 iter->pos++;
288 return item;
289 }
290 return NULL;
291}
292
293static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
294 DEBUG_ASSERT(iter);
295 return iter->pos >=
296 NS(ITEM_VECTORS, size)(&iter->deque->front) + NS(ITEM_VECTORS, size)(&iter->deque->back);
297}
298
299static ITER_CONST NS(SELF, get_iter_const)(SELF const* self) {
300 DEBUG_ASSERT(self);
301 return (ITER_CONST){
302 .deque = self,
303 .pos = 0,
304 };
305}
306
307#undef ITER_CONST
308
309static void NS(SELF, delete)(SELF* self) {
310 DEBUG_ASSERT(self);
311 NS(ITEM_VECTORS, delete)(&self->front);
312 NS(ITEM_VECTORS, delete)(&self->back);
313}
314
#define ALLOC
Definition template.h:56
#define ITEM
Definition template.h:55
static bool deque_rebalance_policy(size_t total_size, size_t front_size)
Definition utils.h:6
#define UNUSED(ident)
Definition helpers.h:16
#define NS(pre, post)
Definition helpers.h:6
#define DEBUG_ASSERT(expr)
Definition panic.h:34
#define SELF
Definition def.h:51
gdb_marker derive_c_deque
Definition template.h:60
ITEM_VECTORS back
Definition template.h:58
ITEM_VECTORS front
Definition template.h:57
ALLOC * alloc
Definition template.h:63
A queue comprised of an extendable circular buffer.
Definition template.h:19
static ITER_CONST get_iter_const(SELF const *self)
Definition template.h:387
static bool empty(ITER const *iter)
Definition template.h:293
static ITER get_iter(SELF *self)
Definition template.h:318
static INDEX_TYPE size(SELF const *self)
Definition template.h:220
static IV_PAIR const * next(ITER *iter)
Definition template.h:301
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:159
static VALUE const * read(SELF const *self, INDEX index)
Definition template.h:189
static VALUE * write(SELF *self, INDEX index)
Definition template.h:171
static SELF clone(SELF const *self)
Definition template.h:195
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:177
static ITEM pop_front(SELF *self)
Definition template.h:161
static ITEM pop_back(SELF *self)
Definition template.h:174
static void reserve(SELF *self, size_t new_capacity_for)
Definition template.h:97
static void push_back(SELF *self, ITEM item)
Definition template.h:135
static void item_delete(item_t *UNUSED(self))
Definition template.h:23
static item_t item_clone(item_t const *self)
Definition template.h:25
static void push_front(SELF *self, ITEM item)
Definition template.h:146
static ITEM const * peek_front_read(SELF const *self)
Definition template.h:133
#define ITEM_VECTORS
Definition template.h:40
static SELF new_with_capacity(size_t front_and_back_capacity, ALLOC *alloc)
Definition template.h:70
static ITEM * peek_front_write(SELF *self)
Definition template.h:144
static ITEM * peek_back_write(SELF *self)
Definition template.h:166
static void rebalance(SELF *self)
Definition template.h:85
static ITEM const * peek_back_read(SELF const *self)
Definition template.h:155
static ITEM * push(SELF *self, ITEM item)
Definition template.h:140
static ITEM pop(SELF *self)
Definition template.h:156
static ITEM * data(SELF *self)
Definition template.h:215