dsa-c
 
Loading...
Searching...
No Matches
fqueue_template.h
Go to the documentation of this file.
1
5
10
11#ifdef __cplusplus
12#ifdef __GNUC__
13#define restrict __restrict__
14#else
15#define restrict
16#endif
17extern "C" {
18#endif
19
20#include <assert.h>
21#include <stdbool.h>
22#include <stddef.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.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#define NAME fqueue
137#error "Must define NAME."
138#else
139#define FQUEUE_NAME NAME
140#endif
141
149#ifndef VALUE_TYPE
150#define VALUE_TYPE int
151#define FUNCTION_DEFINITIONS
152#define TYPE_DEFINITIONS
153#error "Must define VALUE_TYPE."
154#endif
155
160#ifndef FUNCTION_LINKAGE
161#define FUNCTION_LINKAGE
162#endif
163
165#define FQUEUE_TYPE struct FQUEUE_NAME
166#define FQUEUE_INIT JOIN(FQUEUE_NAME, init)
167#define FQUEUE_IS_EMPTY JOIN(FQUEUE_NAME, is_empty)
168#define FQUEUE_IS_FULL JOIN(FQUEUE_NAME, is_full)
170
171// }}}
172
173// type definitions: {{{
174
179#ifdef TYPE_DEFINITIONS
180
184struct FQUEUE_NAME {
185 uint32_t begin_index;
186 uint32_t end_index;
187 uint32_t count;
188 uint32_t capacity;
190};
191
192#endif
193
194// }}}
195
196// function declarations: {{{
197
204FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, init)(FQUEUE_TYPE *self, const uint32_t pow2_capacity);
205
216FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, create)(const uint32_t min_capacity);
217
225FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, destroy)(FQUEUE_TYPE *self);
226
234FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_empty)(const FQUEUE_TYPE *self);
235
243FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_full)(const FQUEUE_TYPE *self);
244
256FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, at)(const FQUEUE_TYPE *self, const uint32_t index);
257
265FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_front)(const FQUEUE_TYPE *self);
266
274FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_back)(const FQUEUE_TYPE *self);
275
283FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, peek)(const FQUEUE_TYPE *self);
284
291FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, enqueue)(FQUEUE_TYPE *self, const VALUE_TYPE value);
292
300FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, dequeue)(FQUEUE_TYPE *self);
301
307FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, clear)(FQUEUE_TYPE *self);
308
315FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, copy)(FQUEUE_TYPE *restrict dest_ptr, const FQUEUE_TYPE *restrict src_ptr);
316
317// }}}
318
319// function definitions: {{{
320
325#ifdef FUNCTION_DEFINITIONS
326
327#include "round_up_pow2_32.h" // round_up_pow2_32
328
329FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, init)(FQUEUE_TYPE *self, const uint32_t pow2_capacity)
330{
331 assert(self);
332 assert(IS_POW2(pow2_capacity));
333
334 self->begin_index = self->end_index = 0;
335 self->count = 0;
336 self->capacity = pow2_capacity;
337
338 return self;
339}
340
341FUNCTION_LINKAGE FQUEUE_TYPE *JOIN(FQUEUE_NAME, create)(const uint32_t min_capacity)
342{
343 if (min_capacity == 0 || min_capacity > UINT32_MAX / 2 + 1) {
344 return NULL;
345 }
346
347 const uint32_t capacity = round_up_pow2_32(min_capacity);
348
349 if (FQUEUE_CALC_SIZEOF_OVERFLOWS(FQUEUE_NAME, capacity)) {
350 return NULL;
351 }
352
353 const uint32_t size = FQUEUE_CALC_SIZEOF(FQUEUE_NAME, capacity);
354
355 FQUEUE_TYPE *self = (FQUEUE_TYPE *)calloc(1, size);
356
357 if (!self) {
358 return NULL;
359 }
360
361 FQUEUE_INIT(self, capacity);
362
363 return self;
364}
365
366FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, destroy)(FQUEUE_TYPE *self)
367{
368 assert(self != NULL);
369
370 free(self);
371}
372
373FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_empty)(const FQUEUE_TYPE *self)
374{
375 assert(self != NULL);
376
377 return self->count == 0;
378}
379
380FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, is_full)(const FQUEUE_TYPE *self)
381{
382 assert(self != NULL);
383
384 return self->count == self->capacity;
385}
386
387FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, at)(const FQUEUE_TYPE *self, const uint32_t index)
388{
389 assert(self != NULL);
390 assert(index < self->count);
391
392 const uint32_t index_mask = (self->capacity - 1);
393
394 return self->values[(self->begin_index + index) & index_mask];
395}
396
397FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_front)(const FQUEUE_TYPE *self)
398{
399 assert(self != NULL);
400 assert(!FQUEUE_IS_EMPTY(self));
401
402 return self->values[self->begin_index];
403}
404
405FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, get_back)(const FQUEUE_TYPE *self)
406{
407 assert(self != NULL);
408 assert(!FQUEUE_IS_EMPTY(self));
409
410 const uint32_t index_mask = (self->capacity - 1);
411
412 return self->values[(self->end_index - 1) & index_mask];
413}
414
415FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, peek)(const FQUEUE_TYPE *self)
416{
417 return JOIN(FQUEUE_NAME, get_front)(self);
418}
419
420FUNCTION_LINKAGE bool JOIN(FQUEUE_NAME, enqueue)(FQUEUE_TYPE *self, const VALUE_TYPE value)
421{
422 assert(self != NULL);
423 assert(!FQUEUE_IS_FULL(self));
424
425 const uint32_t index_mask = (self->capacity - 1);
426
427 self->values[self->end_index] = value;
428 self->end_index++;
429 self->end_index &= index_mask;
430 self->count++;
431
432 return true;
433}
434
435FUNCTION_LINKAGE VALUE_TYPE JOIN(FQUEUE_NAME, dequeue)(FQUEUE_TYPE *self)
436{
437 assert(self != NULL);
438 assert(!FQUEUE_IS_EMPTY(self));
439
440 const uint32_t index_mask = (self->capacity - 1);
441
442 const VALUE_TYPE value = self->values[self->begin_index];
443 self->begin_index++;
444 self->begin_index &= index_mask;
445 self->count--;
446
447 return value;
448}
449
450FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, clear)(FQUEUE_TYPE *self)
451{
452 assert(self != NULL);
453
454 self->count = 0;
455 self->begin_index = self->end_index = 0;
456}
457
458FUNCTION_LINKAGE void JOIN(FQUEUE_NAME, copy)(FQUEUE_TYPE *restrict dest_ptr, const FQUEUE_TYPE *restrict src_ptr)
459{
460 assert(src_ptr != NULL);
461 assert(dest_ptr != NULL);
462 assert(src_ptr->count <= dest_ptr->capacity);
463 assert(FQUEUE_IS_EMPTY(dest_ptr));
464
465 const uint32_t src_begin_index = src_ptr->begin_index;
466 const uint32_t src_index_mask = src_ptr->capacity - 1;
467
468 for (uint32_t i = 0; i < src_ptr->count; i++) {
469 dest_ptr->values[i] = src_ptr->values[(src_begin_index + i) & src_index_mask];
470 }
471
472 dest_ptr->count = src_ptr->count;
473 dest_ptr->begin_index = 0;
474 dest_ptr->end_index = src_ptr->count;
475}
476
477#endif
478
479// }}}
480
481// macro undefs: {{{
482
483#undef NAME
484#undef VALUE_TYPE
485#undef FUNCTION_LINKAGE
486#undef FUNCTION_DEFINITIONS
487#undef TYPE_DEFINITIONS
488
489#undef FQUEUE_NAME
490#undef FQUEUE_TYPE
491#undef FQUEUE_CALC_SIZEOF
492#undef FQUEUE_INIT
493#undef FQUEUE_IS_EMPTY
494#undef FQUEUE_IS_FULL
495
496// }}}
497
498#ifdef __cplusplus
499}
500#endif
501
502// 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:150
#define FUNCTION_LINKAGE
Specify function linkage e.g. static inline.
Definition fstack_template.h:146
#define VALUE_TYPE
Stack value type. This must be manually defined before including this header file.
Definition fstack_template.h:135
uint32_t count
Number of values.
Definition fqueue_template.h:187
uint32_t end_index
Index used to track the back of the queue.
Definition fqueue_template.h:186
VALUE_TYPE values[]
Array of values.
Definition fqueue_template.h:189
uint32_t begin_index
Index used to track the front of the queue.
Definition fqueue_template.h:185
uint32_t capacity
Maximum number of values allocated for.
Definition fqueue_template.h:188