PatchworkOS  2ca1c69
A non-POSIX operating system.
Loading...
Searching...
No Matches
rbtree.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/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 */
144
145/**
146 * @brief Initialize a Red-Black Tree.
147 *
148 * Will not allocate any memory.
149 *
150 * @param tree The tree to initialize.
151 * @param compare The comparison function to use.
152 * @param update The update function to use, or `NULL`.
153 */
154void rbtree_init(rbtree_t* tree, rbnode_compare_t compare, rbnode_update_t update);
155
156/**
157 * @brief Rotate a node in the Red-Black Tree.
158 *
159 * @see https://upload.wikimedia.org/wikipedia/commons/f/f2/Binary_Tree_Rotation_%28animated%29.gif for a animation of
160 * tree rotations.
161 *
162 * @param tree The tree containing the node to rotate.
163 * @param node The node to rotate.
164 * @param direction The direction to rotate.
165 * @return The new root of the rotated subtree.
166 */
168
169/**
170 * @brief Find the minimum node in a subtree.
171 *
172 * This is the same as just going as far left as possible.
173 *
174 * @param node The root of the subtree.
175 * @return The minimum node in the subtree.
176 */
178
179/**
180 * @brief Find the maximum node in a subtree.
181 *
182 * This is the same as just going as far right as possible.
183 *
184 * @param node The root of the subtree.
185 * @return The maximum node in the subtree.
186 */
188
189/**
190 * @brief Swap two nodes in the Red-Black Tree.
191 *
192 * Needed as the structure is intrusive, so we can't just swap the data.
193 *
194 * @param tree The tree containing the nodes to swap.
195 * @param a The first node to swap.
196 * @param b The second node to swap.
197 */
198void rbtree_swap(rbtree_t* tree, rbnode_t* a, rbnode_t* b);
199
200/**
201 * @brief Insert a node into the Red-Black Tree.
202 *
203 * @param tree The tree to insert into.
204 * @param node The node to insert.
205 */
206void rbtree_insert(rbtree_t* tree, rbnode_t* node);
207
208/**
209 * @brief Remove a node from the Red-Black Tree.
210 *
211 * @param tree The tree to remove from.
212 * @param node The node to remove.
213 */
214void rbtree_remove(rbtree_t* tree, rbnode_t* node);
215
216/**
217 * @brief Move the node to its correct position in the Red-Black Tree.
218 *
219 * Should be called whenever the metric used for comparison changes.
220 *
221 * @todo Currently just calls `rbtree_remove()` followed by `rbtree_insert()`, could be optimized?
222 *
223 * @param tree The tree containing the node to update.
224 * @param node The node to update.
225 */
226void rbtree_fix(rbtree_t* tree, rbnode_t* node);
227
228/**
229 * @brief Check if the Red-Black Tree is empty.
230 *
231 * @param tree The tree to check.
232 * @return `true` if the tree is empty, `false` otherwise.
233 */
234bool rbtree_is_empty(const rbtree_t* tree);
235
236/**
237 * @brief Get the next node in the tree, in predecessor order.
238 *
239 * @param node The current node.
240 * @return The next node in the tree, or `NULL` if `node` is the last node.
241 */
242rbnode_t* rbtree_next(const rbnode_t* node);
243
244/**
245 * @brief Get the previous node in the tree, in predecessor order.
246 *
247 * @param node The current node.
248 * @return The previous node in the tree, or `NULL` if `node` is the first node.
249 */
250rbnode_t* rbtree_prev(const rbnode_t* node);
251
252/**
253 * @brief Iterates over a Red-Black Tree in ascending order.
254 *
255 * @param elem The loop variable, a pointer to the structure containing the tree node.
256 * @param tree A pointer to the `rbtree_t` structure to iterate over.
257 * @param member The name of the `rbnode_t` member within the structure `elem`.
258 */
259#define RBTREE_FOR_EACH(elem, tree, member) \
260 for ((elem) = \
261 ((tree)->root != NULL ? CONTAINER_OF(rbtree_find_min((tree)->root), typeof(*(elem)), member) : NULL); \
262 (elem) != NULL; (elem) = (rbtree_next(&(elem)->member) != NULL \
263 ? CONTAINER_OF(rbtree_next(&(elem)->member), typeof(*(elem)), member) \
264 : NULL))
265/**
266 * @brief Iterates over a Red-Black Tree in descending order.
267 *
268 * @param elem The loop variable, a pointer to the structure containing the tree node.
269 * @param tree A pointer to the `rbtree_t` structure to iterate over.
270 * @param member The name of the `rbnode_t` member within the structure `elem`.
271 */
272#define RBTREE_FOR_EACH_REVERSE(elem, tree, member) \
273 for ((elem) = \
274 ((tree)->root != NULL ? CONTAINER_OF(rbtree_find_max((tree)->root), typeof(*(elem)), member) : NULL); \
275 (elem) != NULL; (elem) = (rbtree_prev(&(elem)->member) != NULL \
276 ? CONTAINER_OF(rbtree_prev(&(elem)->member), typeof(*(elem)), member) \
277 : NULL))
278
279/** @} */
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:546
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:216
rbnode_t * rbtree_find_min(rbnode_t *node)
Find the minimum node in a subtree.
Definition rbtree.c:186
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:41
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:568
void rbtree_remove(rbtree_t *tree, rbnode_t *node)
Remove a node from the Red-Black Tree.
Definition rbtree.c:374
void rbtree_insert(rbtree_t *tree, rbnode_t *node)
Insert a node into the Red-Black Tree.
Definition rbtree.c:150
rbnode_t * rbtree_find_max(rbnode_t *node)
Find the maximum node in a subtree.
Definition rbtree.c:201
void rbtree_fix(rbtree_t *tree, rbnode_t *node)
Move the node to its correct position in the Red-Black Tree.
Definition rbtree.c:530
bool rbtree_is_empty(const rbtree_t *tree)
Check if the Red-Black Tree is empty.
Definition rbtree.c:539
@ 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
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__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:142
rbnode_compare_t compare
Definition rbtree.h:141
uint64_t size
Definition rbtree.h:140
rbnode_t * root
Definition rbtree.h:139