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 <stdlib.h>
7#include <string.h>
8
10#include <derive-c/core/panic.h>
11
14
15#if !defined ITEM
16 #if !defined __clang_analyzer__
17 #error "The contained type must be defined for a vector template"
18 #endif
19typedef struct {
20 int x;
21} item_t;
22 #define ITEM item_t
23static void item_delete(item_t* UNUSED(t)) {}
24 #define ITEM_DELETE item_delete
25static item_t item_clone(item_t const* i) { return *i; }
26 #define ITEM_CLONE item_clone
27#endif
28
29#if !defined ITEM_DELETE
30 #define ITEM_DELETE(value)
31#endif
32
33#if !defined ITEM_CLONE
34 #define ITEM_CLONE(value) (*(value))
35#endif
36
37typedef struct {
38 size_t size;
39 size_t capacity;
40 ITEM* data;
41 ALLOC* alloc;
43} SELF;
44
45static SELF NS(SELF, new)(ALLOC* alloc) {
46 SELF temp = (SELF){
47 .size = 0,
48 .capacity = 0,
49 .data = NULL,
50 .alloc = alloc,
51 };
52 return temp;
53}
54
55static SELF NS(SELF, new_with_capacity)(size_t capacity, ALLOC* alloc) {
56 if (capacity == 0) {
57 return NS(SELF, new)(alloc);
58 }
59
60 ITEM* data = (ITEM*)NS(ALLOC, malloc)(alloc, capacity * sizeof(ITEM));
62 return (SELF){
63 .size = 0,
64 .capacity = capacity,
65 .data = data,
66 .alloc = alloc,
67 };
68}
69
70static SELF NS(SELF, new_with_defaults)(size_t size, ITEM default_item, ALLOC* alloc) {
71 ITEM* data = (ITEM*)NS(ALLOC, malloc)(alloc, size * sizeof(ITEM));
72 if (size > 0) {
73 // JUSTIFY: We only need to copy size-1 entries - can move the first as default.
74 data[0] = default_item;
75 for (size_t i = 1; i < size; i++) {
76 data[i] = ITEM_CLONE(&default_item);
77 }
78 }
80 return (SELF){
81 .size = size,
82 .capacity = size,
83 .data = data,
84 .alloc = alloc,
85 };
86}
87
88static void NS(SELF, reserve)(SELF* self, size_t new_capacity) {
89 DEBUG_ASSERT(self);
90 if (new_capacity > self->capacity) {
91 ITEM* new_data =
92 (ITEM*)NS(ALLOC, realloc)(self->alloc, self->data, new_capacity * sizeof(ITEM));
93 ASSERT(new_data);
94 self->data = new_data;
95 self->capacity = new_capacity;
96 }
97}
98
99static SELF NS(SELF, clone)(SELF const* self) {
100 DEBUG_ASSERT(self);
101 ITEM* data = (ITEM*)NS(ALLOC, malloc)(self->alloc, self->capacity * sizeof(ITEM));
102 ASSERT(data);
103 for (size_t index = 0; index < self->size; index++) {
104 data[index] = ITEM_CLONE(&self->data[index]);
105 }
106 return (SELF){
107 .size = self->size,
108 .capacity = self->capacity,
109 .data = data,
110 .alloc = self->alloc,
111 };
112}
113
114static ITEM const* NS(SELF, try_read)(SELF const* self, size_t index) {
115 DEBUG_ASSERT(self);
116 if (LIKELY(index < self->size)) {
117 return &self->data[index];
118 }
119 return NULL;
120}
121
122static ITEM const* NS(SELF, read)(SELF const* self, size_t index) {
123 ITEM const* item = NS(SELF, try_read)(self, index);
124 ASSERT(item);
125 return item;
126}
127
128static ITEM* NS(SELF, try_write)(SELF* self, size_t index) {
129 DEBUG_ASSERT(self);
130 if (LIKELY(index < self->size)) {
131 return &self->data[index];
132 }
133 return NULL;
134}
135
136static ITEM* NS(SELF, write)(SELF* self, size_t index) {
137 ITEM* item = NS(SELF, try_write)(self, index);
138 ASSERT(item);
139 return item;
140}
141
142static void NS(SELF, insert_at)(SELF* self, size_t at, ITEM const* items, size_t count) {
143 DEBUG_ASSERT(self);
144 DEBUG_ASSERT(items);
145 ASSERT(at <= self->size);
146
147 if (count == 0) {
148 return;
149 }
150
151 NS(SELF, reserve)(self, self->size + count);
152
153 memmove(&self->data[at + count], &self->data[at], (self->size - at) * sizeof(ITEM));
154 memcpy(&self->data[at], items, count * sizeof(ITEM));
155 self->size += count;
156}
157
158static void NS(SELF, remove_at)(SELF* self, size_t at, size_t count) {
159 DEBUG_ASSERT(self);
160 ASSERT(at + count <= self->size);
161
162 if (count == 0) {
163 return;
164 }
165
166 for (size_t i = at; i < at + count; i++) {
167 ITEM_DELETE(&self->data[i]);
168 }
169
170 memmove(&self->data[at], &self->data[at + count], (self->size - (at + count)) * sizeof(ITEM));
171 self->size -= count;
172}
173
174static ITEM* NS(SELF, push)(SELF* self, ITEM item) {
175 DEBUG_ASSERT(self);
176 if (self->size == self->capacity) {
177 ITEM* new_data;
178 size_t new_capacity;
179 if (self->data == NULL) {
180 DEBUG_ASSERT(self->capacity == 0);
181 // JUSTIFY: Allocating capacity of 4
182 // - Avoid repeat reallocations on growing a vector from
183 // size sero (from new)
184 // Otherwise an arbitrary choice (given we do not know the size of T)
185 new_capacity = 8;
186 new_data = (ITEM*)NS(ALLOC, malloc)(self->alloc, new_capacity * sizeof(ITEM));
187 } else {
188 // JUSTIFY: Growth factor of 2
189 // - Simple arithmetic (for debugging)
190 // - Same as used by GCC's std::vector implementation
191 new_capacity = self->capacity * 2;
192 new_data =
193 (ITEM*)NS(ALLOC, realloc)(self->alloc, self->data, new_capacity * sizeof(ITEM));
194 }
195 ASSERT(new_data);
196 self->capacity = new_capacity;
197 self->data = new_data;
198 }
199 ITEM* entry = &self->data[self->size];
200 *entry = item;
201 self->size++;
202 return entry;
203}
204
205static bool NS(SELF, try_pop)(SELF* self, ITEM* destination) {
206 DEBUG_ASSERT(self);
207 if (LIKELY(self->size > 0)) {
208 self->size--;
209 *destination = self->data[self->size];
210 return true;
211 }
212 return false;
213}
214
215static ITEM* NS(SELF, data)(SELF* self) {
216 DEBUG_ASSERT(self);
217 return self->data;
218}
219
220static ITEM NS(SELF, pop)(SELF* self) {
221 ITEM entry;
222 ASSERT(NS(SELF, try_pop)(self, &entry));
223 return entry;
224}
225
226static ITEM NS(SELF, pop_front)(SELF* self) {
227 DEBUG_ASSERT(self);
228 ASSERT(self->size > 0);
229 ITEM entry = self->data[0];
230 memmove(&self->data[0], &self->data[1], (self->size - 1) * sizeof(ITEM));
231 self->size--;
232 return entry;
233}
234
235static size_t NS(SELF, size)(SELF const* self) {
236 DEBUG_ASSERT(self);
237 return self->size;
238}
239
240static void NS(SELF, delete)(SELF* self) {
241 DEBUG_ASSERT(self);
242 if (self->data) {
243 for (size_t i = 0; i < self->size; i++) {
244 ITEM_DELETE(&self->data[i]);
245 }
246 NS(ALLOC, free)(self->alloc, self->data);
247 }
248}
249
250#define ITER NS(SELF, iter)
251
252typedef struct {
253 SELF* vec;
254 size_t pos;
255} ITER;
256
257static ITEM* NS(ITER, next)(ITER* iter) {
258 DEBUG_ASSERT(iter);
259 if (iter->pos < iter->vec->size) {
260 ITEM* item = &iter->vec->data[iter->pos];
261 iter->pos++;
262 return item;
263 }
264 return NULL;
265}
266
267static size_t NS(ITER, position)(ITER const* iter) {
268 DEBUG_ASSERT(iter);
269 return iter->pos;
270}
271
272static bool NS(ITER, empty)(ITER const* iter) {
273 DEBUG_ASSERT(iter);
274 return iter->pos >= iter->vec->size;
275}
276
277static ITER NS(SELF, get_iter)(SELF* self) {
278 DEBUG_ASSERT(self);
279 return (ITER){
280 .vec = self,
281 .pos = 0,
282 };
283}
284#undef ITER
285
286#define ITER_CONST NS(SELF, iter_const)
287
288typedef struct {
289 SELF const* vec;
290 size_t pos;
291} ITER_CONST;
292
293static ITEM const* NS(ITER_CONST, next)(ITER_CONST* iter) {
294 DEBUG_ASSERT(iter);
295 if (iter->pos < iter->vec->size) {
296 ITEM const* item = &iter->vec->data[iter->pos];
297 iter->pos++;
298 return item;
299 }
300 return NULL;
301}
302
303static size_t NS(ITER_CONST, position)(ITER_CONST const* iter) {
304 DEBUG_ASSERT(iter);
305 return iter->pos;
306}
307
308static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
309 DEBUG_ASSERT(iter);
310 return iter->pos >= iter->vec->size;
311}
312
313static ITER_CONST NS(SELF, get_iter_const)(SELF const* self) {
314 DEBUG_ASSERT(self);
315 return (ITER_CONST){
316 .vec = self,
317 .pos = 0,
318 };
319}
320
321#undef ITER_CONST
322
323#undef ITEM
324#undef ITEM_DELETE
325#undef ITEM_CLONE
326
static void free(SELF *self, void *ptr)
Definition template.h:56
static void * realloc(SELF *self, void *ptr, size_t size)
Definition template.h:45
static void * malloc(SELF *self, size_t size)
Definition template.h:23
#define ALLOC
Definition template.h:56
#define ITEM
Definition template.h:55
#define UNUSED(ident)
Definition helpers.h:16
#define NS(pre, post)
Definition helpers.h:6
#define LIKELY(x)
Definition helpers.h:18
#define ASSERT(expr,...)
Definition panic.h:15
#define DEBUG_ASSERT(expr)
Definition panic.h:34
#define SELF
Definition def.h:51
size_t capacity
Definition template.h:97
gdb_marker derive_c_vector
Definition template.h:42
ITEM * data
Definition template.h:38
INPLACE_TYPE size
Definition template.h:52
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
#define ITEM_DELETE
Definition template.h:24
static void reserve(SELF *self, size_t new_capacity_for)
Definition template.h:97
static void item_delete(item_t *UNUSED(self))
Definition template.h:23
#define ITEM_CLONE
Definition template.h:26
static item_t item_clone(item_t const *self)
Definition template.h:25
static SELF new_with_capacity(size_t front_and_back_capacity, ALLOC *alloc)
Definition template.h:70
static void remove_at(SELF *self, size_t at, size_t count)
Definition template.h:124
static ITEM * push(SELF *self, ITEM item)
Definition template.h:140
static bool try_pop(SELF *self, ITEM *destination)
Definition template.h:146
static ITEM pop(SELF *self)
Definition template.h:156
static size_t position(ITER const *iter)
Definition template.h:191
#define ITEM
Definition template.h:22
static void insert_at(SELF *self, size_t at, ITEM const *items, size_t count)
Definition template.h:142
static SELF new_with_defaults(size_t size, ITEM default_item, ALLOC *alloc)
Definition template.h:70
static ITEM * data(SELF *self)
Definition template.h:215