blob: 8e9c68614c3b3ce7c1410d2e7c3b02ba38569aaa [file] [log] [blame]
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico/util/pheap.h"
pheap_t *ph_create(uint max_nodes, pheap_comparator comparator, void *user_data) {
invalid_params_if(PHEAP, !max_nodes || max_nodes >= (1u << sizeof(pheap_node_id_t)));
pheap_t *heap = calloc(1, sizeof(pheap_t));
heap->max_nodes = max_nodes;
heap->comparator = comparator;
heap->nodes = calloc(max_nodes, sizeof(pheap_node_t));
heap->user_data = user_data;
ph_clear(heap);
return heap;
}
void ph_clear(pheap_t *heap) {
heap->root_id = 0;
heap->free_head_id = 1;
heap->free_tail_id = heap->max_nodes;
for(uint i = 1; i < heap->max_nodes; i++) {
ph_get_node(heap, i)->sibling = i + 1;
}
ph_get_node(heap, heap->max_nodes)->sibling = 0;
}
void ph_destroy(pheap_t *heap) {
free(heap->nodes);
free(heap);
}
pheap_node_id_t ph_merge_two_pass(pheap_t *heap, pheap_node_id_t id) {
if (!id || !ph_get_node(heap, id)->sibling) {
return id;
} else {
pheap_node_id_t a, b, new_node;
a = id;
b = ph_get_node(heap, id)->sibling;
new_node = ph_get_node(heap, b)->sibling;
ph_get_node(heap, a)->sibling = ph_get_node(heap, b)->sibling = 0;
return ph_merge_nodes(heap, ph_merge_nodes(heap, a, b), ph_merge_two_pass(heap, new_node));
}
}
static pheap_node_id_t ph_remove_any_head(pheap_t *heap, pheap_node_id_t root_id, bool reserve) {
assert(root_id);
// 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);
assert(!ph_get_node(heap, root_id)->sibling);
assert(!ph_get_node(heap, root_id)->parent);
pheap_node_id_t new_root_id = ph_merge_two_pass(heap, ph_get_node(heap, root_id)->child);
if (!reserve) {
if (heap->free_tail_id) {
ph_get_node(heap, heap->free_tail_id)->sibling = root_id;
}
heap->free_tail_id = root_id;
}
if (new_root_id) ph_get_node(heap, new_root_id)->parent = 0;
ph_get_node(heap, root_id)->sibling = 0;
return new_root_id;
}
pheap_node_id_t ph_remove_head_reserve(pheap_t *heap, bool reserve) {
pheap_node_id_t old_root_id = ph_peek_head(heap);
heap->root_id = ph_remove_any_head(heap, old_root_id, reserve);
return old_root_id;
}
#include <stdio.h>
bool ph_delete(pheap_t *heap, pheap_node_id_t id) {
// 1) trivial cases
if (!id) return false;
if (id == heap->root_id) {
ph_remove_head(heap);
return true;
}
// 2) unlink the node from the tree
pheap_node_t *node = ph_get_node(heap, id);
if (!node->parent) return false; // not in tree
pheap_node_t *parent = ph_get_node(heap, node->parent);
if (parent->child == id) {
parent->child = node->sibling;
} else {
pheap_node_id_t prev_sibling_id = parent->child;
bool __unused found = false;
do {
pheap_node_t *prev_sibling = ph_get_node(heap, prev_sibling_id);
if (prev_sibling->sibling == id) {
prev_sibling->sibling = node->sibling;
found = true;
break;
}
prev_sibling_id = prev_sibling->sibling;
} while (prev_sibling_id);
assert(found);
}
node->sibling = node->parent = 0;
// ph_dump(heap, NULL, NULL);
// 3) remove it from the head of its own subtree
pheap_node_id_t new_sub_tree = ph_remove_any_head(heap, id, false);
assert(new_sub_tree != heap->root_id);
heap->root_id = ph_merge_nodes(heap, heap->root_id, new_sub_tree);
return true;
}
static 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) {
uint count = 0;
if (id) {
count++;
for (uint i = 0; i < indent * 2; i++) {
putchar(' ');
}
pheap_node_t *node = ph_get_node(heap, id);
printf("%d (c=%d s=%d p=%d) ", id, node->child, node->sibling, node->parent);
if (dump_key) dump_key(id, user_data);
printf("\n");
count += ph_dump_node(heap, node->child, dump_key, user_data, indent + 1);
count += ph_dump_node(heap, node->sibling, dump_key, user_data, indent);
}
return count;
}
void ph_dump(pheap_t *heap, void (*dump_key)(pheap_node_id_t, void *), void *user_data) {
uint count = ph_dump_node(heap, heap->root_id, dump_key, user_data, 0);
printf("node_count %d\n", count);
}