data-structures-c
Loading...
Searching...
No Matches
fpqueue_template.h
Go to the documentation of this file.
1// Copyright (c) 2026 abxh
2// SPDX-License-Identifier: MIT
3
15
20
21#ifdef __cplusplus
22#ifdef __GNUC__
23#define restrict __restrict__
24#else
25#define restrict
26#endif
27extern "C" {
28#endif
29
30#include <stdbool.h>
31#include <stddef.h>
32#include <stdint.h>
33
34// macro definitions: {{{
35
40#ifndef PASTE
41#define PASTE(a, b) a##b
42#endif
43
48#ifndef XPASTE
49#define XPASTE(a, b) PASTE(a, b)
50#endif
51
56#ifndef JOIN
57#define JOIN(a, b) XPASTE(a, XPASTE(_, b))
58#endif
59
66#ifndef FPQUEUE_LEFT_CHILD
67#define FPQUEUE_LEFT_CHILD(index) (2 * (index) + 1)
68#endif
69
76#ifndef FPQUEUE_RIGHT_CHILD
77#define FPQUEUE_RIGHT_CHILD(index) (2 * (index) + 2)
78#endif
79
86#ifndef FPQUEUE_PARENT
87#define FPQUEUE_PARENT(index) (((index) - 1) / 2)
88#endif
89
101#ifndef FPQUEUE_FOR_EACH
102#define FPQUEUE_FOR_EACH(self, index, value_) \
103 for ((index) = 0; (index) < (self)->count && ((value_) = (self)->elements[(index)].value, true); (index)++)
104#endif
105
116#ifndef FPQUEUE_CALC_SIZEOF
117#define FPQUEUE_CALC_SIZEOF(fpqueue_name, capacity) \
118 (uint32_t)(offsetof(struct fpqueue_name, elements) + capacity * sizeof(((struct fpqueue_name *)0)->elements[0]))
119#endif
120
131#ifndef FPQUEUE_CALC_SIZEOF_OVERFLOWS
132#define FPQUEUE_CALC_SIZEOF_OVERFLOWS(fpqueue_name, capacity) \
133 (capacity \
134 > (UINT32_MAX - offsetof(struct fpqueue_name, elements)) / sizeof(((struct fpqueue_name *)0)->elements[0]))
135#endif
136
144#ifndef NAME
145#error "Must define NAME."
146#else
147#define FPQUEUE_NAME NAME
148#endif
149
157#ifndef VALUE_TYPE
158#define VALUE_TYPE int
159#define FUNCTION_DEFINITIONS
160#define TYPE_DEFINITIONS
161#error "Must declare VALUE_TYPE."
162#endif
163
168#ifndef FUNCTION_LINKAGE
169#define FUNCTION_LINKAGE
170#endif
171
173#define FPQUEUE_TYPE struct FPQUEUE_NAME
174#define FPQUEUE_ELEMENT_TYPE struct JOIN(FPQUEUE_NAME, element)
175#define FPQUEUE_INIT JOIN(FPQUEUE_NAME, init)
176#define FPQUEUE_IS_EMPTY JOIN(FPQUEUE_NAME, is_empty)
177#define FPQUEUE_IS_FULL JOIN(FPQUEUE_NAME, is_full)
178#define FPQUEUE_UPHEAP JOIN(internal, JOIN(FPQUEUE_NAME, upheap))
179#define FPQUEUE_DOWNHEAP JOIN(internal, JOIN(FPQUEUE_NAME, downheap))
181
182// }}}
183
184// type definitions: {{{
185
186struct JOIN(FPQUEUE_NAME, element);
187struct FPQUEUE_NAME;
188
193#ifdef TYPE_DEFINITIONS
194
198struct JOIN(FPQUEUE_NAME, element) {
199 uint32_t priority;
201};
202
206struct FPQUEUE_NAME {
207 uint32_t count;
208 uint32_t capacity;
209 FPQUEUE_ELEMENT_TYPE elements[];
210};
211
212#endif
213
214// }}}
215
216// function declarations: {{{
217
224FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, init)(FPQUEUE_TYPE *self, const uint32_t capacity);
225
238FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME,
239 create_custom)(const uint32_t capacity, void *context_ptr,
240 void *(*allocate)(void *context_ptr, size_t alignment, size_t size));
241
252FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, create)(const uint32_t capacity);
253
263FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, destroy_custom)(FPQUEUE_TYPE *self, void *context_ptr,
264 void (*deallocate)(void *context_ptr, void *mem));
265
273FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, destroy)(FPQUEUE_TYPE *self);
274
282FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_empty)(const FPQUEUE_TYPE *self);
283
291FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_full)(const FPQUEUE_TYPE *self);
292
300FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, get_max)(const FPQUEUE_TYPE *self);
301
310FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, peek)(const FPQUEUE_TYPE *self);
311
319FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, pop_max)(FPQUEUE_TYPE *self);
320
329FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, push)(FPQUEUE_TYPE *self, VALUE_TYPE value, const uint32_t priority);
330
339FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, push)(FPQUEUE_TYPE *self, VALUE_TYPE value, const uint32_t priority);
340
346FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, clear)(FPQUEUE_TYPE *self);
347
355FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, copy)(FPQUEUE_TYPE *restrict dest_ptr, const FPQUEUE_TYPE *restrict src_ptr);
356
357// @}}}
358
359// function definitions: {{{
360
365#ifdef FUNCTION_DEFINITIONS
366
367#include <assert.h>
368#include <stdalign.h>
369#include <stdlib.h>
370#include <string.h>
371
373
374/* push a node down the heap. for restoring the heap property after insertion */
375static inline void JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(FPQUEUE_TYPE *self, const uint32_t index);
376
377/* push a node up the heap. for restoring the heap property after deletion */
378static inline void JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(FPQUEUE_TYPE *self, uint32_t index);
379
381
382FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, init)(FPQUEUE_TYPE *self, const uint32_t capacity)
383{
384 assert(self);
385
386 self->count = 0;
387 self->capacity = capacity;
388
389 return self;
390}
391
392FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME,
393 create_custom)(const uint32_t capacity, void *context_ptr,
394 void *(*allocate)(void *context_ptr, size_t alignment, size_t size))
395{
396 if (capacity == 0 || FPQUEUE_CALC_SIZEOF_OVERFLOWS(FPQUEUE_NAME, capacity)) {
397 return NULL;
398 }
399
400 const uint32_t size = FPQUEUE_CALC_SIZEOF(FPQUEUE_NAME, capacity);
401
402 FPQUEUE_TYPE *self = (FPQUEUE_TYPE *)allocate(context_ptr, alignof(FPQUEUE_TYPE), size);
403
404 if (!self) {
405 return NULL;
406 }
407
408 memset(self, 0, size);
409 FPQUEUE_INIT(self, capacity);
410
411 return self;
412}
413
415static inline void *JOIN(internal, JOIN(FPQUEUE_NAME, allocate))(void *context_ptr, size_t alignment, size_t size)
416{
417 (void)context_ptr;
418 (void)alignment;
419 return malloc(size);
420}
422
423FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, create)(const uint32_t capacity)
424{
425 return JOIN(FPQUEUE_NAME, create_custom)(capacity, NULL, JOIN(internal, JOIN(FPQUEUE_NAME, allocate)));
426}
427
428FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, destroy_custom)(FPQUEUE_TYPE *self, void *context_ptr,
429 void (*deallocate)(void *context_ptr, void *mem))
430{
431 assert(self != NULL);
432
433 deallocate(context_ptr, self);
434}
435
437static inline void JOIN(internal, JOIN(FPQUEUE_NAME, deallocate))(void *context_ptr, void *mem)
438{
439 (void)context_ptr;
440 free(mem);
441}
443
444FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, destroy)(FPQUEUE_TYPE *self)
445{
446 assert(self != NULL);
447
448 JOIN(FPQUEUE_NAME, destroy_custom)(self, NULL, JOIN(internal, JOIN(FPQUEUE_NAME, deallocate)));
449}
450
451FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_empty)(const FPQUEUE_TYPE *self)
452{
453 assert(self != NULL);
454
455 return self->count == 0;
456}
457
458FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_full)(const FPQUEUE_TYPE *self)
459{
460 assert(self != NULL);
461
462 return self->count == self->capacity;
463}
464
465FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, get_max)(const FPQUEUE_TYPE *self)
466{
467 assert(self != NULL);
468 assert(FPQUEUE_IS_EMPTY(self) == false);
469
470 return self->elements[0].value;
471}
472
473FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, peek)(const FPQUEUE_TYPE *self)
474{
475 return JOIN(FPQUEUE_NAME, get_max)(self);
476}
477
478FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, pop_max)(FPQUEUE_TYPE *self)
479{
480 assert(self != NULL);
481 assert(FPQUEUE_IS_EMPTY(self) == false);
482
483 VALUE_TYPE max_priority_value = self->elements[0].value;
484
485 self->elements[0] = self->elements[self->count - 1];
486
487 self->count--;
488
489 JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(self, 0);
490
491 return max_priority_value;
492}
493
494FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, push)(FPQUEUE_TYPE *self, VALUE_TYPE value, const uint32_t priority)
495{
496 assert(self != NULL);
497 assert(FPQUEUE_IS_FULL(self) == false);
498
499 const uint32_t index = self->count;
500
501 self->elements[index] = (FPQUEUE_ELEMENT_TYPE){.priority = priority, .value = value};
502
503 self->count++;
504
505 JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(self, index);
506}
507
508FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, clear)(FPQUEUE_TYPE *self)
509{
510 assert(self != NULL);
511
512 self->count = 0;
513}
514
515FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, copy)(FPQUEUE_TYPE *restrict dest_ptr, const FPQUEUE_TYPE *restrict src_ptr)
516{
517 assert(src_ptr != NULL);
518 assert(dest_ptr != NULL);
519 assert(src_ptr->count <= dest_ptr->capacity);
520 assert(FPQUEUE_IS_EMPTY(dest_ptr));
521
522 for (uint32_t i = 0; i < src_ptr->count; i++) {
523 dest_ptr->elements[i] = src_ptr->elements[i];
524 }
525 dest_ptr->count = src_ptr->count;
526}
527
529
530static inline void JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(FPQUEUE_TYPE *self, uint32_t index)
531{
532 assert(self != NULL);
533 assert(index < self->count);
534
535 uint32_t parent;
536 while (index > 0) {
537 parent = FPQUEUE_PARENT(index);
538
539 const bool sorted = self->elements[parent].priority >= self->elements[index].priority;
540
541 if (sorted) {
542 break;
543 }
544
545 const FPQUEUE_ELEMENT_TYPE temp = self->elements[index];
546 self->elements[index] = self->elements[parent];
547 self->elements[parent] = temp;
548
549 index = parent;
550 }
551}
552
553static inline void JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(FPQUEUE_TYPE *self, const uint32_t index)
554{
555 assert(self != NULL);
556 assert(self->count == 0 || index < self->count);
557
558 const uint32_t l = FPQUEUE_LEFT_CHILD(index);
559 const uint32_t r = FPQUEUE_RIGHT_CHILD(index);
560
561 uint32_t largest = index;
562 if (l < self->count && self->elements[l].priority > self->elements[index].priority) {
563 largest = l;
564 }
565 if (r < self->count && self->elements[r].priority > self->elements[largest].priority) {
566 largest = r;
567 }
568
569 if (largest == index) {
570 return;
571 }
572
573 const FPQUEUE_ELEMENT_TYPE temp = self->elements[index];
574 self->elements[index] = self->elements[largest];
575 self->elements[largest] = temp;
576
577 JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(self, largest);
578}
580
581#endif
582
583// }}}
584
585// macro undefs: {{{
586
587#undef NAME
588#undef VALUE_TYPE
589#undef FUNCTION_LINKAGE
590#undef FUNCTION_DEFINITIONS
591#undef TYPE_DEFINITIONS
592
593#undef FPQUEUE_NAME
594#undef FPQUEUE_TYPE
595#undef FPQUEUE_ELEMENT_TYPE
596#undef FPQUEUE_INIT
597#undef FPQUEUE_IS_EMPTY
598#undef FPQUEUE_IS_FULL
599#undef FPQUEUE_CALC_SIZEOF
600#undef FHASHTABLE_UPHEAP
601#undef FHASHTABLE_DOWNHEAP
602
603// }}}
604
605#ifdef __cplusplus
606}
607#endif
608
609// vim: ft=c fdm=marker
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fpqueue_template.h:57
#define FPQUEUE_RIGHT_CHILD(index)
Given an element index, get the index of the right child.
Definition fpqueue_template.h:77
#define FPQUEUE_CALC_SIZEOF(fpqueue_name, capacity)
Calculate the size of the pqueue struct. No overflow checks.
Definition fpqueue_template.h:117
#define FPQUEUE_LEFT_CHILD(index)
Given an element index, get the index of the left child.
Definition fpqueue_template.h:67
#define FPQUEUE_PARENT(index)
Given an element index, get the index of the parent.
Definition fpqueue_template.h:87
#define VALUE_TYPE
Priority queue value type. This must be manually defined before including this header file.
Definition fpqueue_template.h:158
#define FPQUEUE_CALC_SIZEOF_OVERFLOWS(fpqueue_name, capacity)
Check for a given capacity, if the equivalent size of the pqueue struct overflows.
Definition fpqueue_template.h:132
#define FUNCTION_LINKAGE
Specify function linkage e.g. static inline.
Definition fstack_template.h:146
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fstack_template.h:50
#define VALUE_TYPE
Stack value type. This must be manually defined before including this header file.
Definition fstack_template.h:135
uint32_t priority
Element priority (highest is next to-be-popped).
Definition fpqueue_template.h:199
VALUE_TYPE value
Element value member.
Definition fpqueue_template.h:200
uint32_t capacity
Number of elements allocated for.
Definition fpqueue_template.h:208
fpqueue_element_type elements[]
Array of elements.
Definition fpqueue_template.h:209
uint32_t count
Number of non-empty elements.
Definition fpqueue_template.h:207