PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
rbtree.h
Go to the documentation of this file.
1#pragma once
2
3#include <sys/defs.h>
4
5#include <stdint.h>
6#include <sys/list.h>
7
8typedef struct rbnode rbnode_t;
9
10/**
11 * @brief Augmented Red-Black Tree.
12 * @defgroup kernel_utils_rbtree Red-Black Tree
13 * @ingroup kernel_utils
14 *
15 * A Red-Black Tree (RBT) is a tree structure that maintains sorted data to allow for efficient insertion, deletion, and
16 * lookup operations with a worst case time complexity of `O(log n)`.
17 *
18 * ## Used As A Sorted Linked List
19 *
20 * The name "Red-Black Tree" can be a bit confusing. To the user of the tree, it simply acts as a highly optimized
21 * sorted linked list.
22 *
23 * The tree structure allows for more efficient operations compared to a standard linked list (`O(log n)` vs `O(n)`),
24 * and the red-black properties ensure that the tree remains balanced, preventing it from degenerating into a linear
25 * structure. However, the user of the tree does not need to be concerned with these implementation details.
26 *
27 * @todo Cache minimum and maximum nodes for `O(1)` access.
28 *
29 * ## Update Callbacks
30 *
31 * The tree supports an optional update callback that is called whenever a node is inserted, removed or swapped. This
32 * allows for the tree to be "augmented" with additional data. For example, if you wanted to track the global minimum of
33 * some value in each node, you could do so by updating the minimum value in the update callback, such that you no
34 * longer need to traverse the tree to find the minimum. Very useful for the scheduler.
35 *
36 * @see [Wikipedia Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) for more information on
37 * Red-Black Trees.
38 * @see [Earliest Eligible Virtual Deadline
39 * First](https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=805acf7726282721504c8f00575d91ebfd750564) for
40 * the original paper describing EEVDF, contains some usefull information on balanced trees.
41 *
42 * @{
43 */
44
45/**
46 * @brief Red-Black Tree Node Colors.
47 * @enum rbnode_color_t
48 */
49typedef enum
50{
52 RBNODE_BLACK = 1
54
55/**
56 * @brief Red-Black Tree Node Directions.
57 * @enum rbnode_direction_t
58 *
59 * Used to index into the children array of a `rbnode_t`.
60 */
67
68/**
69 * @brief Get the opposite direction (left <-> right).
70 *
71 * @param direction The direction to get the opposite of.
72 * @return The opposite direction.
73 */
74#define RBNODE_OPPOSITE(direction) ((rbnode_direction_t)(1 - (direction)))
75
76/**
77 * @brief Get the direction of a node from its parent.
78 *
79 * @param node The node to get the direction of.
80 * @return The direction of the node from its parent.
81 */
82#define RBNODE_FROM_PARENT(node) \
83 ((rbnode_direction_t)((node)->parent->children[RBNODE_RIGHT] == (node) ? RBNODE_RIGHT : RBNODE_LEFT))
84
85/**
86 * @brief Red-Black Tree Node.
87 * @struct rbnode_t
88 *
89 * Should be embedded in the structure to be stored in the tree, such that the parent structure can be retrieved via
90 * `CONTAINER_OF()`.
91 */
92typedef struct rbnode
93{
97} rbnode_t;
98
99/**
100 * @brief Create a Red-Black Tree Node initializer.
101 *
102 * @return A Red-Black Tree Node initializer.
103 */
104#define RBNODE_CREATE \
105 (rbnode_t) \
106 { \
107 .parent = NULL, .children = {NULL, NULL}, .color = RBNODE_RED \
108 }
109
110/**
111 * @brief Comparison function for Red-Black Tree nodes.
112 *
113 * Should return:
114 * - A negative value if `a` is less than `b`.
115 * - Zero if `a` is equal to `b`.
116 * - A positive value if `a` is greater than `b`.
117 *
118 * @param a The first node to compare.
119 * @param b The second node to compare.
120 * @return The comparison result.
121 */
122typedef int64_t (*rbnode_compare_t)(const rbnode_t* a, const rbnode_t* b);
123
124/**
125 * @brief Update function for Red-Black Tree nodes.
126 *
127 * Called whenever a node is inserted, removed or swapped.
128 *
129 * @param node The node to update.
130 */
131typedef void (*rbnode_update_t)(rbnode_t* node);
132
133/**
134 * @brief Red-Black Tree.
135 * @struct rbtree_t
136 */
143
144/**
145 * @brief Initialize a Red-Black Tree.
146 *
147 * Will not allocate any memory.
148 *
149 * @param tree The tree to initialize.
150 * @param compare The comparison function to use.
151 * @param update The update function to use, or `NULL`.
152 */
153void rbtree_init(rbtree_t* tree, rbnode_compare_t compare, rbnode_update_t update);
154
155/**
156 * @brief Rotate a node in the Red-Black Tree.
157 *
158 * @see https://upload.wikimedia.org/wikipedia/commons/f/f2/Binary_Tree_Rotation_%28animated%29.gif for a animation of
159 * tree rotations.
160 *
161 * @param tree The tree containing the node to rotate.
162 * @param node The node to rotate.
163 * @param direction The direction to rotate.
164 * @return The new root of the rotated subtree.
165 */
167
168/**
169 * @brief Find the minimum node in a subtree.
170 *
171 * This is the same as just going as far left as possible.
172 *
173 * @param node The root of the subtree.
174 * @return The minimum node in the subtree.
175 */
177
178/**
179 * @brief Find the maximum node in a subtree.
180 *
181 * This is the same as just going as far right as possible.
182 *
183 * @param node The root of the subtree.
184 * @return The maximum node in the subtree.
185 */
187
188/**
189 * @brief Swap two nodes in the Red-Black Tree.
190 *
191 * Needed as the structure is intrusive, so we can't just swap the data.
192 *
193 * @param tree The tree containing the nodes to swap.
194 * @param a The first node to swap.
195 * @param b The second node to swap.
196 */
197void rbtree_swap(rbtree_t* tree, rbnode_t* a, rbnode_t* b);
198
199/**
200 * @brief Insert a node into the Red-Black Tree.
201 *
202 * @param tree The tree to insert into.
203 * @param node The node to insert.
204 */
205void rbtree_insert(rbtree_t* tree, rbnode_t* node);
206
207/**
208 * @brief Remove a node from the Red-Black Tree.
209 *
210 * @param tree The tree to remove from.
211 * @param node The node to remove.
212 */
213void rbtree_remove(rbtree_t* tree, rbnode_t* node);
214
215/**
216 * @brief Move the node to its correct position in the Red-Black Tree.
217 *
218 * Should be called whenever the metric used for comparison changes.
219 *
220 * @note This function is optimized assuming the common case where the node is already close to its correct position.
221 *
222 * @param tree The tree containing the node to update.
223 * @param node The node to update.
224 */
225void rbtree_fix(rbtree_t* tree, rbnode_t* node);
226
227/**
228 * @brief Check if the Red-Black Tree is empty.
229 *
230 * @param tree The tree to check.
231 * @return `true` if the tree is empty, `false` otherwise.
232 */
233bool rbtree_is_empty(const rbtree_t* tree);
234
235/**
236 * @brief Get the next node in the tree, in predecessor order.
237 *
238 * @param node The current node.
239 * @return The next node in the tree, or `NULL` if `node` is the last node.
240 */
241rbnode_t* rbtree_next(const rbnode_t* node);
242
243/**
244 * @brief Get the previous node in the tree, in predecessor order.
245 *
246 * @param node The current node.
247 * @return The previous node in the tree, or `NULL` if `node` is the first node.
248 */
249rbnode_t* rbtree_prev(const rbnode_t* node);
250
251/**
252 * @brief Iterates over a Red-Black Tree in ascending order.
253 *
254 * @param elem The loop variable, a pointer to the structure containing the tree node.
255 * @param tree A pointer to the `rbtree_t` structure to iterate over.
256 * @param member The name of the `rbnode_t` member within the structure `elem`.
257 */
258#define RBTREE_FOR_EACH(elem, tree, member) \
259 for ((elem) = \
260 ((tree)->root != NULL ? CONTAINER_OF(rbtree_find_min((tree)->root), typeof(*(elem)), member) : NULL); \
261 (elem) != NULL; (elem) = (rbtree_next(&(elem)->member) != NULL \
262 ? CONTAINER_OF(rbtree_next(&(elem)->member), typeof(*(elem)), member) \
263 : NULL))
264/**
265 * @brief Iterates over a Red-Black Tree in descending order.
266 *
267 * @param elem The loop variable, a pointer to the structure containing the tree node.
268 * @param tree A pointer to the `rbtree_t` structure to iterate over.
269 * @param member The name of the `rbnode_t` member within the structure `elem`.
270 */
271#define RBTREE_FOR_EACH_REVERSE(elem, tree, member) \
272 for ((elem) = \
273 ((tree)->root != NULL ? CONTAINER_OF(rbtree_find_max((tree)->root), typeof(*(elem)), member) : NULL); \
274 (elem) != NULL; (elem) = (rbtree_prev(&(elem)->member) != NULL \
275 ? CONTAINER_OF(rbtree_prev(&(elem)->member), typeof(*(elem)), member) \
276 : NULL))
277
278/** @} */
void(* rbnode_update_t)(rbnode_t *node)
Update function for Red-Black Tree nodes.
Definition rbtree.h:131
rbnode_t * rbtree_next(const rbnode_t *node)
Get the next node in the tree, in predecessor order.
Definition rbtree.c:559
int64_t(* rbnode_compare_t)(const rbnode_t *a, const rbnode_t *b)
Comparison function for Red-Black Tree nodes.
Definition rbtree.h:122
void rbtree_swap(rbtree_t *tree, rbnode_t *a, rbnode_t *b)
Swap two nodes in the Red-Black Tree.
Definition rbtree.c:214
rbnode_t * rbtree_find_min(rbnode_t *node)
Find the minimum node in a subtree.
Definition rbtree.c:184
rbnode_color_t
Red-Black Tree Node Colors.
Definition rbtree.h:50
rbnode_direction_t
Red-Black Tree Node Directions.
Definition rbtree.h:62
rbnode_t * rbtree_rotate(rbtree_t *tree, rbnode_t *node, rbnode_direction_t direction)
Rotate a node in the Red-Black Tree.
Definition rbtree.c:40
void rbtree_init(rbtree_t *tree, rbnode_compare_t compare, rbnode_update_t update)
Initialize a Red-Black Tree.
Definition rbtree.c:30
rbnode_t * rbtree_prev(const rbnode_t *node)
Get the previous node in the tree, in predecessor order.
Definition rbtree.c:581
void rbtree_remove(rbtree_t *tree, rbnode_t *node)
Remove a node from the Red-Black Tree.
Definition rbtree.c:370
void rbtree_insert(rbtree_t *tree, rbnode_t *node)
Insert a node into the Red-Black Tree.
Definition rbtree.c:149
rbnode_t * rbtree_find_max(rbnode_t *node)
Find the maximum node in a subtree.
Definition rbtree.c:199
void rbtree_fix(rbtree_t *tree, rbnode_t *node)
Move the node to its correct position in the Red-Black Tree.
Definition rbtree.c:526
bool rbtree_is_empty(const rbtree_t *tree)
Check if the Red-Black Tree is empty.
Definition rbtree.c:553
@ RBNODE_BLACK
Definition rbtree.h:52
@ RBNODE_RED
Definition rbtree.h:51
@ RBNODE_RIGHT
Definition rbtree.h:64
@ RBNODE_AMOUNT
Definition rbtree.h:65
@ RBNODE_LEFT
Definition rbtree.h:63
__INT64_TYPE__ int64_t
Definition stdint.h:16
Red-Black Tree Node.
Definition rbtree.h:93
rbnode_t * parent
Definition rbtree.h:94
rbnode_color_t color
Definition rbtree.h:96
Red-Black Tree.
Definition rbtree.h:138
rbnode_update_t update
Definition rbtree.h:141
rbnode_compare_t compare
Definition rbtree.h:140
rbnode_t * root
Definition rbtree.h:139