pheap.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _PICO_UTIL_PHEAP_H
8#define _PICO_UTIL_PHEAP_H
9
10#include "pico.h"
11
12#ifdef __cplusplus
13extern "C" {
14#endif
15
16// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PHEAP, Enable/disable assertions in the pheap module, type=bool, default=0, group=pico_util
17#ifndef PARAM_ASSERTIONS_ENABLED_PHEAP
18#define PARAM_ASSERTIONS_ENABLED_PHEAP 0
19#endif
20
38// PICO_CONFIG: PICO_PHEAP_MAX_ENTRIES, Maximum number of entries in the pheap, min=1, max=65534, default=255, group=pico_util
39#ifndef PICO_PHEAP_MAX_ENTRIES
40#define PICO_PHEAP_MAX_ENTRIES 255
41#endif
42
43// public heap_node ids are numbered from 1 (0 means none)
44#if PICO_PHEAP_MAX_ENTRIES < 256
45typedef uint8_t pheap_node_id_t;
46#elif PICO_PHEAP_MAX_ENTRIES < 65535
47typedef uint16_t pheap_node_id_t;
48#else
49#error invalid PICO_PHEAP_MAX_ENTRIES
50#endif
51
52typedef struct pheap_node {
53 pheap_node_id_t child, sibling, parent;
55
61typedef bool (*pheap_comparator)(void *user_data, pheap_node_id_t a, pheap_node_id_t b);
62
63typedef struct pheap {
64 pheap_node_t *nodes;
65 pheap_comparator comparator;
66 void *user_data;
67 pheap_node_id_t max_nodes;
68 pheap_node_id_t root_id;
69 // we remove from head and add to tail to stop reusing the same ids
70 pheap_node_id_t free_head_id;
71 pheap_node_id_t free_tail_id;
72} pheap_t;
73
87pheap_t *ph_create(uint max_nodes, pheap_comparator comparator, void *user_data);
88
93void ph_clear(pheap_t *heap);
94
101void ph_destroy(pheap_t *heap);
102
103// internal method
104static inline pheap_node_t *ph_get_node(pheap_t *heap, pheap_node_id_t id) {
105 assert(id && id <= heap->max_nodes);
106 return heap->nodes + id - 1;
107}
108
109// internal method
110static void ph_add_child_node(pheap_t *heap, pheap_node_id_t parent_id, pheap_node_id_t child_id) {
111 pheap_node_t *n = ph_get_node(heap, parent_id);
112 assert(parent_id);
113 assert(child_id);
114 assert(parent_id != child_id);
115 pheap_node_t *c = ph_get_node(heap, child_id);
116 c->parent = parent_id;
117 if (!n->child) {
118 n->child = child_id;
119 } else {
120 c->sibling = n->child;
121 n->child = child_id;
122 }
123}
124
125// internal method
126static pheap_node_id_t ph_merge_nodes(pheap_t *heap, pheap_node_id_t a, pheap_node_id_t b) {
127 if (!a) return b;
128 if (!b) return a;
129 if (heap->comparator(heap->user_data, a, b)) {
130 ph_add_child_node(heap, a, b);
131 return a;
132 } else {
133 ph_add_child_node(heap, b, a);
134 return b;
135 }
136}
137
144static inline pheap_node_id_t ph_new_node(pheap_t *heap) {
145 if (!heap->free_head_id) return 0;
146 pheap_node_id_t id = heap->free_head_id;
147 pheap_node_t *hn = ph_get_node(heap, id);
148 heap->free_head_id = hn->sibling;
149 if (!heap->free_head_id) heap->free_tail_id = 0;
150 hn->child = hn->sibling = hn->parent = 0;
151 return id;
152}
153
165static inline pheap_node_id_t ph_insert_node(pheap_t *heap, pheap_node_id_t id) {
166 assert(id);
167 pheap_node_t *hn = ph_get_node(heap, id);
168 hn->child = hn->sibling = hn->parent = 0;
169 heap->root_id = ph_merge_nodes(heap, heap->root_id, id);
170 return heap->root_id;
171}
172
180static inline pheap_node_id_t ph_peek_head(pheap_t *heap) {
181 return heap->root_id;
182}
183
199pheap_node_id_t ph_remove_head(pheap_t *heap, bool free);
200
213static inline pheap_node_id_t ph_remove_and_free_head(pheap_t *heap) {
214 return ph_remove_head(heap, true);
215}
216
225bool ph_remove_and_free_node(pheap_t *heap, pheap_node_id_t id);
226
235static inline bool ph_contains_node(pheap_t *heap, pheap_node_id_t id) {
236 return id == heap->root_id || ph_get_node(heap, id)->parent;
237}
238
239
246static inline void ph_free_node(pheap_t *heap, pheap_node_id_t id) {
247 assert(id && !ph_contains_node(heap, id));
248 if (heap->free_tail_id) {
249 ph_get_node(heap, heap->free_tail_id)->sibling = id;
250 }
251 heap->free_tail_id = id;
252}
253
261void ph_dump(pheap_t *heap, void (*dump_key)(pheap_node_id_t id, void *user_data), void *user_data);
262
272void ph_post_alloc_init(pheap_t *heap, uint max_nodes, pheap_comparator comparator, void *user_data);
273
278#define PHEAP_DEFINE_STATIC(name, _max_nodes) \
279 static_assert(_max_nodes && _max_nodes < (1u << (8 * sizeof(pheap_node_id_t))), ""); \
280 static pheap_node_t name ## _nodes[_max_nodes]; \
281 static pheap_t name = { \
282 .nodes = name ## _nodes, \
283 .max_nodes = _max_nodes \
284 };
285
286
287#ifdef __cplusplus
288}
289#endif
290
291#endif
bool(* pheap_comparator)(void *user_data, pheap_node_id_t a, pheap_node_id_t b)
A user comparator function for nodes in a pairing heap.
Definition: pheap.h:61
void ph_destroy(pheap_t *heap)
De-allocates a pairing heap.
Definition: pheap.c:37
static void ph_free_node(pheap_t *heap, pheap_node_id_t id)
Free a node that is not currently in the heap, but has been allocated.
Definition: pheap.h:246
void ph_clear(pheap_t *heap)
Removes all nodes from the pairing heap.
Definition: pheap.c:27
void ph_post_alloc_init(pheap_t *heap, uint max_nodes, pheap_comparator comparator, void *user_data)
Initialize a statically allocated heap (ph_create() using the C heap).
Definition: pheap.c:19
static bool ph_contains_node(pheap_t *heap, pheap_node_id_t id)
Determine if the heap contains a given node.
Definition: pheap.h:235
bool ph_remove_and_free_node(pheap_t *heap, pheap_node_id_t id)
Remove and free an arbitrary node from the pairing heap.
Definition: pheap.c:78
pheap_node_id_t ph_remove_head(pheap_t *heap, bool free)
Remove the head node from the pairing heap.
Definition: pheap.c:72
static pheap_node_id_t ph_peek_head(pheap_t *heap)
Returns the head node in the heap, i.e.
Definition: pheap.h:180
void ph_dump(pheap_t *heap, void(*dump_key)(pheap_node_id_t id, void *user_data), void *user_data)
Print a representation of the heap for debugging.
static pheap_node_id_t ph_insert_node(pheap_t *heap, pheap_node_id_t id)
Inserts a node into the heap.
Definition: pheap.h:165
pheap_t * ph_create(uint max_nodes, pheap_comparator comparator, void *user_data)
Create a pairing heap, which effectively maintains an efficient sorted ordering of nodes.
Definition: pheap.c:11
static pheap_node_id_t ph_remove_and_free_head(pheap_t *heap)
Remove the head node from the pairing heap.
Definition: pheap.h:213
static pheap_node_id_t ph_new_node(pheap_t *heap)
Allocate a new node from the unused space in the heap.
Definition: pheap.h:144
Definition: pheap.h:52
Definition: pheap.h:63