data-structures-c
Loading...
Searching...
No Matches
fqueue_template.h
Go to the documentation of this file.
1// Copyright (c) 2026 abxh
2// SPDX-License-Identifier: MIT
3
8
13
14#ifdef __cplusplus
15#ifdef __GNUC__
16#define restrict __restrict__
17#else
18#define restrict
19#endif
20extern "C" {
21#endif
22
23#include <stdbool.h>
24#include <stddef.h>
25#include <stdint.h>
26
27// macro definitions: {{{
28
33#ifndef PASTE
34#define PASTE(a, b) a##b
35#endif
36
41#ifndef XPASTE
42#define XPASTE(a, b) PASTE(a, b)
43#endif
44
49#ifndef JOIN
50#define JOIN(a, b) XPASTE(a, XPASTE(_, b))
51#endif
52
60#ifndef IS_POW2
61#define IS_POW2(X) ((X) != 0 && ((X) & ((X) - 1)) == 0)
62#endif
63
74#ifndef FQUEUE_FOR_EACH
75#define FQUEUE_FOR_EACH(self, index, value) \
76 for ((index) = 0; (index) < (self)->count \
77 && ((value) = (self)->values[((self)->begin_index + (index)) & ((self)->capacity - 1)], true); \
78 (index)++)
79#endif
80
91#ifndef FQUEUE_FOR_EACH_REVERSE
92#define FQUEUE_FOR_EACH_REVERSE(self, index, value) \
93 for ((index) = 0; (index) < (self)->count \
94 && ((value) = (self)->values[((self)->end_index - 1 - (index)) & ((self)->capacity - 1)], true); \
95 (index)++)
96#endif
97
108#ifndef FQUEUE_CALC_SIZEOF
109#define FQUEUE_CALC_SIZEOF(fqueue_name, capacity) \
110 (uint32_t)(offsetof(struct fqueue_name, values) + capacity * sizeof(((struct fqueue_name *)0)->values[0]))
111#endif
112
123#ifndef FQUEUE_CALC_SIZEOF_OVERFLOWS
124#define FQUEUE_CALC_SIZEOF_OVERFLOWS(fqueue_name, capacity) \
125 (capacity > (UINT32_MAX - offsetof(struct fqueue_name, values)) / sizeof(((struct fqueue_name *)0)->values[0]))
126#endif
127
135#ifndef NAME
136#error "Must define NAME."
137#define FUNCTION_DEFINITIONS
138#define TYPE_DEFINITIONS
139#else
140#define FQUEUE_NAME NAME
141#endif
142
150#ifndef VALUE_TYPE
151#define VALUE_TYPE int
152#error "Must define VALUE_TYPE."
153#endif
154
159#ifndef FUNCTION_LINKAGE
160#define FUNCTION_LINKAGE
161#endif
162
164#define FQUEUE_TYPE struct FQUEUE_NAME
165#define FQUEUE_INIT JOIN(FQUEUE_NAME, init)
166#define FQUEUE_IS_EMPTY JOIN(FQUEUE_NAME, is_empty)
167#define FQUEUE_IS_FULL JOIN(FQUEUE_NAME, is_full)
169
170// }}}
171
172// type definitions: {{{
173
174struct FQUEUE_NAME;
175
180#ifdef TYPE_DEFINITIONS
181
185struct FQUEUE_NAME {
186 uint32_t begin_index;
187 uint32_t end_index;
188 uint32_t count;
189 uint32_t capacity;
191};
192
193#endif
194
195// }}}
196
197// function declarations: {{{
198
205FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, init)(FQUEUE_TYPE *self, const uint32_t pow2_capacity);
206
219FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME,
220 create_custom)(const uint32_t min_capacity, void *context_ptr,
221 void *(*allocate)(void *context_ptr, size_t alignment, size_t size));
222
233FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, create)(const uint32_t min_capacity);
234
244FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, destroy_custom)(FQUEUE_TYPE *self, void *context_ptr,
245 void (*deallocate)(void *context_ptr, void *mem));
246
254FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, destroy)(FQUEUE_TYPE *self);
255
263FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_empty)(const FQUEUE_TYPE *self);
264
272FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_full)(const FQUEUE_TYPE *self);
273
285FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, at)(const FQUEUE_TYPE *self, const uint32_t index);
286
294FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_front)(const FQUEUE_TYPE *self);
295
303FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_back)(const FQUEUE_TYPE *self);
304
312FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, peek)(const FQUEUE_TYPE *self);
313
320FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, enqueue)(FQUEUE_TYPE *self, const VALUE_TYPE value);
321
329FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, dequeue)(FQUEUE_TYPE *self);
330
336FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, clear)(FQUEUE_TYPE *self);
337
344FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, copy)(FQUEUE_TYPE *restrict dest_ptr, const FQUEUE_TYPE *restrict src_ptr);
345
346// }}}
347
348// function definitions: {{{
349
354#ifdef FUNCTION_DEFINITIONS
355
356#include <assert.h>
357#include <stdalign.h>
358#include <stdlib.h>
359#include <string.h>
360
361#include "round_up_pow2_32.h" // round_up_pow2_32
362
363FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, init)(FQUEUE_TYPE *self, const uint32_t pow2_capacity)
364{
365 assert(self);
366 assert(IS_POW2(pow2_capacity));
367
368 self->begin_index = self->end_index = 0;
369 self->count = 0;
370 self->capacity = pow2_capacity;
371
372 return self;
373}
374
375FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME,
376 create_custom)(const uint32_t min_capacity, void *context_ptr,
377 void *(*allocate)(void *context_ptr, size_t alignment, size_t size))
378{
379 if (min_capacity == 0 || min_capacity > UINT32_MAX / 2 + 1) {
380 return NULL;
381 }
382
383 const uint32_t capacity = round_up_pow2_32(min_capacity);
384
385 if (FQUEUE_CALC_SIZEOF_OVERFLOWS(FQUEUE_NAME, capacity)) {
386 return NULL;
387 }
388
389 const uint32_t size = FQUEUE_CALC_SIZEOF(FQUEUE_NAME, capacity);
390
391 FQUEUE_TYPE *self = (FQUEUE_TYPE *)allocate(context_ptr, alignof(FQUEUE_TYPE), size);
392
393 if (!self) {
394 return NULL;
395 }
396
397 memset(self, 0, size);
398 FQUEUE_INIT(self, capacity);
399
400 return self;
401}
402
404static inline void *JOIN(internal, JOIN(FQUEUE_NAME, allocate))(void *context_ptr, size_t alignment, size_t size)
405{
406 (void)context_ptr;
407 (void)alignment;
408 return malloc(size);
409}
411
412FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, create)(const uint32_t capacity)
413{
414 return JOIN(FQUEUE_NAME, create_custom)(capacity, NULL, JOIN(internal, JOIN(FQUEUE_NAME, allocate)));
415}
416
417FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, destroy_custom)(FQUEUE_TYPE *self, void *context_ptr,
418 void (*deallocate)(void *context_ptr, void *mem))
419{
420 assert(self != NULL);
421
422 deallocate(context_ptr, self);
423}
424
426static inline void JOIN(internal, JOIN(FQUEUE_NAME, deallocate))(void *context_ptr, void *mem)
427{
428 (void)context_ptr;
429 free(mem);
430}
432
433FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, destroy)(FQUEUE_TYPE *self)
434{
435 assert(self != NULL);
436
437 JOIN(FQUEUE_NAME, destroy_custom)(self, NULL, JOIN(internal, JOIN(FQUEUE_NAME, deallocate)));
438}
439
440FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_empty)(const FQUEUE_TYPE *self)
441{
442 assert(self != NULL);
443
444 return self->count == 0;
445}
446
447FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_full)(const FQUEUE_TYPE *self)
448{
449 assert(self != NULL);
450
451 return self->count == self->capacity;
452}
453
454FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, at)(const FQUEUE_TYPE *self, const uint32_t index)
455{
456 assert(self != NULL);
457 assert(index < self->count);
458
459 const uint32_t index_mask = (self->capacity - 1);
460
461 return self->values[(self->begin_index + index) & index_mask];
462}
463
464FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_front)(const FQUEUE_TYPE *self)
465{
466 assert(self != NULL);
467 assert(!FQUEUE_IS_EMPTY(self));
468
469 return self->values[self->begin_index];
470}
471
472FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_back)(const FQUEUE_TYPE *self)
473{
474 assert(self != NULL);
475 assert(!FQUEUE_IS_EMPTY(self));
476
477 const uint32_t index_mask = (self->capacity - 1);
478
479 return self->values[(self->end_index - 1) & index_mask];
480}
481
482FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, peek)(const FQUEUE_TYPE *self)
483{
484 return JOIN(FQUEUE_NAME, get_front)(self);
485}
486
487FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, enqueue)(FQUEUE_TYPE *self, const VALUE_TYPE value)
488{
489 assert(self != NULL);
490 assert(!FQUEUE_IS_FULL(self));
491
492 const uint32_t index_mask = (self->capacity - 1);
493
494 self->values[self->end_index] = value;
495 self->end_index++;
496 self->end_index &= index_mask;
497 self->count++;
498
499 return true;
500}
501
502FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, dequeue)(FQUEUE_TYPE *self)
503{
504 assert(self != NULL);
505 assert(!FQUEUE_IS_EMPTY(self));
506
507 const uint32_t index_mask = (self->capacity - 1);
508
509 const VALUE_TYPE value = self->values[self->begin_index];
510 self->begin_index++;
511 self->begin_index &= index_mask;
512 self->count--;
513
514 return value;
515}
516
517FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, clear)(FQUEUE_TYPE *self)
518{
519 assert(self != NULL);
520
521 self->count = 0;
522 self->begin_index = self->end_index = 0;
523}
524
525FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, copy)(FQUEUE_TYPE *restrict dest_ptr, const FQUEUE_TYPE *restrict src_ptr)
526{
527 assert(src_ptr != NULL);
528 assert(dest_ptr != NULL);
529 assert(src_ptr->count <= dest_ptr->capacity);
530 assert(FQUEUE_IS_EMPTY(dest_ptr));
531
532 const uint32_t src_begin_index = src_ptr->begin_index;
533 const uint32_t src_index_mask = src_ptr->capacity - 1;
534
535 for (uint32_t i = 0; i < src_ptr->count; i++) {
536 dest_ptr->values[i] = src_ptr->values[(src_begin_index + i) & src_index_mask];
537 }
538
539 dest_ptr->count = src_ptr->count;
540 dest_ptr->begin_index = 0;
541 dest_ptr->end_index = src_ptr->count;
542}
543
544#endif
545
546// }}}
547
548// macro undefs: {{{
549
550#undef NAME
551#undef VALUE_TYPE
552#undef FUNCTION_LINKAGE
553#undef FUNCTION_DEFINITIONS
554#undef TYPE_DEFINITIONS
555
556#undef FQUEUE_NAME
557#undef FQUEUE_TYPE
558#undef FQUEUE_CALC_SIZEOF
559#undef FQUEUE_INIT
560#undef FQUEUE_IS_EMPTY
561#undef FQUEUE_IS_FULL
562
563// }}}
564
565#ifdef __cplusplus
566}
567#endif
568
569// vim: ft=c fdm=marker
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fqueue_template.h:50
#define IS_POW2(X)
Macro to check if a number is a power of two.
Definition fqueue_template.h:61
#define FQUEUE_CALC_SIZEOF(fqueue_name, capacity)
Calculate the size of the queue struct. No overflow checks.
Definition fqueue_template.h:109
#define FQUEUE_CALC_SIZEOF_OVERFLOWS(fqueue_name, capacity)
Check for a given capacity, if the equivalent size of the queue struct overflows.
Definition fqueue_template.h:124
#define VALUE_TYPE
Queue value type. This must be manually defined before including this header file.
Definition fqueue_template.h:151
#define FUNCTION_LINKAGE
Specify function linkage e.g. static inline.
Definition fstack_template.h:145
#define VALUE_TYPE
Stack value type. This must be manually defined before including this header file.
Definition fstack_template.h:136
uint32_t count
Number of values.
Definition fqueue_template.h:188
uint32_t end_index
Index used to track the back of the queue.
Definition fqueue_template.h:187
VALUE_TYPE values[]
Array of values.
Definition fqueue_template.h:190
uint32_t begin_index
Index used to track the front of the queue.
Definition fqueue_template.h:186
uint32_t capacity
Maximum number of values allocated for.
Definition fqueue_template.h:189