mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
301 lines
10 KiB
ReStructuredText
301 lines
10 KiB
ReStructuredText
|
.. SPDX-License-Identifier: GPL-2.0
|
||
|
|
||
|
============
|
||
|
Min Heap API
|
||
|
============
|
||
|
|
||
|
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 {
|
||
|
int nr; /* Number of elements in the heap */
|
||
|
int 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);
|
||
|
}
|