/src/fluent-bit/lib/monkey/deps/rbtree/rbtree.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 2013, Phil Vachon <phil@cowpig.ca> |
3 | | All rights reserved. |
4 | | |
5 | | Redistribution and use in source and binary forms, with or without |
6 | | modification, are permitted provided that the following conditions |
7 | | are met: |
8 | | |
9 | | - Redistributions of source code must retain the above copyright notice, |
10 | | this list of conditions and the following disclaimer. |
11 | | |
12 | | - Redistributions in binary form must reproduce the above copyright notice, |
13 | | this list of conditions and the following disclaimer in the documentation |
14 | | and/or other materials provided with the distribution. |
15 | | |
16 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
20 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
21 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
22 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
23 | | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
24 | | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
25 | | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
26 | | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | | */ |
28 | | |
29 | | /** \defgroup rb_tree_implementation Implementation Details |
30 | | * All the implementation details for the red-black tree, including functions for |
31 | | * the maintenance of tree properties. |
32 | | * @{ |
33 | | */ |
34 | | |
35 | | /** \file rbtree.c |
36 | | * An implementation of an intrusive red-black self-balancing tree, that can |
37 | | * be used to implement red-black trees in situations where memory allocation |
38 | | * is not an option. |
39 | | * |
40 | | * This file exclusively contains implementation details for the red-black tree, so |
41 | | * probably is not of much interest to most people. |
42 | | * |
43 | | * \see rbtree.h |
44 | | * \see rb_tree |
45 | | * \see rb_tree_node |
46 | | */ |
47 | | |
48 | | #include <rbtree.h> |
49 | | |
50 | | #include <stdlib.h> |
51 | | #include <string.h> |
52 | | |
53 | | /** \defgroup rb_tree_colors Colors for the red-black tree nodes |
54 | | * @{ |
55 | | */ |
56 | | |
57 | | /** |
58 | | * Node is black |
59 | | */ |
60 | 0 | #define COLOR_BLACK 0x0 |
61 | | |
62 | | /** |
63 | | * Node is red |
64 | | */ |
65 | 0 | #define COLOR_RED 0x1 |
66 | | /**@}*/ |
67 | | |
68 | | static |
69 | | int __rb_tree_cmp_mapper(void *state, const void *lhs, const void *rhs) |
70 | 0 | { |
71 | 0 | rb_cmp_func_t cmp = state; |
72 | 0 | return cmp(lhs, rhs); |
73 | 0 | } |
74 | | |
75 | | rb_result_t rb_tree_new_ex(struct rb_tree *tree, |
76 | | rb_cmp_func_ex_t compare, |
77 | | void *state) |
78 | 0 | { |
79 | 0 | rb_result_t ret = RB_OK; |
80 | |
|
81 | 0 | RB_ASSERT_ARG(tree != NULL); |
82 | 0 | RB_ASSERT_ARG(compare != NULL); |
83 | | |
84 | 0 | tree->root = NULL; |
85 | 0 | tree->compare = compare; |
86 | 0 | tree->state = state; |
87 | 0 | tree->rightmost = NULL; |
88 | |
|
89 | 0 | return ret; |
90 | 0 | } |
91 | | |
92 | | rb_result_t rb_tree_new(struct rb_tree *tree, |
93 | | rb_cmp_func_t compare) |
94 | 0 | { |
95 | 0 | RB_ASSERT_ARG(tree != NULL); |
96 | 0 | RB_ASSERT_ARG(compare != NULL); |
97 | | |
98 | 0 | return rb_tree_new_ex(tree, __rb_tree_cmp_mapper, (void *)compare); |
99 | 0 | } |
100 | | |
101 | | rb_result_t rb_tree_destroy(struct rb_tree *tree) |
102 | 0 | { |
103 | 0 | rb_result_t ret = RB_OK; |
104 | |
|
105 | 0 | RB_ASSERT_ARG(tree != NULL); |
106 | | |
107 | 0 | memset(tree, 0, sizeof(struct rb_tree)); |
108 | |
|
109 | 0 | return ret; |
110 | 0 | } |
111 | | |
112 | | rb_result_t rb_tree_empty(struct rb_tree *tree, |
113 | | int *is_empty) |
114 | 0 | { |
115 | 0 | rb_result_t ret = RB_OK; |
116 | |
|
117 | 0 | RB_ASSERT_ARG(tree != NULL); |
118 | 0 | RB_ASSERT_ARG(is_empty != NULL); |
119 | | |
120 | 0 | *is_empty = !!(tree->root == NULL); |
121 | |
|
122 | 0 | return ret; |
123 | 0 | } |
124 | | |
125 | | rb_result_t rb_tree_find(struct rb_tree *tree, |
126 | | const void *key, |
127 | | struct rb_tree_node **value) |
128 | 0 | { |
129 | 0 | rb_result_t ret = RB_OK; |
130 | |
|
131 | 0 | RB_ASSERT_ARG(tree != NULL); |
132 | 0 | RB_ASSERT_ARG(value != NULL); |
133 | | |
134 | 0 | *value = NULL; |
135 | |
|
136 | 0 | if (RB_UNLIKELY(tree->root == NULL)) { |
137 | 0 | ret = RB_NOT_FOUND; |
138 | 0 | goto done; |
139 | 0 | } |
140 | | |
141 | 0 | struct rb_tree_node *node = tree->root; |
142 | |
|
143 | 0 | while (node != NULL) { |
144 | 0 | int compare = tree->compare(tree->state, key, node->key); |
145 | |
|
146 | 0 | if (compare < 0) { |
147 | 0 | node = node->left; |
148 | 0 | } else if (compare == 0) { |
149 | 0 | break; /* We found our node */ |
150 | 0 | } else { |
151 | | /* Otherwise, we want the right node, and continue iteration */ |
152 | 0 | node = node->right; |
153 | 0 | } |
154 | 0 | } |
155 | |
|
156 | 0 | if (node == NULL) { |
157 | 0 | ret = RB_NOT_FOUND; |
158 | 0 | goto done; |
159 | 0 | } |
160 | | |
161 | | /* Return the node we found */ |
162 | 0 | *value = node; |
163 | |
|
164 | 0 | done: |
165 | 0 | return ret; |
166 | 0 | } |
167 | | |
168 | | /* Helper function to get a node's sibling */ |
169 | | static inline |
170 | | struct rb_tree_node *__helper_get_sibling(struct rb_tree_node *node) |
171 | 0 | { |
172 | 0 | if (node->parent == NULL) { |
173 | 0 | return NULL; |
174 | 0 | } |
175 | 0 |
|
176 | 0 | struct rb_tree_node *parent = node->parent; |
177 | 0 |
|
178 | 0 | if (node == parent->left) { |
179 | 0 | return parent->right; |
180 | 0 | } else { |
181 | 0 | return parent->left; |
182 | 0 | } |
183 | 0 | } |
184 | | |
185 | | /* Helper function to get a node's grandparent */ |
186 | | static inline |
187 | | struct rb_tree_node *__helper_get_grandparent(struct rb_tree_node *node) |
188 | 0 | { |
189 | 0 | if (node->parent == NULL) { |
190 | 0 | return NULL; |
191 | 0 | } |
192 | | |
193 | 0 | struct rb_tree_node *parent_node = node->parent; |
194 | |
|
195 | 0 | return parent_node->parent; |
196 | 0 | } |
197 | | |
198 | | /* Helper function to get a node's uncle */ |
199 | | static inline |
200 | | struct rb_tree_node *__helper_get_uncle(struct rb_tree_node *node) |
201 | 0 | { |
202 | 0 | struct rb_tree_node *grandparent = __helper_get_grandparent(node); |
203 | 0 |
|
204 | 0 | if (grandparent == NULL) { |
205 | 0 | return NULL; |
206 | 0 | } |
207 | 0 |
|
208 | 0 | if (node->parent == grandparent->left) { |
209 | 0 | return grandparent->right; |
210 | 0 | } else { |
211 | 0 | return grandparent->left; |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | | /* Helper function to do a left rotation of a given node */ |
216 | | static inline |
217 | | void __helper_rotate_left(struct rb_tree *tree, |
218 | | struct rb_tree_node *node) |
219 | 0 | { |
220 | 0 | struct rb_tree_node *x = node; |
221 | 0 | struct rb_tree_node *y = x->right; |
222 | |
|
223 | 0 | x->right = y->left; |
224 | |
|
225 | 0 | if (y->left != NULL) { |
226 | 0 | struct rb_tree_node *yleft = y->left; |
227 | 0 | yleft->parent = x; |
228 | 0 | } |
229 | |
|
230 | 0 | y->parent = x->parent; |
231 | |
|
232 | 0 | if (x->parent == NULL) { |
233 | 0 | tree->root = y; |
234 | 0 | } else { |
235 | 0 | struct rb_tree_node *xp = x->parent; |
236 | 0 | if (x == xp->left) { |
237 | 0 | xp->left = y; |
238 | 0 | } else { |
239 | 0 | xp->right = y; |
240 | 0 | } |
241 | 0 | } |
242 | |
|
243 | 0 | y->left = x; |
244 | 0 | x->parent = y; |
245 | 0 | } |
246 | | |
247 | | /* Helper function to do a right rotation of a given node */ |
248 | | static inline |
249 | | void __helper_rotate_right(struct rb_tree *tree, |
250 | | struct rb_tree_node *node) |
251 | 0 | { |
252 | 0 | struct rb_tree_node *x = node; |
253 | 0 | struct rb_tree_node *y = x->left; |
254 | |
|
255 | 0 | x->left = y->right; |
256 | |
|
257 | 0 | if (y->right != NULL) { |
258 | 0 | struct rb_tree_node *yright = y->right; |
259 | 0 | yright->parent = x; |
260 | 0 | } |
261 | |
|
262 | 0 | y->parent = x->parent; |
263 | |
|
264 | 0 | if (x->parent == NULL) { |
265 | 0 | tree->root = y; |
266 | 0 | } else { |
267 | 0 | struct rb_tree_node *xp = x->parent; |
268 | 0 | if (x == xp->left) { |
269 | 0 | xp->left = y; |
270 | 0 | } else { |
271 | 0 | xp->right = y; |
272 | 0 | } |
273 | 0 | } |
274 | |
|
275 | 0 | y->right = x; |
276 | 0 | x->parent = y; |
277 | 0 | } |
278 | | |
279 | | /* Function to perform a RB tree rebalancing after an insertion */ |
280 | | static |
281 | | void __helper_rb_tree_insert_rebalance(struct rb_tree *tree, |
282 | | struct rb_tree_node *node) |
283 | 0 | { |
284 | 0 | struct rb_tree_node *new_node_parent = node->parent; |
285 | |
|
286 | 0 | if (new_node_parent != NULL && new_node_parent->color != COLOR_BLACK) { |
287 | 0 | struct rb_tree_node *pnode = node; |
288 | | |
289 | | /* Iterate until we're at the root (which we just color black) or |
290 | | * until we the parent node is no longer red. |
291 | | */ |
292 | 0 | while ((tree->root != pnode) && (pnode->parent != NULL) && |
293 | 0 | (pnode->parent->color == COLOR_RED)) |
294 | 0 | { |
295 | 0 | struct rb_tree_node *parent = pnode->parent; |
296 | 0 | struct rb_tree_node *grandparent = __helper_get_grandparent(pnode); |
297 | 0 | struct rb_tree_node *uncle = NULL; |
298 | 0 | int uncle_is_left; |
299 | |
|
300 | 0 | assert(pnode->color == COLOR_RED); |
301 | | |
302 | 0 | if (parent == grandparent->left) { |
303 | 0 | uncle_is_left = 0; |
304 | 0 | uncle = grandparent->right; |
305 | 0 | } else { |
306 | 0 | uncle_is_left = 1; |
307 | 0 | uncle = grandparent->left; |
308 | 0 | } |
309 | | |
310 | | /* Case 1: Uncle is not black */ |
311 | 0 | if (uncle && uncle->color == COLOR_RED) { |
312 | | /* Color parent and uncle black */ |
313 | 0 | parent->color = COLOR_BLACK; |
314 | 0 | uncle->color = COLOR_BLACK; |
315 | | |
316 | | /* Color Grandparent as Black */ |
317 | 0 | grandparent->color = COLOR_RED; |
318 | 0 | pnode = grandparent; |
319 | | /* Continue iteration, processing grandparent */ |
320 | 0 | } else { |
321 | | /* Case 2 - node's parent is red, but uncle is black */ |
322 | 0 | if (!uncle_is_left && parent->right == pnode) { |
323 | 0 | pnode = pnode->parent; |
324 | 0 | __helper_rotate_left(tree, pnode); |
325 | 0 | } else if (uncle_is_left && parent->left == pnode) { |
326 | 0 | pnode = pnode->parent; |
327 | 0 | __helper_rotate_right(tree, pnode); |
328 | 0 | } |
329 | | |
330 | | /* Case 3 - Recolor and rotate*/ |
331 | 0 | parent = pnode->parent; |
332 | 0 | parent->color = COLOR_BLACK; |
333 | |
|
334 | 0 | grandparent = __helper_get_grandparent(pnode); |
335 | 0 | grandparent->color = COLOR_RED; |
336 | 0 | if (!uncle_is_left) { |
337 | 0 | __helper_rotate_right(tree, grandparent); |
338 | 0 | } else { |
339 | 0 | __helper_rotate_left(tree, grandparent); |
340 | 0 | } |
341 | 0 | } |
342 | 0 | } |
343 | | |
344 | | /* Make sure the tree root is black (Case 1: Continued) */ |
345 | 0 | struct rb_tree_node *tree_root = tree->root; |
346 | 0 | tree_root->color = COLOR_BLACK; |
347 | 0 | } |
348 | 0 | } |
349 | | |
350 | | rb_result_t rb_tree_insert(struct rb_tree *tree, |
351 | | const void *key, |
352 | | struct rb_tree_node *node) |
353 | 0 | { |
354 | 0 | rb_result_t ret = RB_OK; |
355 | |
|
356 | 0 | int rightmost = 1; |
357 | 0 | struct rb_tree_node *nd = NULL; |
358 | |
|
359 | 0 | RB_ASSERT_ARG(tree != NULL); |
360 | 0 | RB_ASSERT_ARG(node != NULL); |
361 | | |
362 | 0 | node->left = NULL; |
363 | 0 | node->right = NULL; |
364 | 0 | node->parent = NULL; |
365 | 0 | node->key = key; |
366 | | |
367 | | /* Case 1: Simplest case -- tree is empty */ |
368 | 0 | if (RB_UNLIKELY(tree->root == NULL)) { |
369 | 0 | tree->root = node; |
370 | 0 | tree->rightmost = node; |
371 | 0 | node->color = COLOR_BLACK; |
372 | 0 | goto done; |
373 | 0 | } |
374 | | |
375 | | /* Otherwise, insert the node as you would typically in a BST */ |
376 | 0 | nd = tree->root; |
377 | 0 | node->color = COLOR_RED; |
378 | |
|
379 | 0 | rightmost = 1; |
380 | | |
381 | | /* Insert a node into the tree as you normally would */ |
382 | 0 | while (nd != NULL) { |
383 | 0 | int compare = tree->compare(tree->state, node->key, nd->key); |
384 | |
|
385 | 0 | if (compare == 0) { |
386 | 0 | ret = RB_DUPLICATE; |
387 | 0 | goto done; |
388 | 0 | } |
389 | | |
390 | 0 | if (compare < 0) { |
391 | 0 | rightmost = 0; |
392 | 0 | if (nd->left == NULL) { |
393 | 0 | nd->left = node; |
394 | 0 | break; |
395 | 0 | } else { |
396 | 0 | nd = nd->left; |
397 | 0 | } |
398 | 0 | } else { |
399 | 0 | if (nd->right == NULL) { |
400 | 0 | nd->right = node; |
401 | 0 | break; |
402 | 0 | } else { |
403 | 0 | nd = nd->right; |
404 | 0 | } |
405 | 0 | } |
406 | 0 | } |
407 | | |
408 | 0 | node->parent = nd; |
409 | |
|
410 | 0 | if (1 == rightmost) { |
411 | 0 | tree->rightmost = node; |
412 | 0 | } |
413 | | |
414 | | /* Rebalance the tree about the node we just added */ |
415 | 0 | __helper_rb_tree_insert_rebalance(tree, node); |
416 | |
|
417 | 0 | done: |
418 | 0 | return ret; |
419 | 0 | } |
420 | | |
421 | | rb_result_t rb_tree_find_or_insert(struct rb_tree *tree, |
422 | | void *key, |
423 | | struct rb_tree_node *new_candidate, |
424 | | struct rb_tree_node **value) |
425 | 0 | { |
426 | 0 | rb_result_t ret = RB_OK; |
427 | |
|
428 | 0 | RB_ASSERT_ARG(tree != NULL); |
429 | 0 | RB_ASSERT_ARG(value != NULL); |
430 | 0 | RB_ASSERT_ARG(new_candidate != NULL); |
431 | | |
432 | 0 | *value = NULL; |
433 | 0 | new_candidate->key = key; |
434 | |
|
435 | 0 | struct rb_tree_node *node = tree->root; |
436 | | |
437 | | /* Case 1: Tree is empty, so we just insert the node */ |
438 | 0 | if (RB_UNLIKELY(tree->root == NULL)) { |
439 | 0 | tree->root = new_candidate; |
440 | 0 | tree->rightmost = new_candidate; |
441 | 0 | new_candidate->color = COLOR_BLACK; |
442 | 0 | node = new_candidate; |
443 | 0 | goto done; |
444 | 0 | } |
445 | | |
446 | 0 | struct rb_tree_node *node_prev = NULL; |
447 | 0 | int dir = 0, rightmost = 1; |
448 | 0 | while (node != NULL) { |
449 | 0 | int compare = tree->compare(tree->state, key, node->key); |
450 | |
|
451 | 0 | if (compare < 0) { |
452 | 0 | node_prev = node; |
453 | 0 | dir = 0; |
454 | 0 | node = node->left; |
455 | 0 | rightmost = 0; |
456 | 0 | } else if (compare == 0) { |
457 | 0 | break; /* We found our node */ |
458 | 0 | } else { |
459 | | /* Otherwise, we want the right node, and continue iteration */ |
460 | 0 | node_prev = node; |
461 | 0 | dir = 1; |
462 | 0 | node = node->right; |
463 | 0 | } |
464 | 0 | } |
465 | | |
466 | | /* Case 2 - we didn't find the node, so insert the candidate */ |
467 | 0 | if (node == NULL) { |
468 | 0 | if (dir == 0) { |
469 | 0 | rightmost = 0; |
470 | 0 | node_prev->left = new_candidate; |
471 | 0 | } else { |
472 | 0 | node_prev->right = new_candidate; |
473 | 0 | } |
474 | |
|
475 | 0 | new_candidate->parent = node_prev; |
476 | |
|
477 | 0 | node = new_candidate; |
478 | 0 | node->color = COLOR_RED; |
479 | |
|
480 | 0 | if (1 == rightmost) { |
481 | 0 | tree->rightmost = new_candidate; |
482 | 0 | } |
483 | | |
484 | | /* Rebalance the tree, preserving rb properties */ |
485 | 0 | __helper_rb_tree_insert_rebalance(tree, node); |
486 | 0 | } |
487 | |
|
488 | 0 | done: |
489 | | /* Return the node we found */ |
490 | 0 | *value = node; |
491 | |
|
492 | 0 | return ret; |
493 | 0 | } |
494 | | |
495 | | /** |
496 | | * Find the minimum of the subtree starting at node |
497 | | */ |
498 | | static |
499 | | struct rb_tree_node *__helper_rb_tree_find_minimum(struct rb_tree_node *node) |
500 | 0 | { |
501 | 0 | struct rb_tree_node *x = node; |
502 | |
|
503 | 0 | while (x->left != NULL) { |
504 | 0 | x = x->left; |
505 | 0 | } |
506 | |
|
507 | 0 | return x; |
508 | 0 | } |
509 | | |
510 | | static |
511 | | struct rb_tree_node *__helper_rb_tree_find_maximum(struct rb_tree_node *node) |
512 | 0 | { |
513 | 0 | struct rb_tree_node *x = node; |
514 | |
|
515 | 0 | while (x->right != NULL) { |
516 | 0 | x = x->right; |
517 | 0 | } |
518 | |
|
519 | 0 | return x; |
520 | 0 | } |
521 | | |
522 | | static |
523 | | struct rb_tree_node *__helper_rb_tree_find_successor(struct rb_tree_node *node) |
524 | 0 | { |
525 | 0 | struct rb_tree_node *x = node; |
526 | |
|
527 | 0 | if (x->right != NULL) { |
528 | 0 | return __helper_rb_tree_find_minimum(x->right); |
529 | 0 | } |
530 | | |
531 | 0 | struct rb_tree_node *y = x->parent; |
532 | |
|
533 | 0 | while (y != NULL && x == y->right) { |
534 | 0 | x = y; |
535 | 0 | y = y->parent; |
536 | 0 | } |
537 | |
|
538 | 0 | return y; |
539 | 0 | } |
540 | | |
541 | | static |
542 | | struct rb_tree_node *__helper_rb_tree_find_predecessor(struct rb_tree_node *node) |
543 | 0 | { |
544 | 0 | struct rb_tree_node *x = node; |
545 | |
|
546 | 0 | if (x->left != NULL) { |
547 | 0 | return __helper_rb_tree_find_maximum(x->left); |
548 | 0 | } |
549 | | |
550 | 0 | struct rb_tree_node *y = x->parent; |
551 | |
|
552 | 0 | while (y != NULL && x == y->left) { |
553 | 0 | x = y; |
554 | 0 | y = y->parent; |
555 | 0 | } |
556 | |
|
557 | 0 | return y; |
558 | 0 | } |
559 | | |
560 | | |
561 | | /* Replace x with y, inserting y where x previously was */ |
562 | | static |
563 | | void __helper_rb_tree_swap_node(struct rb_tree *tree, |
564 | | struct rb_tree_node *x, |
565 | | struct rb_tree_node *y) |
566 | 0 | { |
567 | 0 | struct rb_tree_node *left = x->left; |
568 | 0 | struct rb_tree_node *right = x->right; |
569 | 0 | struct rb_tree_node *parent = x->parent; |
570 | |
|
571 | 0 | y->parent = parent; |
572 | |
|
573 | 0 | if (parent != NULL) { |
574 | 0 | if (parent->left == x) { |
575 | 0 | parent->left = y; |
576 | 0 | } else { |
577 | 0 | parent->right = y; |
578 | 0 | } |
579 | 0 | } else { |
580 | 0 | if (tree->root == x) { |
581 | 0 | tree->root = y; |
582 | 0 | } |
583 | 0 | } |
584 | |
|
585 | 0 | y->right = right; |
586 | 0 | if (right != NULL) { |
587 | 0 | right->parent = y; |
588 | 0 | } |
589 | 0 | x->right = NULL; |
590 | |
|
591 | 0 | y->left = left; |
592 | 0 | if (left != NULL) { |
593 | 0 | left->parent = y; |
594 | 0 | } |
595 | 0 | x->left = NULL; |
596 | |
|
597 | 0 | y->color = x->color; |
598 | 0 | x->parent = NULL; |
599 | 0 | } |
600 | | |
601 | | static |
602 | | void __helper_rb_tree_delete_rebalance(struct rb_tree *tree, |
603 | | struct rb_tree_node *node, |
604 | | struct rb_tree_node *parent, |
605 | | int node_is_left) |
606 | 0 | { |
607 | 0 | struct rb_tree_node *x = node; |
608 | 0 | struct rb_tree_node *xp = parent; |
609 | 0 | int is_left = node_is_left; |
610 | |
|
611 | 0 | while (x != tree->root && (x == NULL || x->color == COLOR_BLACK)) { |
612 | 0 | struct rb_tree_node *w = is_left ? xp->right : xp->left; /* Sibling */ |
613 | |
|
614 | 0 | if (w != NULL && w->color == COLOR_RED) { |
615 | | /* Case 1: */ |
616 | 0 | w->color = COLOR_BLACK; |
617 | 0 | xp->color = COLOR_RED; |
618 | 0 | if (is_left) { |
619 | 0 | __helper_rotate_left(tree, xp); |
620 | 0 | } else { |
621 | 0 | __helper_rotate_right(tree, xp); |
622 | 0 | } |
623 | 0 | w = is_left ? xp->right : xp->left; |
624 | 0 | } |
625 | |
|
626 | 0 | struct rb_tree_node *wleft = w != NULL ? w->left : NULL; |
627 | 0 | struct rb_tree_node *wright = w != NULL ? w->right : NULL; |
628 | 0 | if ( (wleft == NULL || wleft->color == COLOR_BLACK) && |
629 | 0 | (wright == NULL || wright->color == COLOR_BLACK) ) |
630 | 0 | { |
631 | | /* Case 2: */ |
632 | 0 | if (w != NULL) { |
633 | 0 | w->color = COLOR_RED; |
634 | 0 | } |
635 | 0 | x = xp; |
636 | 0 | xp = x->parent; |
637 | 0 | is_left = xp && (x == xp->left); |
638 | 0 | } else { |
639 | 0 | if (is_left && (wright == NULL || wright->color == COLOR_BLACK)) { |
640 | | /* Case 3a: */ |
641 | 0 | w->color = COLOR_RED; |
642 | 0 | if (wleft) { |
643 | 0 | wleft->color = COLOR_BLACK; |
644 | 0 | } |
645 | 0 | __helper_rotate_right(tree, w); |
646 | 0 | w = xp->right; |
647 | 0 | } else if (!is_left && (wleft == NULL || wleft->color == COLOR_BLACK)) { |
648 | | /* Case 3b: */ |
649 | 0 | w->color = COLOR_RED; |
650 | 0 | if (wright) { |
651 | 0 | wright->color = COLOR_BLACK; |
652 | 0 | } |
653 | 0 | __helper_rotate_left(tree, w); |
654 | 0 | w = xp->left; |
655 | 0 | } |
656 | | |
657 | | /* Case 4: */ |
658 | 0 | wleft = w->left; |
659 | 0 | wright = w->right; |
660 | |
|
661 | 0 | w->color = xp->color; |
662 | 0 | xp->color = COLOR_BLACK; |
663 | |
|
664 | 0 | if (is_left && wright != NULL) { |
665 | 0 | wright->color = COLOR_BLACK; |
666 | 0 | __helper_rotate_left(tree, xp); |
667 | 0 | } else if (!is_left && wleft != NULL) { |
668 | 0 | wleft->color = COLOR_BLACK; |
669 | 0 | __helper_rotate_right(tree, xp); |
670 | 0 | } |
671 | 0 | x = tree->root; |
672 | 0 | } |
673 | 0 | } |
674 | |
|
675 | 0 | if (x != NULL) { |
676 | 0 | x->color = COLOR_BLACK; |
677 | 0 | } |
678 | 0 | } |
679 | | |
680 | | rb_result_t rb_tree_remove(struct rb_tree *tree, |
681 | | struct rb_tree_node *node) |
682 | 0 | { |
683 | 0 | rb_result_t ret = RB_OK; |
684 | |
|
685 | 0 | RB_ASSERT_ARG(tree != NULL); |
686 | 0 | RB_ASSERT_ARG(node != NULL); |
687 | | |
688 | 0 | struct rb_tree_node *y; |
689 | | |
690 | |
|
691 | 0 | if (node->left == NULL || node->right == NULL) { |
692 | 0 | y = node; |
693 | 0 | if (node == tree->rightmost) { |
694 | | /* The new rightmost item is our successor */ |
695 | 0 | tree->rightmost = __helper_rb_tree_find_predecessor(node); |
696 | 0 | } |
697 | 0 | } else { |
698 | 0 | y = __helper_rb_tree_find_successor(node); |
699 | 0 | } |
700 | |
|
701 | 0 | struct rb_tree_node *x, *xp; |
702 | |
|
703 | 0 | if (y->left != NULL) { |
704 | 0 | x = y->left; |
705 | 0 | } else { |
706 | 0 | x = y->right; |
707 | 0 | } |
708 | |
|
709 | 0 | if (x != NULL) { |
710 | 0 | x->parent = y->parent; |
711 | 0 | xp = x->parent; |
712 | 0 | } else { |
713 | 0 | xp = y->parent; |
714 | 0 | } |
715 | |
|
716 | 0 | int is_left = 0; |
717 | 0 | if (y->parent == NULL) { |
718 | 0 | tree->root = x; |
719 | 0 | xp = NULL; |
720 | 0 | } else { |
721 | 0 | struct rb_tree_node *yp = y->parent; |
722 | 0 | if (y == yp->left) { |
723 | 0 | yp->left = x; |
724 | 0 | is_left = 1; |
725 | 0 | } else { |
726 | 0 | yp->right = x; |
727 | 0 | is_left = 0; |
728 | 0 | } |
729 | 0 | } |
730 | |
|
731 | 0 | int y_color = y->color; |
732 | | |
733 | | /* Swap in the node */ |
734 | 0 | if (y != node) { |
735 | 0 | __helper_rb_tree_swap_node(tree, node, y); |
736 | 0 | if (xp == node) { |
737 | 0 | xp = y; |
738 | 0 | } |
739 | 0 | } |
740 | |
|
741 | 0 | if (y_color == COLOR_BLACK) { |
742 | 0 | __helper_rb_tree_delete_rebalance(tree, x, xp, is_left); |
743 | 0 | } |
744 | |
|
745 | 0 | node->parent = NULL; |
746 | 0 | node->left = NULL; |
747 | 0 | node->right = NULL; |
748 | |
|
749 | 0 | return ret; |
750 | 0 | } |
751 | | |
752 | | /** |
753 | | * \mainpage An Intrusive Red-Black Tree |
754 | | * |
755 | | * The goal of this implementation is to be both easy to use, but also |
756 | | * sufficiently powerful enough to perform all the operations that one might |
757 | | * typically want to do with a red-black tree. |
758 | | * |
759 | | * To make a structure usable with an rb_tree, you must embed the structure |
760 | | * struct rb_tree_node. |
761 | | * \code |
762 | | struct my_sample_struct { |
763 | | const char *name; |
764 | | int data; |
765 | | struct rb_tree_node rnode; |
766 | | }; |
767 | | * \endcode |
768 | | * \note `rb_tree_node` need not be initialized -- it is initialized during the |
769 | | * insertion operation. |
770 | | * |
771 | | * Next, you must declare a comparison function that, given a pointer to two |
772 | | * keys, returns a value less than 0 if the left-hand side is less than the |
773 | | * right-hand side, 0 if the left-hand side is equal to the right-hand side, |
774 | | * or greater than 0 if the left-hand side is greater than the left-hand side. |
775 | | * |
776 | | * A simple example for a string might use the `strcmp(3)` function directly, |
777 | | * as such: |
778 | | * |
779 | | * \code |
780 | | int my_sample_struct_compare_keys(void *lhs, void *rhs) |
781 | | { |
782 | | return strcmp((const char *)lhs, (const char *)rhs); |
783 | | } |
784 | | * \endcode |
785 | | * \note the function you create for your comparison function must conform to |
786 | | * rb_cmp_func_t, or the compiler will generate a warning and, if you're |
787 | | * unlucky, you will fail catastrophically at a later date. |
788 | | * |
789 | | * Then, to create a new, empty red-black tree, call rb_tree_new, as so: |
790 | | * \code |
791 | | struct rb_tree my_rb_tree; |
792 | | if (rb_tree_new(&my_rb_tree, my_sample_struct_compare_keys) != RB_OK) { |
793 | | exit(EXIT_FAILURE); |
794 | | } |
795 | | * \endcode |
796 | | * |
797 | | * Items can be added to the red-black tree using the function `rb_tree_insert`: |
798 | | * \code |
799 | | struct my_sample_struct node = { .name = "test1", .date = 42 }; |
800 | | if (rb_tree_insert(&my_rb_tree, node.name, &(node.rnode)) != RB_OK) { |
801 | | printf("Failed to insert a node into the RB tree!\n"); |
802 | | exit(EXIT_FAILURE); |
803 | | } |
804 | | * \endcode |
805 | | * |
806 | | * \see rb_tree |
807 | | * \see rb_tree_node |
808 | | * \see rb_functions |
809 | | * \see rbtree.h |
810 | | */ |
811 | | |