dsa-c
 
Loading...
Searching...
No Matches
fpqueue_template.h
Go to the documentation of this file.
1
12
17
18#ifdef __cplusplus
19#ifdef __GNUC__
20#define restrict __restrict__
21#else
22#define restrict
23#endif
24extern "C" {
25#endif
26
27#include <assert.h>
28#include <stdbool.h>
29#include <stddef.h>
30#include <stdint.h>
31#include <stdlib.h>
32
33// macro definitions: {{{
34
39#ifndef PASTE
40#define PASTE(a, b) a##b
41#endif
42
47#ifndef XPASTE
48#define XPASTE(a, b) PASTE(a, b)
49#endif
50
55#ifndef JOIN
56#define JOIN(a, b) XPASTE(a, XPASTE(_, b))
57#endif
58
65#ifndef FPQUEUE_LEFT_CHILD
66#define FPQUEUE_LEFT_CHILD(index) (2 * (index) + 1)
67#endif
68
75#ifndef FPQUEUE_RIGHT_CHILD
76#define FPQUEUE_RIGHT_CHILD(index) (2 * (index) + 2)
77#endif
78
85#ifndef FPQUEUE_PARENT
86#define FPQUEUE_PARENT(index) (((index) - 1) / 2)
87#endif
88
100#ifndef FPQUEUE_FOR_EACH
101#define FPQUEUE_FOR_EACH(self, index, value_) \
102 for ((index) = 0; (index) < (self)->count && ((value_) = (self)->elements[(index)].value, true); (index)++)
103#endif
104
115#ifndef FPQUEUE_CALC_SIZEOF
116#define FPQUEUE_CALC_SIZEOF(fpqueue_name, capacity) \
117 (uint32_t)(offsetof(struct fpqueue_name, elements) + capacity * sizeof(((struct fpqueue_name *)0)->elements[0]))
118#endif
119
130#ifndef FPQUEUE_CALC_SIZEOF_OVERFLOWS
131#define FPQUEUE_CALC_SIZEOF_OVERFLOWS(fpqueue_name, capacity) \
132 (capacity \
133 > (UINT32_MAX - offsetof(struct fpqueue_name, elements)) / sizeof(((struct fpqueue_name *)0)->elements[0]))
134#endif
135
143#ifndef NAME
144#error "Must define NAME."
145#else
146#define FPQUEUE_NAME NAME
147#endif
148
156#ifndef VALUE_TYPE
157#define VALUE_TYPE int
158#define FUNCTION_DEFINITIONS
159#define TYPE_DEFINITIONS
160#error "Must declare VALUE_TYPE."
161#endif
162
167#ifndef FUNCTION_LINKAGE
168#define FUNCTION_LINKAGE
169#endif
170
172#define FPQUEUE_TYPE struct FPQUEUE_NAME
173#define FPQUEUE_ELEMENT_TYPE struct JOIN(FPQUEUE_NAME, element)
174#define FPQUEUE_INIT JOIN(FPQUEUE_NAME, init)
175#define FPQUEUE_IS_EMPTY JOIN(FPQUEUE_NAME, is_empty)
176#define FPQUEUE_IS_FULL JOIN(FPQUEUE_NAME, is_full)
177#define FPQUEUE_UPHEAP JOIN(internal, JOIN(FPQUEUE_NAME, upheap))
178#define FPQUEUE_DOWNHEAP JOIN(internal, JOIN(FPQUEUE_NAME, downheap))
180
181// }}}
182
183// type definitions: {{{
184
189#ifdef TYPE_DEFINITIONS
190
194struct JOIN(FPQUEUE_NAME, element) {
195 uint32_t priority;
197};
198
202struct FPQUEUE_NAME {
203 uint32_t count;
204 uint32_t capacity;
205 FPQUEUE_ELEMENT_TYPE elements[];
206};
207
208#endif
209
210// }}}
211
212// function declarations: {{{
213
220FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, init)(FPQUEUE_TYPE *self, const uint32_t capacity);
221
232FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, create)(const uint32_t capacity);
233
241FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, destroy)(FPQUEUE_TYPE *self);
242
250FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_empty)(const FPQUEUE_TYPE *self);
251
259FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_full)(const FPQUEUE_TYPE *self);
260
268FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, get_max)(const FPQUEUE_TYPE *self);
269
278FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, peek)(const FPQUEUE_TYPE *self);
279
287FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, pop_max)(FPQUEUE_TYPE *self);
288
297FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, push)(FPQUEUE_TYPE *self, VALUE_TYPE value, const uint32_t priority);
298
307FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, push)(FPQUEUE_TYPE *self, VALUE_TYPE value, const uint32_t priority);
308
314FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, clear)(FPQUEUE_TYPE *self);
315
323FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, copy)(FPQUEUE_TYPE *restrict dest_ptr, const FPQUEUE_TYPE *restrict src_ptr);
324
325// @}}}
326
327// function definitions: {{{
328
333#ifdef FUNCTION_DEFINITIONS
334
336
337/* push a node down the heap. for restoring the heap property after insertion */
338static inline void JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(FPQUEUE_TYPE *self, const uint32_t index);
339
340/* push a node up the heap. for restoring the heap property after deletion */
341static inline void JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(FPQUEUE_TYPE *self, uint32_t index);
342
344
345FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, init)(FPQUEUE_TYPE *self, const uint32_t capacity)
346{
347 assert(self);
348
349 self->count = 0;
350 self->capacity = capacity;
351
352 return self;
353}
354
355FUNCTION_LINKAGE FPQUEUE_TYPE *JOIN(FPQUEUE_NAME, create)(const uint32_t capacity)
356{
357 if (capacity == 0 || FPQUEUE_CALC_SIZEOF_OVERFLOWS(FPQUEUE_NAME, capacity)) {
358 return NULL;
359 }
360
361 const uint32_t size = FPQUEUE_CALC_SIZEOF(FPQUEUE_NAME, capacity);
362
363 FPQUEUE_TYPE *self = (FPQUEUE_TYPE *)calloc(1, size);
364
365 if (!self) {
366 return NULL;
367 }
368
369 FPQUEUE_INIT(self, capacity);
370
371 return self;
372}
373
374FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, destroy)(FPQUEUE_TYPE *self)
375{
376 assert(self != NULL);
377
378 free(self);
379}
380
381FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_empty)(const FPQUEUE_TYPE *self)
382{
383 assert(self != NULL);
384
385 return self->count == 0;
386}
387
388FUNCTION_LINKAGE bool JOIN(FPQUEUE_NAME, is_full)(const FPQUEUE_TYPE *self)
389{
390 assert(self != NULL);
391
392 return self->count == self->capacity;
393}
394
395FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, get_max)(const FPQUEUE_TYPE *self)
396{
397 assert(self != NULL);
398 assert(FPQUEUE_IS_EMPTY(self) == false);
399
400 return self->elements[0].value;
401}
402
403FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, peek)(const FPQUEUE_TYPE *self)
404{
405 return JOIN(FPQUEUE_NAME, get_max)(self);
406}
407
408FUNCTION_LINKAGE VALUE_TYPE JOIN(FPQUEUE_NAME, pop_max)(FPQUEUE_TYPE *self)
409{
410 assert(self != NULL);
411 assert(FPQUEUE_IS_EMPTY(self) == false);
412
413 VALUE_TYPE max_priority_value = self->elements[0].value;
414
415 self->elements[0] = self->elements[self->count - 1];
416
417 self->count--;
418
419 JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(self, 0);
420
421 return max_priority_value;
422}
423
424FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, push)(FPQUEUE_TYPE *self, VALUE_TYPE value, const uint32_t priority)
425{
426 assert(self != NULL);
427 assert(FPQUEUE_IS_FULL(self) == false);
428
429 const uint32_t index = self->count;
430
431 self->elements[index] = (FPQUEUE_ELEMENT_TYPE){.priority = priority, .value = value};
432
433 self->count++;
434
435 JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(self, index);
436}
437
438FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, clear)(FPQUEUE_TYPE *self)
439{
440 assert(self != NULL);
441
442 self->count = 0;
443}
444
445FUNCTION_LINKAGE void JOIN(FPQUEUE_NAME, copy)(FPQUEUE_TYPE *restrict dest_ptr, const FPQUEUE_TYPE *restrict src_ptr)
446{
447 assert(src_ptr != NULL);
448 assert(dest_ptr != NULL);
449 assert(src_ptr->count <= dest_ptr->capacity);
450 assert(FPQUEUE_IS_EMPTY(dest_ptr));
451
452 for (uint32_t i = 0; i < src_ptr->count; i++) {
453 dest_ptr->elements[i] = src_ptr->elements[i];
454 }
455 dest_ptr->count = src_ptr->count;
456}
457
459
460static inline void JOIN(internal, JOIN(FPQUEUE_NAME, upheap))(FPQUEUE_TYPE *self, uint32_t index)
461{
462 assert(self != NULL);
463 assert(index < self->count);
464
465 uint32_t parent;
466 while (index > 0) {
467 parent = FPQUEUE_PARENT(index);
468
469 const bool sorted = self->elements[parent].priority >= self->elements[index].priority;
470
471 if (sorted) {
472 break;
473 }
474
475 const FPQUEUE_ELEMENT_TYPE temp = self->elements[index];
476 self->elements[index] = self->elements[parent];
477 self->elements[parent] = temp;
478
479 index = parent;
480 }
481}
482
483static inline void JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(FPQUEUE_TYPE *self, const uint32_t index)
484{
485 assert(self != NULL);
486 assert(self->count == 0 || index < self->count);
487
488 const uint32_t l = FPQUEUE_LEFT_CHILD(index);
489 const uint32_t r = FPQUEUE_RIGHT_CHILD(index);
490
491 uint32_t largest = index;
492 if (l < self->count && self->elements[l].priority > self->elements[index].priority) {
493 largest = l;
494 }
495 if (r < self->count && self->elements[r].priority > self->elements[largest].priority) {
496 largest = r;
497 }
498
499 if (largest == index) {
500 return;
501 }
502
503 const FPQUEUE_ELEMENT_TYPE temp = self->elements[index];
504 self->elements[index] = self->elements[largest];
505 self->elements[largest] = temp;
506
507 JOIN(internal, JOIN(FPQUEUE_NAME, downheap))(self, largest);
508}
510
511#endif
512
513// }}}
514
515// macro undefs: {{{
516
517#undef NAME
518#undef VALUE_TYPE
519#undef FUNCTION_LINKAGE
520#undef FUNCTION_DEFINITIONS
521#undef TYPE_DEFINITIONS
522
523#undef FPQUEUE_NAME
524#undef FPQUEUE_TYPE
525#undef FPQUEUE_ELEMENT_TYPE
526#undef FPQUEUE_INIT
527#undef FPQUEUE_IS_EMPTY
528#undef FPQUEUE_IS_FULL
529#undef FPQUEUE_CALC_SIZEOF
530#undef FHASHTABLE_UPHEAP
531#undef FHASHTABLE_DOWNHEAP
532
533// }}}
534
535#ifdef __cplusplus
536}
537#endif
538
539// vim: ft=c fdm=marker
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fpqueue_template.h:56
#define FPQUEUE_RIGHT_CHILD(index)
Given an element index, get the index of the right child.
Definition fpqueue_template.h:76
#define FPQUEUE_CALC_SIZEOF(fpqueue_name, capacity)
Calculate the size of the pqueue struct. No overflow checks.
Definition fpqueue_template.h:116
#define FPQUEUE_LEFT_CHILD(index)
Given an element index, get the index of the left child.
Definition fpqueue_template.h:66
#define FPQUEUE_PARENT(index)
Given an element index, get the index of the parent.
Definition fpqueue_template.h:86
#define VALUE_TYPE
Priority queue value type. This must be manually defined before including this header file.
Definition fpqueue_template.h:157
#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:131
#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 priority
Element priority (highest is next to-be-popped).
Definition fpqueue_template.h:195
VALUE_TYPE value
Element value member.
Definition fpqueue_template.h:196
uint32_t capacity
Number of elements allocated for.
Definition fpqueue_template.h:204
fpqueue_element_type elements[]
Array of elements.
Definition fpqueue_template.h:205
uint32_t count
Number of non-empty elements.
Definition fpqueue_template.h:203