You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
3.3 KiB
159 lines
3.3 KiB
/* |
|
* Copyright (c) 2025 Aerlync Labs Inc. |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <stdlib.h> |
|
#include <zephyr/sys/min_heap.h> |
|
#include <zephyr/logging/log.h> |
|
|
|
LOG_MODULE_REGISTER(min_heap); |
|
|
|
/** |
|
* @brief Restore heap order by moving a node up the tree. |
|
* |
|
* Moves the node at the given index upward in the heap until the min-heap |
|
* property is restored. |
|
* |
|
* @param heap Pointer to the min-heap. |
|
* @param index Index of the node to heapify upwards. |
|
*/ |
|
static void heapify_up(struct min_heap *heap, size_t index) |
|
{ |
|
while (index > 0) { |
|
size_t parent = (index - 1) / 2; |
|
void *curr = min_heap_get_element(heap, index); |
|
void *par = min_heap_get_element(heap, parent); |
|
|
|
if (heap->cmp(curr, par) >= 0) { |
|
break; |
|
} |
|
byteswp(curr, par, heap->elem_size); |
|
index = parent; |
|
} |
|
} |
|
|
|
/** |
|
* @brief Restore heap order by moving a node down the tree. |
|
* |
|
* Moves the node at the specified index downward in the heap until the |
|
* min-heap property is restored. |
|
* |
|
* @param heap Pointer to the min-heap. |
|
* @param index Index of the node to heapify downward. |
|
*/ |
|
|
|
static void heapify_down(struct min_heap *heap, size_t index) |
|
{ |
|
/* Terminate the loop naturally when the left child is out of bounds */ |
|
for (size_t left = 2 * index + 1; left < heap->size; left = 2 * index + 1) { |
|
|
|
size_t right = left + 1; |
|
size_t smallest = index; |
|
void *elem_index = min_heap_get_element(heap, index); |
|
void *elem_left = min_heap_get_element(heap, left); |
|
void *elem_smallest = elem_index; |
|
|
|
if (heap->cmp(elem_left, elem_index) < 0) { |
|
smallest = left; |
|
elem_smallest = elem_left; |
|
} |
|
|
|
if (right < heap->size) { |
|
void *elem_right = min_heap_get_element(heap, right); |
|
|
|
if (heap->cmp(elem_right, elem_smallest) < 0) { |
|
smallest = right; |
|
elem_smallest = elem_right; |
|
} |
|
} |
|
|
|
if (smallest == index) { |
|
break; |
|
} |
|
|
|
byteswp(elem_index, elem_smallest, heap->elem_size); |
|
index = smallest; |
|
} |
|
} |
|
|
|
|
|
void min_heap_init(struct min_heap *heap, void *storage, size_t cap, |
|
size_t elem_size, min_heap_cmp_t cmp) |
|
{ |
|
heap->storage = storage; |
|
heap->capacity = cap; |
|
heap->elem_size = elem_size; |
|
heap->cmp = cmp; |
|
heap->size = 0; |
|
} |
|
|
|
void *min_heap_peek(const struct min_heap *heap) |
|
{ |
|
if (heap->size == 0) { |
|
return NULL; |
|
} |
|
|
|
return min_heap_get_element(heap, 0); |
|
} |
|
|
|
int min_heap_push(struct min_heap *heap, const void *item) |
|
{ |
|
if (heap->size >= heap->capacity) { |
|
return -ENOMEM; |
|
} |
|
|
|
void *dest = min_heap_get_element(heap, heap->size); |
|
|
|
memcpy(dest, item, heap->elem_size); |
|
heapify_up(heap, heap->size); |
|
heap->size++; |
|
|
|
return 0; |
|
} |
|
|
|
bool min_heap_remove(struct min_heap *heap, size_t id, void *out_buf) |
|
{ |
|
if (id >= heap->size) { |
|
return false; |
|
} |
|
|
|
void *removed = min_heap_get_element(heap, id); |
|
|
|
memcpy(out_buf, removed, heap->elem_size); |
|
heap->size--; |
|
if (id != heap->size) { |
|
void *last = min_heap_get_element(heap, heap->size); |
|
|
|
memcpy(removed, last, heap->elem_size); |
|
heapify_down(heap, id); |
|
heapify_up(heap, id); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool min_heap_pop(struct min_heap *heap, void *out_buf) |
|
{ |
|
return min_heap_remove(heap, 0, out_buf); |
|
} |
|
|
|
void *min_heap_find(struct min_heap *heap, min_heap_eq_t eq, |
|
const void *other, size_t *out_id) |
|
{ |
|
void *element; |
|
|
|
for (size_t i = 0; i < heap->size; ++i) { |
|
|
|
element = min_heap_get_element(heap, i); |
|
if (eq(element, other)) { |
|
if (out_id) { |
|
*out_id = i; |
|
} |
|
return element; |
|
} |
|
} |
|
|
|
return NULL; |
|
}
|
|
|