data-structures-c
Loading...
Searching...
No Matches
fpqueue.h
Go to the documentation of this file.
1/* fpqueue.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
24// macro definitions: {{{
25
26#ifndef FPQUEUE_H
27#define FPQUEUE_H
28
29#include "paste.h" // PASTE, XPASTE, JOIN
30
31#include <assert.h>
32#include <stdbool.h>
33#include <stddef.h>
34#include <stdint.h>
35#include <stdlib.h>
36
43#define fpqueue_left_child(index) (2 * (index) + 1)
44
51#define fpqueue_right_child(index) (2 * (index) + 2)
52
59#define fpqueue_parent(index) (((index) - 1) / 2)
60
72#define fpqueue_for_each(self, index, value_) \
73 for ((index) = 0; (index) < (self)->count && ((value_) = (self)->elements[(index)].value, true); (index)++)
74
85#define fpqueue_calc_sizeof(fpqueue_name, capacity) \
86 (uint32_t)(offsetof(struct fpqueue_name, elements) + capacity * sizeof(((struct fpqueue_name *)0)->elements[0]))
87
98#define fpqueue_calc_sizeof_overflows(fpqueue_name, capacity) \
99 (capacity \
100 > (UINT32_MAX - offsetof(struct fpqueue_name, elements)) / sizeof(((struct fpqueue_name *)0)->elements[0]))
101
102#endif // FPQUEUE_H
103
111#ifndef NAME
112#define NAME fpqueue
113#error "Must define NAME."
114#else
115#define FPQUEUE_NAME NAME
116#endif
117
125#ifndef VALUE_TYPE
126#error "Must declare VALUE_TYPE."
127#define VALUE_TYPE int
128#endif
129
131#define FPQUEUE_TYPE struct FPQUEUE_NAME
132#define FPQUEUE_ELEMENT_TYPE struct JOIN(FPQUEUE_NAME, element)
133#define FPQUEUE_INIT JOIN(FPQUEUE_NAME, init)
134#define FPQUEUE_IS_EMPTY JOIN(FPQUEUE_NAME, is_empty)
135#define FPQUEUE_IS_FULL JOIN(FPQUEUE_NAME, is_full)
136#define FPQUEUE_CALC_SIZEOF JOIN(FPQUEUE_NAME, calc_sizeof)
137#define FPQUEUE_UPHEAP JOIN(internal, JOIN(FPQUEUE_NAME, upheap))
138#define FPQUEUE_DOWNHEAP JOIN(internal, JOIN(FPQUEUE_NAME, downheap))
140
141// }}}
142
143// type definitions: {{{
144
148struct JOIN(FPQUEUE_NAME, element) {
149 uint32_t priority;
151};
152
156struct FPQUEUE_NAME {
157 uint32_t count;
158 uint32_t capacity;
159 FPQUEUE_ELEMENT_TYPE elements[];
160};
161
162// }}}
163
164// function definitions: {{{
165
167
168/* push a node down the heap. for restoring the heap property after insertion */
169static inline void JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(FPQUEUE_TYPE *self, const uint32_t index);
170
171/* push a node up the heap. for restoring the heap property after deletion */
172static inline void JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(FPQUEUE_TYPE *self, uint32_t index);
173
175
182static inline FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, init)(FPQUEUE_TYPE *self, const uint32_t capacity)
183{
184 assert(self);
185
186 self->count = 0;
187 self->capacity = capacity;
188
189 return self;
190}
191
202static inline FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, create)(const uint32_t capacity)
203{
204 if (capacity == 0 || fpqueue_calc_sizeof_overflows(FPQUEUE_NAME, capacity)) {
205 return NULL;
206 }
207
208 const uint32_t size = fpqueue_calc_sizeof(FPQUEUE_NAME, capacity);
209
210 FPQUEUE_TYPE *self = (FPQUEUE_TYPE *)calloc(1, size);
211
212 if (!self) {
213 return NULL;
214 }
215
216 FPQUEUE_INIT(self, capacity);
217
218 return self;
219}
220
228static inline void JOIN(FPQUEUE_NAME, destroy)(FPQUEUE_TYPE *self)
229{
230 assert(self != NULL);
231
232 free(self);
233}
234
242static inline bool JOIN(FPQUEUE_NAME, is_empty)(const FPQUEUE_TYPE *self)
243{
244 assert(self != NULL);
245
246 return self->count == 0;
247}
248
256static inline bool JOIN(FPQUEUE_NAME, is_full)(const FPQUEUE_TYPE *self)
257{
258 assert(self != NULL);
259
260 return self->count == self->capacity;
261}
262
270static inline VALUE_TYPE JOIN(FPQUEUE_NAME, get_max)(const FPQUEUE_TYPE *self)
271{
272 assert(self != NULL);
273 assert(FPQUEUE_IS_EMPTY(self) == false);
274
275 return self->elements[0].value;
276}
277
286static inline VALUE_TYPE JOIN(FPQUEUE_NAME, peek)(const FPQUEUE_TYPE *self)
287{
288 return JOIN(FPQUEUE_NAME, get_max)(self);
289}
290
298static inline VALUE_TYPE JOIN(FPQUEUE_NAME, pop_max)(FPQUEUE_TYPE *self)
299{
300 assert(self != NULL);
301 assert(FPQUEUE_IS_EMPTY(self) == false);
302
303 VALUE_TYPE max_priority_value = self->elements[0].value;
304
305 self->elements[0] = self->elements[self->count - 1];
306
307 self->count--;
308
309 JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(self, 0);
310
311 return max_priority_value;
312}
313
322static inline void JOIN(FPQUEUE_NAME, push)(FPQUEUE_TYPE *self, VALUE_TYPE value, uint32_t priority)
323{
324 assert(self != NULL);
325 assert(FPQUEUE_IS_FULL(self) == false);
326
327 const uint32_t index = self->count;
328
329 self->elements[index] = (FPQUEUE_ELEMENT_TYPE){.priority = priority, .value = value};
330
331 self->count++;
332
333 JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(self, index);
334}
335
341static inline void JOIN(FPQUEUE_NAME, clear)(FPQUEUE_TYPE *self)
342{
343 assert(self != NULL);
344
345 self->count = 0;
346}
347
355static inline void JOIN(FPQUEUE_NAME, copy)(FPQUEUE_TYPE *restrict dest_ptr, const FPQUEUE_TYPE *restrict src_ptr)
356{
357 assert(src_ptr != NULL);
358 assert(dest_ptr != NULL);
359 assert(src_ptr->count <= dest_ptr->capacity);
360 assert(FPQUEUE_IS_EMPTY(dest_ptr));
361
362 for (uint32_t i = 0; i < src_ptr->count; i++) {
363 dest_ptr->elements[i] = src_ptr->elements[i];
364 }
365 dest_ptr->count = src_ptr->count;
366}
367
369
370static inline void JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(FPQUEUE_TYPE *self, uint32_t index)
371{
372 assert(self != NULL);
373 assert(index < self->count);
374
375 uint32_t parent;
376 while (index > 0) {
377 parent = fpqueue_parent(index);
378
379 const bool sorted = self->elements[parent].priority >= self->elements[index].priority;
380
381 if (sorted) {
382 break;
383 }
384
385 const FPQUEUE_ELEMENT_TYPE temp = self->elements[index];
386 self->elements[index] = self->elements[parent];
387 self->elements[parent] = temp;
388
389 index = parent;
390 }
391}
392
393static inline void JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(FPQUEUE_TYPE *self, const uint32_t index)
394{
395 assert(self != NULL);
396 assert(self->count == 0 || index < self->count);
397
398 const uint32_t l = fpqueue_left_child(index);
399 const uint32_t r = fpqueue_right_child(index);
400
401 uint32_t largest = index;
402 if (l < self->count && self->elements[l].priority > self->elements[index].priority) {
403 largest = l;
404 }
405 if (r < self->count && self->elements[r].priority > self->elements[largest].priority) {
406 largest = r;
407 }
408
409 if (largest == index) {
410 return;
411 }
412
413 const FPQUEUE_ELEMENT_TYPE temp = self->elements[index];
414 self->elements[index] = self->elements[largest];
415 self->elements[largest] = temp;
416
417 JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(self, largest);
418}
420
421// }}}
422
423// macro undefs: {{{
424
425#undef NAME
426#undef VALUE_TYPE
427
428#undef FPQUEUE_NAME
429#undef FPQUEUE_TYPE
430#undef FPQUEUE_ELEMENT_TYPE
431#undef FPQUEUE_INIT
432#undef FPQUEUE_IS_EMPTY
433#undef FPQUEUE_IS_FULL
434#undef FPQUEUE_CALC_SIZEOF
435#undef FHASHTABLE_UPHEAP
436#undef FHASHTABLE_DOWNHEAP
437
438// }}}
439
440// 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 fpqueue_calc_sizeof(fpqueue_name, capacity)
Calculate the size of the pqueue struct. No overflow checks.
Definition fpqueue.h:85
#define fpqueue_parent(index)
Given an element index, get the index of the parent.
Definition fpqueue.h:59
#define fpqueue_calc_sizeof_overflows(fpqueue_name, capacity)
Check for a given capacity, if the equivalent size of the pqueue struct overflows.
Definition fpqueue.h:98
#define fpqueue_left_child(index)
Given an element index, get the index of the left child.
Definition fpqueue.h:43
#define fpqueue_right_child(index)
Given an element index, get the index of the right child.
Definition fpqueue.h:51
#define VALUE_TYPE
Priority queue value type. This must be manually defined before including this header file.
Definition fpqueue.h:127
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
uint32_t priority
Element priority (highest is next to-be-popped).
Definition fpqueue.h:149
VALUE_TYPE value
Element value member.
Definition fpqueue.h:150
uint32_t capacity
Number of elements allocated for.
Definition fpqueue.h:158
uint32_t count
Number of non-empty elements.
Definition fpqueue.h:157