diff --git a/include/zephyr/sys/min_heap.h b/include/zephyr/sys/min_heap.h new file mode 100644 index 00000000000..eaf5d39fa05 --- /dev/null +++ b/include/zephyr/sys/min_heap.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2025 Aerlync Labs Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_MIN_HEAP_H_ +#define ZEPHYR_INCLUDE_SYS_MIN_HEAP_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief min_heap + * @defgroup min_heap_apis Min-Heap service + * @ingroup datastructure_apis + * @{ + */ + +/** + * @brief Comparator function type for min-heap ordering. + * + * This function compares two heap nodes to establish their relative order. + * It must be implemented by the user and provided at min-heap + * initialization. + * + * @param a First user defined data pointer for comparison. + * @param b Second user defined data pointer for comparison. + * + * @return Negative value if @p a is less than @p b, + * positive value if @p a is greater than @p b, + * zero if they are equal. + */ +typedef int (*min_heap_cmp_t)(const void *a, + const void *b); + +/** + * @brief Equality function for finding a node in the heap. + * + * @param node Pointer to a user defined data. + * @param other Pointer to a user-defined key or structure to compare with. + * + * @return true if the node matches the search criteria, false otherwise. + */ +typedef bool (*min_heap_eq_t)(const void *node, + const void *other); + +/** + * @brief min-heap data structure with user-provided comparator. + */ +struct min_heap { + /** Raw pointer to contiguous memory for elements */ + void *storage; + /** Maximum number of elements */ + size_t capacity; + /** Size of each element*/ + size_t elem_size; + /** Current elements count */ + size_t size; + /** Comparator function */ + min_heap_cmp_t cmp; +}; + +/** + * @brief Define and initialize a heap instance at runtime. + * + * @param name Name of the heap variable. + * @param storage Pointer to the preallocated storage. + * @param cap Capacity (number of elements). + * @param size Size of each element. + * @param cmp_func Comparator function for the heap. + */ +#define MIN_HEAP_DEFINE(name, storage, cap, size, cmp_func) \ + struct min_heap name; \ + min_heap_init(&name, storage, cap, size, cmp_func) + +/** + * @brief Define a statically allocated and aligned min-heap instance. + * + * @param name Base name for the heap instance. + * @param cap Capacity (number of elements). + * @param elem_sz Size in bytes of each element. + * @param align Required alignment of each element. + * @param cmp_func Comparator function used by the heap + */ +#define MIN_HEAP_DEFINE_STATIC(name, cap, elem_sz, align, cmp_func) \ + static uint8_t name##_storage[(cap) * (elem_sz)] __aligned(align); \ + static struct min_heap name = { \ + .storage = name##_storage, \ + .capacity = (cap), \ + .elem_size = (elem_sz), \ + .size = 0, \ + .cmp = (cmp_func) \ + } + +/** + * @brief Initialize a min-heap instance at runtime. + * + * Sets up the internal structure of a min heap using a user-provided + * memory block, capacity, and comparator function. This function must + * be called before using the heap if not statically defined. + * + * @param heap Pointer to the min-heap structure. + * @param storage Pointer to memory block for storing elements. + * @param cap Maximum number of elements the heap can store. + * @param elem_size Size in bytes of each element. + * @param cmp Comparator function used to order the heap elements. + * + * @note All arguments must be valid. This function does not allocate memory. + * + */ +void min_heap_init(struct min_heap *heap, void *storage, size_t cap, + size_t elem_size, min_heap_cmp_t cmp); + +/** + * @brief Push an element into the min-heap. + * + * Adds a new element to the min-heap and restores the heap order by moving it + * upward as necessary. Insert operation will fail if the min-heap + * has reached full capacity. + * + * @param heap Pointer to the min-heap. + * @param item Pointer to the item to insert. + * + * @return 0 on Success, -ENOMEM if the heap is full. + */ +int min_heap_push(struct min_heap *heap, const void *item); + +/** + * @brief Peek at the top element of the min-heap. + * + * The function will not remove the element from the min-heap. + * + * @param heap Pointer to the min-heap. + * + * @return Pointer to the top priority element, or NULL if the heap is empty. + */ +void *min_heap_peek(const struct min_heap *heap); + +/** + * @brief Remove a specific element from the min-heap. + * + * Removes the specified node from the min-heap based on the ID it stores + * internally. The min-heap is rebalanced after removal to ensure + * proper ordering. + * The caller gains ownership of the returned element and is responsible for + * any further management of its memory or reuse. + * + * @param heap Pointer to the min-heap. + * @param id element ID to be removed. + * @param out_buf User-provided buffer where the removed element will be copied. + * + * @return true in success, false otherwise. + */ +bool min_heap_remove(struct min_heap *heap, size_t id, void *out_buf); + +/** + * @brief Check if the min heap is empty. + * + * This function checks whether the heap contains any elements. + * + * @param heap Pointer to the min heap. + * + * @return true if heap is empty, false otherwise. + */ +static inline bool min_heap_is_empty(struct min_heap *heap) +{ + __ASSERT_NO_MSG(heap != NULL); + + return (heap->size == 0); +} + +/** + * @brief Remove and return the highest priority element in the heap. + * + * The caller gains ownership of the returned element and is responsible for + * any further management of its memory or reuse. The min-heap is rebalanced + * after removal to ensure proper ordering. + * + * @param heap Pointer to heap. + * @param out_buf User-provided buffer where the removed element will be copied. + * + * @return true in success, false otherwise. + */ +bool min_heap_pop(struct min_heap *heap, void *out_buf); + +/** + * @brief Search for a node in the heap matching a condition. + * + * @param heap Pointer to the heap structure. + * @param eq Function used to compare each node with the search target. + * @param other Pointer to the data used for comparison in the eq function. + * @param out_id Optional output parameter to store the index of the found node. + * + * @return Pointer to the first matching element, or NULL if not found. + */ +void *min_heap_find(struct min_heap *heap, min_heap_eq_t eq, + const void *other, size_t *out_id); + +/** + * @brief Get a pointer to the element at the specified index. + * + * @param heap Pointer to the min-heap. + * @param index Index of the element to retrieve. + * + * @return Pointer to the element at the given index. + */ +static inline void *min_heap_get_element(const struct min_heap *heap, + size_t index) +{ + return (void *)((uintptr_t)heap->storage + index * heap->elem_size); +} + +/** + * @brief Iterate over each node in the heap. + * + * @param heap Pointer to the heap. + * @param node_var The loop variable used to reference each node. + * @param body Code block to execute for each node. + * + * Example: + * ``` + * void *node; + * MIN_HEAP_FOREACH(&heap, node, { + * printk("Value: %d\n", node->value); + * }); + * ``` + */ +#define MIN_HEAP_FOREACH(heap, node_var, body) \ + do { for (size_t _i = 0; _i < (heap)->size && \ + (((node_var) = min_heap_get_element((heap), _i)) || true); \ + ++_i) { \ + body; \ + } \ + } while (0) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_MIN_HEAP_H_ */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index b945968c8fb..9fb963de415 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory_ifdef(CONFIG_NET_BUF net_buf) add_subdirectory(os) add_subdirectory(utils) add_subdirectory_ifdef(CONFIG_SMF smf) +add_subdirectory_ifdef(CONFIG_MIN_HEAP min_heap) add_subdirectory_ifdef(CONFIG_OPENAMP open-amp) add_subdirectory_ifdef(CONFIG_ACPI acpi) add_subdirectory(uuid) diff --git a/lib/Kconfig b/lib/Kconfig index ae97399b199..626bec379dd 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1,4 +1,6 @@ # Copyright (c) 2016 Intel Corporation +# Copyright (c) 2025 Aerlync Labs Inc. +# # SPDX-License-Identifier: Apache-2.0 source "lib/libc/Kconfig" @@ -32,4 +34,6 @@ source "lib/runtime/Kconfig" source "lib/utils/Kconfig" source "lib/uuid/Kconfig" + +source "lib/min_heap/Kconfig" endmenu diff --git a/lib/min_heap/CMakeLists.txt b/lib/min_heap/CMakeLists.txt new file mode 100644 index 00000000000..1a157763c3d --- /dev/null +++ b/lib/min_heap/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_interface_library_named(min_heap) + +target_include_directories(min_heap INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +zephyr_library() + +zephyr_library_sources(min_heap.c) + +zephyr_library_link_libraries(min_heap) diff --git a/lib/min_heap/Kconfig b/lib/min_heap/Kconfig new file mode 100644 index 00000000000..076db547442 --- /dev/null +++ b/lib/min_heap/Kconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2025 Aerlync Labs Inc. +# SPDX-License-Identifier: Apache-2.0 + +config MIN_HEAP + bool "Min-Heap Data Structure" + help + Enable support for a generic Min-Heap data structure library. + + A Min-Heap is a binary tree-based data structure in which the + smallest element is always at the root. It supports efficient + insertion and removal of the minimum element in O(log n) time, + making it useful for priority queues, schedulers, and timeout + queues. + + This implementation is designed for general-purpose use in both + kernel and application code. It supports static and dynamic + initialization and allows for custom comparator functions. + + Note: This is unrelated to the kernel's heap memory allocator + (used for dynamic memory allocation with `k_malloc()` or + `k_heap_alloc()`). The "heap" in Min-Heap refers to the ordering + structure, not memory management. diff --git a/lib/min_heap/min_heap.c b/lib/min_heap/min_heap.c new file mode 100644 index 00000000000..3beed5f9721 --- /dev/null +++ b/lib/min_heap/min_heap.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025 Aerlync Labs Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +LOG_MODULE_REGISTER(min_heap); + +/** + * @brief Swap two elements in the heap. + * + * This function swaps the contents of two elements at the specified indices + * within the heap. + * + * @param heap Pointer to the min-heap. + * @param a Index of the first element. + * @param b Index of the second element. + */ +static void swap(struct min_heap *heap, size_t a, size_t b) +{ + uint8_t tmp[heap->elem_size]; + void *elem_a = min_heap_get_element(heap, a); + void *elem_b = min_heap_get_element(heap, b); + + memcpy(tmp, elem_a, heap->elem_size); + memcpy(elem_a, elem_b, heap->elem_size); + memcpy(elem_b, tmp, heap->elem_size); +} + +/** + * @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) +{ + size_t parent; + void *curr, *par; + + while (index > 0) { + parent = (index - 1) / 2; + curr = min_heap_get_element(heap, index); + par = min_heap_get_element(heap, parent); + if (heap->cmp(curr, par) >= 0) { + break; + } + swap(heap, index, parent); + 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) +{ + size_t left, right, smallest; + + while (true) { + left = 2 * index + 1; + right = 2 * index + 2; + smallest = index; + + if (left < heap->size && + heap->cmp(min_heap_get_element(heap, left), + min_heap_get_element(heap, smallest)) < 0) { + smallest = left; + } + + if (right < heap->size && + heap->cmp(min_heap_get_element(heap, right), + min_heap_get_element(heap, smallest)) < 0) { + smallest = right; + } + + if (smallest == index) { + break; + } + + swap(heap, index, smallest); + 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; +}