blob: fc8043552e2f7be4e88b0ea6e638396aa97a6b67 [file] [log] [blame]
Austin Schuh208337d2022-01-01 14:29:11 -08001/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include "pico/util/pheap.h"
10
11pheap_t *ph_create(uint max_nodes, pheap_comparator comparator, void *user_data) {
12 invalid_params_if(PHEAP, !max_nodes || max_nodes >= (1u << (8 * sizeof(pheap_node_id_t))));
13 pheap_t *heap = calloc(1, sizeof(pheap_t));
14 heap->nodes = calloc(max_nodes, sizeof(pheap_node_t));
15 ph_post_alloc_init(heap, max_nodes, comparator, user_data);
16 return heap;
17}
18
19void ph_post_alloc_init(pheap_t *heap, uint max_nodes, pheap_comparator comparator, void *user_data) {
20 invalid_params_if(PHEAP, !max_nodes || max_nodes >= (1u << (8 * sizeof(pheap_node_id_t))));
21 heap->max_nodes = (pheap_node_id_t) max_nodes;
22 heap->comparator = comparator;
23 heap->user_data = user_data;
24 ph_clear(heap);
25}
26
27void ph_clear(pheap_t *heap) {
28 heap->root_id = 0;
29 heap->free_head_id = 1;
30 heap->free_tail_id = heap->max_nodes;
31 for(pheap_node_id_t i = 1; i < heap->max_nodes; i++) {
32 ph_get_node(heap, i)->sibling = (pheap_node_id_t)(i + 1);
33 }
34 ph_get_node(heap, heap->max_nodes)->sibling = 0;
35}
36
37void ph_destroy(pheap_t *heap) {
38 free(heap->nodes);
39 free(heap);
40}
41
42pheap_node_id_t ph_merge_two_pass(pheap_t *heap, pheap_node_id_t id) {
43 if (!id || !ph_get_node(heap, id)->sibling) {
44 return id;
45 } else {
46 pheap_node_id_t a, b, new_node;
47 a = id;
48 b = ph_get_node(heap, id)->sibling;
49 new_node = ph_get_node(heap, b)->sibling;
50 ph_get_node(heap, a)->sibling = ph_get_node(heap, b)->sibling = 0;
51 return ph_merge_nodes(heap, ph_merge_nodes(heap, a, b), ph_merge_two_pass(heap, new_node));
52 }
53}
54
55static pheap_node_id_t ph_remove_any_head(pheap_t *heap, pheap_node_id_t root_id, bool free) {
56 assert(root_id);
57// printf("Removing head %d (parent %d sibling %d)\n", root_id, ph_get_node(heap, root_id)->parent, ph_get_node(heap, root_id)->sibling);
58 assert(!ph_get_node(heap, root_id)->sibling);
59 assert(!ph_get_node(heap, root_id)->parent);
60 pheap_node_id_t new_root_id = ph_merge_two_pass(heap, ph_get_node(heap, root_id)->child);
61 if (free) {
62 if (heap->free_tail_id) {
63 ph_get_node(heap, heap->free_tail_id)->sibling = root_id;
64 }
65 heap->free_tail_id = root_id;
66 }
67 if (new_root_id) ph_get_node(heap, new_root_id)->parent = 0;
68 ph_get_node(heap, root_id)->sibling = 0;
69 return new_root_id;
70}
71
72pheap_node_id_t ph_remove_head(pheap_t *heap, bool free) {
73 pheap_node_id_t old_root_id = ph_peek_head(heap);
74 heap->root_id = ph_remove_any_head(heap, old_root_id, free);
75 return old_root_id;
76}
77
78bool ph_remove_and_free_node(pheap_t *heap, pheap_node_id_t id) {
79 // 1) trivial cases
80 if (!id) return false;
81 if (id == heap->root_id) {
82 ph_remove_and_free_head(heap);
83 return true;
84 }
85 // 2) unlink the node from the tree
86 pheap_node_t *node = ph_get_node(heap, id);
87 if (!node->parent) return false; // not in tree
88 pheap_node_t *parent = ph_get_node(heap, node->parent);
89 if (parent->child == id) {
90 parent->child = node->sibling;
91 } else {
92 pheap_node_id_t prev_sibling_id = parent->child;
93 bool __unused found = false;
94 do {
95 pheap_node_t *prev_sibling = ph_get_node(heap, prev_sibling_id);
96 if (prev_sibling->sibling == id) {
97 prev_sibling->sibling = node->sibling;
98 found = true;
99 break;
100 }
101 prev_sibling_id = prev_sibling->sibling;
102 } while (prev_sibling_id);
103 assert(found);
104 }
105 node->sibling = node->parent = 0;
106// ph_dump(heap, NULL, NULL);
107 // 3) remove it from the head of its own subtree
108 pheap_node_id_t new_sub_tree = ph_remove_any_head(heap, id, true);
109 assert(new_sub_tree != heap->root_id);
110 heap->root_id = ph_merge_nodes(heap, heap->root_id, new_sub_tree);
111 return true;
112}
113
114static uint ph_dump_node(pheap_t *heap, pheap_node_id_t id, void (*dump_key)(pheap_node_id_t, void *), void *user_data, uint indent) {
115 uint count = 0;
116 if (id) {
117 count++;
118 for (uint i = 0; i < indent * 2; i++) {
119 putchar(' ');
120 }
121 pheap_node_t *node = ph_get_node(heap, id);
122 printf("%d (c=%d s=%d p=%d) ", id, node->child, node->sibling, node->parent);
123 if (dump_key) dump_key(id, user_data);
124 printf("\n");
125 count += ph_dump_node(heap, node->child, dump_key, user_data, indent + 1);
126 count += ph_dump_node(heap, node->sibling, dump_key, user_data, indent);
127 }
128 return count;
129}
130
131void ph_dump(pheap_t *heap, void (*dump_key)(pheap_node_id_t, void *), void *user_data) {
132 uint count = ph_dump_node(heap, heap->root_id, dump_key, user_data, 0);
133 printf("node_count %d\n", count);
134}