| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- .. SPDX-License-Identifier: GPL-2.0
- ============
- Min Heap API
- ============
- :Author: Kuan-Wei Chiu <visitorckw@gmail.com>
- Introduction
- ============
- The Min Heap API provides a set of functions and macros for managing min-heaps
- in the Linux kernel. A min-heap is a binary tree structure where the value of
- each node is less than or equal to the values of its children, ensuring that
- the smallest element is always at the root.
- This document provides a guide to the Min Heap API, detailing how to define and
- use min-heaps. Users should not directly call functions with **__min_heap_*()**
- prefixes, but should instead use the provided macro wrappers.
- In addition to the standard version of the functions, the API also includes a
- set of inline versions for performance-critical scenarios. These inline
- functions have the same names as their non-inline counterparts but include an
- **_inline** suffix. For example, **__min_heap_init_inline** and its
- corresponding macro wrapper **min_heap_init_inline**. The inline versions allow
- custom comparison and swap functions to be called directly, rather than through
- indirect function calls. This can significantly reduce overhead, especially
- when CONFIG_MITIGATION_RETPOLINE is enabled, as indirect function calls become
- more expensive. As with the non-inline versions, it is important to use the
- macro wrappers for inline functions instead of directly calling the functions
- themselves.
- Data Structures
- ===============
- Min-Heap Definition
- -------------------
- The core data structure for representing a min-heap is defined using the
- **MIN_HEAP_PREALLOCATED** and **DEFINE_MIN_HEAP** macros. These macros allow
- you to define a min-heap with a preallocated buffer or dynamically allocated
- memory.
- Example:
- .. code-block:: c
- #define MIN_HEAP_PREALLOCATED(_type, _name, _nr)
- struct _name {
- size_t nr; /* Number of elements in the heap */
- size_t size; /* Maximum number of elements that can be held */
- _type *data; /* Pointer to the heap data */
- _type preallocated[_nr]; /* Static preallocated array */
- }
- #define DEFINE_MIN_HEAP(_type, _name) MIN_HEAP_PREALLOCATED(_type, _name, 0)
- A typical heap structure will include a counter for the number of elements
- (`nr`), the maximum capacity of the heap (`size`), and a pointer to an array of
- elements (`data`). Optionally, you can specify a static array for preallocated
- heap storage using **MIN_HEAP_PREALLOCATED**.
- Min Heap Callbacks
- ------------------
- The **struct min_heap_callbacks** provides customization options for ordering
- elements in the heap and swapping them. It contains two function pointers:
- .. code-block:: c
- struct min_heap_callbacks {
- bool (*less)(const void *lhs, const void *rhs, void *args);
- void (*swp)(void *lhs, void *rhs, void *args);
- };
- - **less** is the comparison function used to establish the order of elements.
- - **swp** is a function for swapping elements in the heap. If swp is set to
- NULL, the default swap function will be used, which swaps the elements based on their size
- Macro Wrappers
- ==============
- The following macro wrappers are provided for interacting with the heap in a
- user-friendly manner. Each macro corresponds to a function that operates on the
- heap, and they abstract away direct calls to internal functions.
- Each macro accepts various parameters that are detailed below.
- Heap Initialization
- --------------------
- .. code-block:: c
- min_heap_init(heap, data, size);
- - **heap**: A pointer to the min-heap structure to be initialized.
- - **data**: A pointer to the buffer where the heap elements will be stored. If
- `NULL`, the preallocated buffer within the heap structure will be used.
- - **size**: The maximum number of elements the heap can hold.
- This macro initializes the heap, setting its initial state. If `data` is
- `NULL`, the preallocated memory inside the heap structure will be used for
- storage. Otherwise, the user-provided buffer is used. The operation is **O(1)**.
- **Inline Version:** min_heap_init_inline(heap, data, size)
- Accessing the Top Element
- -------------------------
- .. code-block:: c
- element = min_heap_peek(heap);
- - **heap**: A pointer to the min-heap from which to retrieve the smallest
- element.
- This macro returns a pointer to the smallest element (the root) of the heap, or
- `NULL` if the heap is empty. The operation is **O(1)**.
- **Inline Version:** min_heap_peek_inline(heap)
- Heap Insertion
- --------------
- .. code-block:: c
- success = min_heap_push(heap, element, callbacks, args);
- - **heap**: A pointer to the min-heap into which the element should be inserted.
- - **element**: A pointer to the element to be inserted into the heap.
- - **callbacks**: A pointer to a `struct min_heap_callbacks` providing the
- `less` and `swp` functions.
- - **args**: Optional arguments passed to the `less` and `swp` functions.
- This macro inserts an element into the heap. It returns `true` if the insertion
- was successful and `false` if the heap is full. The operation is **O(log n)**.
- **Inline Version:** min_heap_push_inline(heap, element, callbacks, args)
- Heap Removal
- ------------
- .. code-block:: c
- success = min_heap_pop(heap, callbacks, args);
- - **heap**: A pointer to the min-heap from which to remove the smallest element.
- - **callbacks**: A pointer to a `struct min_heap_callbacks` providing the
- `less` and `swp` functions.
- - **args**: Optional arguments passed to the `less` and `swp` functions.
- This macro removes the smallest element (the root) from the heap. It returns
- `true` if the element was successfully removed, or `false` if the heap is
- empty. The operation is **O(log n)**.
- **Inline Version:** min_heap_pop_inline(heap, callbacks, args)
- Heap Maintenance
- ----------------
- You can use the following macros to maintain the heap's structure:
- .. code-block:: c
- min_heap_sift_down(heap, pos, callbacks, args);
- - **heap**: A pointer to the min-heap.
- - **pos**: The index from which to start sifting down.
- - **callbacks**: A pointer to a `struct min_heap_callbacks` providing the
- `less` and `swp` functions.
- - **args**: Optional arguments passed to the `less` and `swp` functions.
- This macro restores the heap property by moving the element at the specified
- index (`pos`) down the heap until it is in the correct position. The operation
- is **O(log n)**.
- **Inline Version:** min_heap_sift_down_inline(heap, pos, callbacks, args)
- .. code-block:: c
- min_heap_sift_up(heap, idx, callbacks, args);
- - **heap**: A pointer to the min-heap.
- - **idx**: The index of the element to sift up.
- - **callbacks**: A pointer to a `struct min_heap_callbacks` providing the
- `less` and `swp` functions.
- - **args**: Optional arguments passed to the `less` and `swp` functions.
- This macro restores the heap property by moving the element at the specified
- index (`idx`) up the heap. The operation is **O(log n)**.
- **Inline Version:** min_heap_sift_up_inline(heap, idx, callbacks, args)
- .. code-block:: c
- min_heapify_all(heap, callbacks, args);
- - **heap**: A pointer to the min-heap.
- - **callbacks**: A pointer to a `struct min_heap_callbacks` providing the
- `less` and `swp` functions.
- - **args**: Optional arguments passed to the `less` and `swp` functions.
- This macro ensures that the entire heap satisfies the heap property. It is
- called when the heap is built from scratch or after many modifications. The
- operation is **O(n)**.
- **Inline Version:** min_heapify_all_inline(heap, callbacks, args)
- Removing Specific Elements
- --------------------------
- .. code-block:: c
- success = min_heap_del(heap, idx, callbacks, args);
- - **heap**: A pointer to the min-heap.
- - **idx**: The index of the element to delete.
- - **callbacks**: A pointer to a `struct min_heap_callbacks` providing the
- `less` and `swp` functions.
- - **args**: Optional arguments passed to the `less` and `swp` functions.
- This macro removes an element at the specified index (`idx`) from the heap and
- restores the heap property. The operation is **O(log n)**.
- **Inline Version:** min_heap_del_inline(heap, idx, callbacks, args)
- Other Utilities
- ===============
- - **min_heap_full(heap)**: Checks whether the heap is full.
- Complexity: **O(1)**.
- .. code-block:: c
- bool full = min_heap_full(heap);
- - `heap`: A pointer to the min-heap to check.
- This macro returns `true` if the heap is full, otherwise `false`.
- **Inline Version:** min_heap_full_inline(heap)
- - **min_heap_empty(heap)**: Checks whether the heap is empty.
- Complexity: **O(1)**.
- .. code-block:: c
- bool empty = min_heap_empty(heap);
- - `heap`: A pointer to the min-heap to check.
- This macro returns `true` if the heap is empty, otherwise `false`.
- **Inline Version:** min_heap_empty_inline(heap)
- Example Usage
- =============
- An example usage of the min-heap API would involve defining a heap structure,
- initializing it, and inserting and removing elements as needed.
- .. code-block:: c
- #include <linux/min_heap.h>
- int my_less_function(const void *lhs, const void *rhs, void *args) {
- return (*(int *)lhs < *(int *)rhs);
- }
- struct min_heap_callbacks heap_cb = {
- .less = my_less_function, /* Comparison function for heap order */
- .swp = NULL, /* Use default swap function */
- };
- void example_usage(void) {
- /* Pre-populate the buffer with elements */
- int buffer[5] = {5, 2, 8, 1, 3};
- /* Declare a min-heap */
- DEFINE_MIN_HEAP(int, my_heap);
- /* Initialize the heap with preallocated buffer and size */
- min_heap_init(&my_heap, buffer, 5);
- /* Build the heap using min_heapify_all */
- my_heap.nr = 5; /* Set the number of elements in the heap */
- min_heapify_all(&my_heap, &heap_cb, NULL);
- /* Peek at the top element (should be 1 in this case) */
- int *top = min_heap_peek(&my_heap);
- pr_info("Top element: %d\n", *top);
- /* Pop the top element (1) and get the new top (2) */
- min_heap_pop(&my_heap, &heap_cb, NULL);
- top = min_heap_peek(&my_heap);
- pr_info("New top element: %d\n", *top);
- /* Insert a new element (0) and recheck the top */
- int new_element = 0;
- min_heap_push(&my_heap, &new_element, &heap_cb, NULL);
- top = min_heap_peek(&my_heap);
- pr_info("Top element after insertion: %d\n", *top);
- }
|