data-structures-c
Loading...
Searching...
No Matches
fqueue.h
Go to the documentation of this file.
1/* fqueue.h
2 *
3 * Copyright (C) 2023 abxh
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 * See the file LICENSE included with this distribution for more
10 * information. */
11
21// macro definitions: {{{
22
23#ifndef FQUEUE_H
24#define FQUEUE_H
25
26#include "is_pow2.h" // is_pow2
27#include "paste.h" // PASTE, XPASTE, JOIN
28#include "round_up_pow2.h" // round_up_pow2_32
29
30#include <assert.h>
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34
45#define fqueue_for_each(self, index, value) \
46 for ((index) = 0; (index) < (self)->count \
47 && ((value) = (self)->values[((self)->begin_index + (index)) & ((self)->capacity - 1)], true); \
48 (index)++)
49
60#define fqueue_for_each_reverse(self, index, value) \
61 for ((index) = 0; (index) < (self)->count \
62 && ((value) = (self)->values[((self)->end_index - 1 - (index)) & ((self)->capacity - 1)], true); \
63 (index)++)
64
75#define fqueue_calc_sizeof(fqueue_name, capacity) \
76 (uint32_t)(offsetof(struct fqueue_name, values) + capacity * sizeof(((struct fqueue_name *)0)->values[0]))
77
88#define fqueue_calc_sizeof_overflows(fqueue_name, capacity) \
89 (capacity > (UINT32_MAX - offsetof(struct fqueue_name, values)) / sizeof(((struct fqueue_name *)0)->values[0]))
90
91#endif // FQUEUE_H
92
100#ifndef NAME
101#define NAME fqueue
102#error "Must define NAME."
103#else
104#define FQUEUE_NAME NAME
105#endif
106
114#ifndef VALUE_TYPE
115#define VALUE_TYPE int
116#error "Must define VALUE_TYPE."
117#endif
118
120#define FQUEUE_TYPE struct FQUEUE_NAME
121#define FQUEUE_CALC_SIZEOF JOIN(FQUEUE_NAME, calc_sizeof)
122#define FQUEUE_INIT JOIN(FQUEUE_NAME, init)
123#define FQUEUE_IS_EMPTY JOIN(FQUEUE_NAME, is_empty)
124#define FQUEUE_IS_FULL JOIN(FQUEUE_NAME, is_full)
126
127// }}}
128
129// type definitions: {{{
130
134struct FQUEUE_NAME {
135 uint32_t begin_index;
136 uint32_t end_index;
137 uint32_t count;
138 uint32_t capacity;
139 VALUE_TYPE values[];
140};
141
142// }}}
143
144// function definitions: {{{
145
152static inline FQUEUE_TYPE *JOIN(FQUEUE_NAME, init)(FQUEUE_TYPE *self, const uint32_t pow2_capacity)
153{
154 assert(self);
155 assert(is_pow2(pow2_capacity));
156
157 self->begin_index = self->end_index = 0;
158 self->count = 0;
159 self->capacity = pow2_capacity;
160
161 return self;
162}
163
174static inline FQUEUE_TYPE *JOIN(FQUEUE_NAME, create)(const uint32_t min_capacity)
175{
176 if (min_capacity == 0 || min_capacity > UINT32_MAX / 2 + 1) {
177 return NULL;
178 }
179
180 const uint32_t capacity = round_up_pow2_32(min_capacity);
181
182 if (fqueue_calc_sizeof_overflows(FQUEUE_NAME, capacity)) {
183 return NULL;
184 }
185
186 const uint32_t size = fqueue_calc_sizeof(FQUEUE_NAME, capacity);
187
188 FQUEUE_TYPE *self = (FQUEUE_TYPE *)calloc(1, size);
189
190 if (!self) {
191 return NULL;
192 }
193
194 FQUEUE_INIT(self, capacity);
195
196 return self;
197}
198
206static inline void JOIN(FQUEUE_NAME, destroy)(FQUEUE_TYPE *self)
207{
208 assert(self != NULL);
209
210 free(self);
211}
212
220static inline bool JOIN(FQUEUE_NAME, is_empty)(const FQUEUE_TYPE *self)
221{
222 assert(self != NULL);
223
224 return self->count == 0;
225}
226
234static inline bool JOIN(FQUEUE_NAME, is_full)(const FQUEUE_TYPE *self)
235{
236 assert(self != NULL);
237
238 return self->count == self->capacity;
239}
240
252static inline VALUE_TYPE JOIN(FQUEUE_NAME, at)(const FQUEUE_TYPE *self, const uint32_t index)
253{
254 assert(self != NULL);
255 assert(index < self->count);
256
257 const uint32_t index_mask = (self->capacity - 1);
258
259 return self->values[(self->begin_index + index) & index_mask];
260}
261
269static inline VALUE_TYPE JOIN(FQUEUE_NAME, get_front)(const FQUEUE_TYPE *self)
270{
271 assert(self != NULL);
272 assert(!FQUEUE_IS_EMPTY(self));
273
274 return self->values[self->begin_index];
275}
276
284static inline VALUE_TYPE JOIN(FQUEUE_NAME, get_back)(const FQUEUE_TYPE *self)
285{
286 assert(self != NULL);
287 assert(!FQUEUE_IS_EMPTY(self));
288
289 const uint32_t index_mask = (self->capacity - 1);
290
291 return self->values[(self->end_index - 1) & index_mask];
292}
293
301static inline VALUE_TYPE JOIN(FQUEUE_NAME, peek)(const FQUEUE_TYPE *self)
302{
303 return JOIN(FQUEUE_NAME, get_front)(self);
304}
305
312static inline bool JOIN(FQUEUE_NAME, enqueue)(FQUEUE_TYPE *self, const VALUE_TYPE value)
313{
314 assert(self != NULL);
315 assert(!FQUEUE_IS_FULL(self));
316
317 const uint32_t index_mask = (self->capacity - 1);
318
319 self->values[self->end_index] = value;
320 self->end_index++;
321 self->end_index &= index_mask;
322 self->count++;
323
324 return true;
325}
326
334static inline VALUE_TYPE JOIN(FQUEUE_NAME, dequeue)(FQUEUE_TYPE *self)
335{
336 assert(self != NULL);
337 assert(!FQUEUE_IS_EMPTY(self));
338
339 const uint32_t index_mask = (self->capacity - 1);
340
341 const VALUE_TYPE value = self->values[self->begin_index];
342 self->begin_index++;
343 self->begin_index &= index_mask;
344 self->count--;
345
346 return value;
347}
348
354static inline void JOIN(FQUEUE_NAME, clear)(FQUEUE_TYPE *self)
355{
356 assert(self != NULL);
357
358 self->count = 0;
359 self->begin_index = self->end_index = 0;
360}
361
368static inline void JOIN(FQUEUE_NAME, copy)(FQUEUE_TYPE *restrict dest_ptr, const FQUEUE_TYPE *restrict src_ptr)
369{
370 assert(src_ptr != NULL);
371 assert(dest_ptr != NULL);
372 assert(src_ptr->count <= dest_ptr->capacity);
373 assert(FQUEUE_IS_EMPTY(dest_ptr));
374
375 const uint32_t src_begin_index = src_ptr->begin_index;
376 const uint32_t src_index_mask = src_ptr->capacity - 1;
377
378 for (uint32_t i = 0; i < src_ptr->count; i++) {
379 dest_ptr->values[i] = src_ptr->values[(src_begin_index + i) & src_index_mask];
380 }
381
382 dest_ptr->count = src_ptr->count;
383 dest_ptr->begin_index = 0;
384 dest_ptr->end_index = src_ptr->count;
385}
386
387// }}}
388
389// macro undefs: {{{
390
391#undef NAME
392#undef VALUE_TYPE
393
394#undef FQUEUE_NAME
395#undef FQUEUE_TYPE
396#undef FQUEUE_CALC_SIZEOF
397#undef FQUEUE_INIT
398#undef FQUEUE_IS_EMPTY
399#undef FQUEUE_IS_FULL
400
401// }}}
402
403// vim: ft=c fdm=marker
#define VALUE_TYPE
The value type. This must be manually defined before including this header file.
Definition fhashtable.h:144
#define fqueue_calc_sizeof(fqueue_name, capacity)
Calculate the size of the queue struct. No overflow checks.
Definition fqueue.h:75
#define fqueue_calc_sizeof_overflows(fqueue_name, capacity)
Check for a given capacity, if the equivalent size of the queue struct overflows.
Definition fqueue.h:88
#define VALUE_TYPE
Queue value type. This must be manually defined before including this header file.
Definition fqueue.h:115
Check if a number is a power of two.
static size_t is_pow2(const size_t x)
Check if a number is a power of two.
Definition is_pow2.h:34
C preprocessor macros for pasting tokens together.
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition paste.h:35
Round up to the next power of two.
static uint32_t round_up_pow2_32(uint32_t x)
Definition round_up_pow2.h:39
uint32_t count
Number of values.
Definition fqueue.h:137
uint32_t end_index
Index used to track the back of the queue.
Definition fqueue.h:136
uint32_t begin_index
Index used to track the front of the queue.
Definition fqueue.h:135
uint32_t capacity
Maximum number of values allocated for.
Definition fqueue.h:138