1933707f3Ssthen /*
2933707f3Ssthen * rbtree.c -- generic red black tree
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2001-2007, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen *
35933707f3Ssthen */
36933707f3Ssthen
37933707f3Ssthen /**
38933707f3Ssthen * \file
39933707f3Ssthen * Implementation of a redblack tree.
40933707f3Ssthen */
41933707f3Ssthen
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include "log.h"
44933707f3Ssthen #include "fptr_wlist.h"
45933707f3Ssthen #include "util/rbtree.h"
46933707f3Ssthen
47933707f3Ssthen /** Node colour black */
48933707f3Ssthen #define BLACK 0
49933707f3Ssthen /** Node colour red */
50933707f3Ssthen #define RED 1
51933707f3Ssthen
52933707f3Ssthen /** the NULL node, global alloc */
53*77079be7Ssthen rbnode_type rbtree_null_node = {
54933707f3Ssthen RBTREE_NULL, /* Parent. */
55933707f3Ssthen RBTREE_NULL, /* Left. */
56933707f3Ssthen RBTREE_NULL, /* Right. */
57933707f3Ssthen NULL, /* Key. */
58933707f3Ssthen BLACK /* Color. */
59933707f3Ssthen };
60933707f3Ssthen
61933707f3Ssthen /** rotate subtree left (to preserve redblack property) */
62*77079be7Ssthen static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node);
63933707f3Ssthen /** rotate subtree right (to preserve redblack property) */
64*77079be7Ssthen static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node);
65933707f3Ssthen /** Fixup node colours when insert happened */
66*77079be7Ssthen static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node);
67933707f3Ssthen /** Fixup node colours when delete happened */
68*77079be7Ssthen static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child,
69*77079be7Ssthen rbnode_type* child_parent);
70933707f3Ssthen
71933707f3Ssthen /*
724bfc71b0Ssthen * Creates a new red black tree, initializes and returns a pointer to it.
73933707f3Ssthen *
74933707f3Ssthen * Return NULL on failure.
75933707f3Ssthen *
76933707f3Ssthen */
77*77079be7Ssthen rbtree_type *
rbtree_create(int (* cmpf)(const void *,const void *))78933707f3Ssthen rbtree_create (int (*cmpf)(const void *, const void *))
79933707f3Ssthen {
80*77079be7Ssthen rbtree_type *rbtree;
81933707f3Ssthen
82933707f3Ssthen /* Allocate memory for it */
83*77079be7Ssthen rbtree = (rbtree_type *) malloc(sizeof(rbtree_type));
84933707f3Ssthen if (!rbtree) {
85933707f3Ssthen return NULL;
86933707f3Ssthen }
87933707f3Ssthen
88933707f3Ssthen /* Initialize it */
89933707f3Ssthen rbtree_init(rbtree, cmpf);
90933707f3Ssthen
91933707f3Ssthen return rbtree;
92933707f3Ssthen }
93933707f3Ssthen
94933707f3Ssthen void
rbtree_init(rbtree_type * rbtree,int (* cmpf)(const void *,const void *))95*77079be7Ssthen rbtree_init(rbtree_type *rbtree, int (*cmpf)(const void *, const void *))
96933707f3Ssthen {
97933707f3Ssthen /* Initialize it */
98933707f3Ssthen rbtree->root = RBTREE_NULL;
99933707f3Ssthen rbtree->count = 0;
100933707f3Ssthen rbtree->cmp = cmpf;
101933707f3Ssthen }
102933707f3Ssthen
103933707f3Ssthen /*
104933707f3Ssthen * Rotates the node to the left.
105933707f3Ssthen *
106933707f3Ssthen */
107933707f3Ssthen static void
rbtree_rotate_left(rbtree_type * rbtree,rbnode_type * node)108*77079be7Ssthen rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node)
109933707f3Ssthen {
110*77079be7Ssthen rbnode_type *right = node->right;
111933707f3Ssthen node->right = right->left;
112933707f3Ssthen if (right->left != RBTREE_NULL)
113933707f3Ssthen right->left->parent = node;
114933707f3Ssthen
115933707f3Ssthen right->parent = node->parent;
116933707f3Ssthen
117933707f3Ssthen if (node->parent != RBTREE_NULL) {
118933707f3Ssthen if (node == node->parent->left) {
119933707f3Ssthen node->parent->left = right;
120933707f3Ssthen } else {
121933707f3Ssthen node->parent->right = right;
122933707f3Ssthen }
123933707f3Ssthen } else {
124933707f3Ssthen rbtree->root = right;
125933707f3Ssthen }
126933707f3Ssthen right->left = node;
127933707f3Ssthen node->parent = right;
128933707f3Ssthen }
129933707f3Ssthen
130933707f3Ssthen /*
131933707f3Ssthen * Rotates the node to the right.
132933707f3Ssthen *
133933707f3Ssthen */
134933707f3Ssthen static void
rbtree_rotate_right(rbtree_type * rbtree,rbnode_type * node)135*77079be7Ssthen rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node)
136933707f3Ssthen {
137*77079be7Ssthen rbnode_type *left = node->left;
138933707f3Ssthen node->left = left->right;
139933707f3Ssthen if (left->right != RBTREE_NULL)
140933707f3Ssthen left->right->parent = node;
141933707f3Ssthen
142933707f3Ssthen left->parent = node->parent;
143933707f3Ssthen
144933707f3Ssthen if (node->parent != RBTREE_NULL) {
145933707f3Ssthen if (node == node->parent->right) {
146933707f3Ssthen node->parent->right = left;
147933707f3Ssthen } else {
148933707f3Ssthen node->parent->left = left;
149933707f3Ssthen }
150933707f3Ssthen } else {
151933707f3Ssthen rbtree->root = left;
152933707f3Ssthen }
153933707f3Ssthen left->right = node;
154933707f3Ssthen node->parent = left;
155933707f3Ssthen }
156933707f3Ssthen
157933707f3Ssthen static void
rbtree_insert_fixup(rbtree_type * rbtree,rbnode_type * node)158*77079be7Ssthen rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node)
159933707f3Ssthen {
160*77079be7Ssthen rbnode_type *uncle;
161933707f3Ssthen
162933707f3Ssthen /* While not at the root and need fixing... */
163933707f3Ssthen while (node != rbtree->root && node->parent->color == RED) {
164933707f3Ssthen /* If our parent is left child of our grandparent... */
165933707f3Ssthen if (node->parent == node->parent->parent->left) {
166933707f3Ssthen uncle = node->parent->parent->right;
167933707f3Ssthen
168933707f3Ssthen /* If our uncle is red... */
169933707f3Ssthen if (uncle->color == RED) {
170933707f3Ssthen /* Paint the parent and the uncle black... */
171933707f3Ssthen node->parent->color = BLACK;
172933707f3Ssthen uncle->color = BLACK;
173933707f3Ssthen
174933707f3Ssthen /* And the grandparent red... */
175933707f3Ssthen node->parent->parent->color = RED;
176933707f3Ssthen
177933707f3Ssthen /* And continue fixing the grandparent */
178933707f3Ssthen node = node->parent->parent;
179933707f3Ssthen } else { /* Our uncle is black... */
180933707f3Ssthen /* Are we the right child? */
181933707f3Ssthen if (node == node->parent->right) {
182933707f3Ssthen node = node->parent;
183933707f3Ssthen rbtree_rotate_left(rbtree, node);
184933707f3Ssthen }
185933707f3Ssthen /* Now we're the left child, repaint and rotate... */
186933707f3Ssthen node->parent->color = BLACK;
187933707f3Ssthen node->parent->parent->color = RED;
188933707f3Ssthen rbtree_rotate_right(rbtree, node->parent->parent);
189933707f3Ssthen }
190933707f3Ssthen } else {
191933707f3Ssthen uncle = node->parent->parent->left;
192933707f3Ssthen
193933707f3Ssthen /* If our uncle is red... */
194933707f3Ssthen if (uncle->color == RED) {
195933707f3Ssthen /* Paint the parent and the uncle black... */
196933707f3Ssthen node->parent->color = BLACK;
197933707f3Ssthen uncle->color = BLACK;
198933707f3Ssthen
199933707f3Ssthen /* And the grandparent red... */
200933707f3Ssthen node->parent->parent->color = RED;
201933707f3Ssthen
202933707f3Ssthen /* And continue fixing the grandparent */
203933707f3Ssthen node = node->parent->parent;
204933707f3Ssthen } else { /* Our uncle is black... */
205933707f3Ssthen /* Are we the right child? */
206933707f3Ssthen if (node == node->parent->left) {
207933707f3Ssthen node = node->parent;
208933707f3Ssthen rbtree_rotate_right(rbtree, node);
209933707f3Ssthen }
210933707f3Ssthen /* Now we're the right child, repaint and rotate... */
211933707f3Ssthen node->parent->color = BLACK;
212933707f3Ssthen node->parent->parent->color = RED;
213933707f3Ssthen rbtree_rotate_left(rbtree, node->parent->parent);
214933707f3Ssthen }
215933707f3Ssthen }
216933707f3Ssthen }
217933707f3Ssthen rbtree->root->color = BLACK;
218933707f3Ssthen }
219933707f3Ssthen
220933707f3Ssthen
221933707f3Ssthen /*
222933707f3Ssthen * Inserts a node into a red black tree.
223933707f3Ssthen *
224933707f3Ssthen * Returns NULL on failure or the pointer to the newly added node
225933707f3Ssthen * otherwise.
226933707f3Ssthen */
227*77079be7Ssthen rbnode_type *
rbtree_insert(rbtree_type * rbtree,rbnode_type * data)228*77079be7Ssthen rbtree_insert (rbtree_type *rbtree, rbnode_type *data)
229933707f3Ssthen {
230933707f3Ssthen /* XXX Not necessary, but keeps compiler quiet... */
231933707f3Ssthen int r = 0;
232933707f3Ssthen
233933707f3Ssthen /* We start at the root of the tree */
234*77079be7Ssthen rbnode_type *node = rbtree->root;
235*77079be7Ssthen rbnode_type *parent = RBTREE_NULL;
236933707f3Ssthen
237933707f3Ssthen fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
238933707f3Ssthen /* Lets find the new parent... */
239933707f3Ssthen while (node != RBTREE_NULL) {
240933707f3Ssthen /* Compare two keys, do we have a duplicate? */
241933707f3Ssthen if ((r = rbtree->cmp(data->key, node->key)) == 0) {
242933707f3Ssthen return NULL;
243933707f3Ssthen }
244933707f3Ssthen parent = node;
245933707f3Ssthen
246933707f3Ssthen if (r < 0) {
247933707f3Ssthen node = node->left;
248933707f3Ssthen } else {
249933707f3Ssthen node = node->right;
250933707f3Ssthen }
251933707f3Ssthen }
252933707f3Ssthen
253933707f3Ssthen /* Initialize the new node */
254933707f3Ssthen data->parent = parent;
255933707f3Ssthen data->left = data->right = RBTREE_NULL;
256933707f3Ssthen data->color = RED;
257933707f3Ssthen rbtree->count++;
258933707f3Ssthen
259933707f3Ssthen /* Insert it into the tree... */
260933707f3Ssthen if (parent != RBTREE_NULL) {
261933707f3Ssthen if (r < 0) {
262933707f3Ssthen parent->left = data;
263933707f3Ssthen } else {
264933707f3Ssthen parent->right = data;
265933707f3Ssthen }
266933707f3Ssthen } else {
267933707f3Ssthen rbtree->root = data;
268933707f3Ssthen }
269933707f3Ssthen
270933707f3Ssthen /* Fix up the red-black properties... */
271933707f3Ssthen rbtree_insert_fixup(rbtree, data);
272933707f3Ssthen
273933707f3Ssthen return data;
274933707f3Ssthen }
275933707f3Ssthen
276933707f3Ssthen /*
277933707f3Ssthen * Searches the red black tree, returns the data if key is found or NULL otherwise.
278933707f3Ssthen *
279933707f3Ssthen */
280*77079be7Ssthen rbnode_type *
rbtree_search(rbtree_type * rbtree,const void * key)281*77079be7Ssthen rbtree_search (rbtree_type *rbtree, const void *key)
282933707f3Ssthen {
283*77079be7Ssthen rbnode_type *node;
284933707f3Ssthen
285933707f3Ssthen if (rbtree_find_less_equal(rbtree, key, &node)) {
286933707f3Ssthen return node;
287933707f3Ssthen } else {
288933707f3Ssthen return NULL;
289933707f3Ssthen }
290933707f3Ssthen }
291933707f3Ssthen
292933707f3Ssthen /** helpers for delete: swap node colours */
swap_int8(uint8_t * x,uint8_t * y)293933707f3Ssthen static void swap_int8(uint8_t* x, uint8_t* y)
294933707f3Ssthen {
295933707f3Ssthen uint8_t t = *x; *x = *y; *y = t;
296933707f3Ssthen }
297933707f3Ssthen
298933707f3Ssthen /** helpers for delete: swap node pointers */
swap_np(rbnode_type ** x,rbnode_type ** y)299*77079be7Ssthen static void swap_np(rbnode_type** x, rbnode_type** y)
300933707f3Ssthen {
301*77079be7Ssthen rbnode_type* t = *x; *x = *y; *y = t;
302933707f3Ssthen }
303933707f3Ssthen
304933707f3Ssthen /** Update parent pointers of child trees of 'parent' */
change_parent_ptr(rbtree_type * rbtree,rbnode_type * parent,rbnode_type * old,rbnode_type * new)305*77079be7Ssthen static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent,
306*77079be7Ssthen rbnode_type* old, rbnode_type* new)
307933707f3Ssthen {
308933707f3Ssthen if(parent == RBTREE_NULL)
309933707f3Ssthen {
310933707f3Ssthen log_assert(rbtree->root == old);
311933707f3Ssthen if(rbtree->root == old) rbtree->root = new;
312933707f3Ssthen return;
313933707f3Ssthen }
314933707f3Ssthen log_assert(parent->left == old || parent->right == old
315933707f3Ssthen || parent->left == new || parent->right == new);
316933707f3Ssthen if(parent->left == old) parent->left = new;
317933707f3Ssthen if(parent->right == old) parent->right = new;
318933707f3Ssthen }
319933707f3Ssthen /** Update parent pointer of a node 'child' */
change_child_ptr(rbnode_type * child,rbnode_type * old,rbnode_type * new)320*77079be7Ssthen static void change_child_ptr(rbnode_type* child, rbnode_type* old,
321*77079be7Ssthen rbnode_type* new)
322933707f3Ssthen {
323933707f3Ssthen if(child == RBTREE_NULL) return;
324933707f3Ssthen log_assert(child->parent == old || child->parent == new);
325933707f3Ssthen if(child->parent == old) child->parent = new;
326933707f3Ssthen }
327933707f3Ssthen
328*77079be7Ssthen rbnode_type*
rbtree_delete(rbtree_type * rbtree,const void * key)329*77079be7Ssthen rbtree_delete(rbtree_type *rbtree, const void *key)
330933707f3Ssthen {
331*77079be7Ssthen rbnode_type *to_delete;
332*77079be7Ssthen rbnode_type *child;
333933707f3Ssthen if((to_delete = rbtree_search(rbtree, key)) == 0) return 0;
334933707f3Ssthen rbtree->count--;
335933707f3Ssthen
336933707f3Ssthen /* make sure we have at most one non-leaf child */
337933707f3Ssthen if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
338933707f3Ssthen {
339933707f3Ssthen /* swap with smallest from right subtree (or largest from left) */
340*77079be7Ssthen rbnode_type *smright = to_delete->right;
341933707f3Ssthen while(smright->left != RBTREE_NULL)
342933707f3Ssthen smright = smright->left;
343933707f3Ssthen /* swap the smright and to_delete elements in the tree,
344*77079be7Ssthen * but the rbnode_type is first part of user data struct
345933707f3Ssthen * so cannot just swap the keys and data pointers. Instead
346933707f3Ssthen * readjust the pointers left,right,parent */
347933707f3Ssthen
348933707f3Ssthen /* swap colors - colors are tied to the position in the tree */
349933707f3Ssthen swap_int8(&to_delete->color, &smright->color);
350933707f3Ssthen
351933707f3Ssthen /* swap child pointers in parents of smright/to_delete */
352933707f3Ssthen change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
353933707f3Ssthen if(to_delete->right != smright)
354933707f3Ssthen change_parent_ptr(rbtree, smright->parent, smright, to_delete);
355933707f3Ssthen
356933707f3Ssthen /* swap parent pointers in children of smright/to_delete */
357933707f3Ssthen change_child_ptr(smright->left, smright, to_delete);
358933707f3Ssthen change_child_ptr(smright->left, smright, to_delete);
359933707f3Ssthen change_child_ptr(smright->right, smright, to_delete);
360933707f3Ssthen change_child_ptr(smright->right, smright, to_delete);
361933707f3Ssthen change_child_ptr(to_delete->left, to_delete, smright);
362933707f3Ssthen if(to_delete->right != smright)
363933707f3Ssthen change_child_ptr(to_delete->right, to_delete, smright);
364933707f3Ssthen if(to_delete->right == smright)
365933707f3Ssthen {
366933707f3Ssthen /* set up so after swap they work */
367933707f3Ssthen to_delete->right = to_delete;
368933707f3Ssthen smright->parent = smright;
369933707f3Ssthen }
370933707f3Ssthen
371933707f3Ssthen /* swap pointers in to_delete/smright nodes */
372933707f3Ssthen swap_np(&to_delete->parent, &smright->parent);
373933707f3Ssthen swap_np(&to_delete->left, &smright->left);
374933707f3Ssthen swap_np(&to_delete->right, &smright->right);
375933707f3Ssthen
376933707f3Ssthen /* now delete to_delete (which is at the location where the smright previously was) */
377933707f3Ssthen }
378933707f3Ssthen log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
379933707f3Ssthen
380933707f3Ssthen if(to_delete->left != RBTREE_NULL) child = to_delete->left;
381933707f3Ssthen else child = to_delete->right;
382933707f3Ssthen
383933707f3Ssthen /* unlink to_delete from the tree, replace to_delete with child */
384933707f3Ssthen change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
385933707f3Ssthen change_child_ptr(child, to_delete, to_delete->parent);
386933707f3Ssthen
387933707f3Ssthen if(to_delete->color == RED)
388933707f3Ssthen {
389933707f3Ssthen /* if node is red then the child (black) can be swapped in */
390933707f3Ssthen }
391933707f3Ssthen else if(child->color == RED)
392933707f3Ssthen {
393933707f3Ssthen /* change child to BLACK, removing a RED node is no problem */
394933707f3Ssthen if(child!=RBTREE_NULL) child->color = BLACK;
395933707f3Ssthen }
396933707f3Ssthen else rbtree_delete_fixup(rbtree, child, to_delete->parent);
397933707f3Ssthen
398933707f3Ssthen /* unlink completely */
399933707f3Ssthen to_delete->parent = RBTREE_NULL;
400933707f3Ssthen to_delete->left = RBTREE_NULL;
401933707f3Ssthen to_delete->right = RBTREE_NULL;
402933707f3Ssthen to_delete->color = BLACK;
403933707f3Ssthen return to_delete;
404933707f3Ssthen }
405933707f3Ssthen
rbtree_delete_fixup(rbtree_type * rbtree,rbnode_type * child,rbnode_type * child_parent)406*77079be7Ssthen static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child,
407*77079be7Ssthen rbnode_type* child_parent)
408933707f3Ssthen {
409*77079be7Ssthen rbnode_type* sibling;
410933707f3Ssthen int go_up = 1;
411933707f3Ssthen
412933707f3Ssthen /* determine sibling to the node that is one-black short */
413933707f3Ssthen if(child_parent->right == child) sibling = child_parent->left;
414933707f3Ssthen else sibling = child_parent->right;
415933707f3Ssthen
416933707f3Ssthen while(go_up)
417933707f3Ssthen {
418933707f3Ssthen if(child_parent == RBTREE_NULL)
419933707f3Ssthen {
420933707f3Ssthen /* removed parent==black from root, every path, so ok */
421933707f3Ssthen return;
422933707f3Ssthen }
423933707f3Ssthen
424933707f3Ssthen if(sibling->color == RED)
425933707f3Ssthen { /* rotate to get a black sibling */
426933707f3Ssthen child_parent->color = RED;
427933707f3Ssthen sibling->color = BLACK;
428933707f3Ssthen if(child_parent->right == child)
429933707f3Ssthen rbtree_rotate_right(rbtree, child_parent);
430933707f3Ssthen else rbtree_rotate_left(rbtree, child_parent);
431933707f3Ssthen /* new sibling after rotation */
432933707f3Ssthen if(child_parent->right == child) sibling = child_parent->left;
433933707f3Ssthen else sibling = child_parent->right;
434933707f3Ssthen }
435933707f3Ssthen
436933707f3Ssthen if(child_parent->color == BLACK
437933707f3Ssthen && sibling->color == BLACK
438933707f3Ssthen && sibling->left->color == BLACK
439933707f3Ssthen && sibling->right->color == BLACK)
440933707f3Ssthen { /* fixup local with recolor of sibling */
441933707f3Ssthen if(sibling != RBTREE_NULL)
442933707f3Ssthen sibling->color = RED;
443933707f3Ssthen
444933707f3Ssthen child = child_parent;
445933707f3Ssthen child_parent = child_parent->parent;
446933707f3Ssthen /* prepare to go up, new sibling */
447933707f3Ssthen if(child_parent->right == child) sibling = child_parent->left;
448933707f3Ssthen else sibling = child_parent->right;
449933707f3Ssthen }
450933707f3Ssthen else go_up = 0;
451933707f3Ssthen }
452933707f3Ssthen
453933707f3Ssthen if(child_parent->color == RED
454933707f3Ssthen && sibling->color == BLACK
455933707f3Ssthen && sibling->left->color == BLACK
456933707f3Ssthen && sibling->right->color == BLACK)
457933707f3Ssthen {
458933707f3Ssthen /* move red to sibling to rebalance */
459933707f3Ssthen if(sibling != RBTREE_NULL)
460933707f3Ssthen sibling->color = RED;
461933707f3Ssthen child_parent->color = BLACK;
462933707f3Ssthen return;
463933707f3Ssthen }
464933707f3Ssthen log_assert(sibling != RBTREE_NULL);
465933707f3Ssthen
466933707f3Ssthen /* get a new sibling, by rotating at sibling. See which child
467933707f3Ssthen of sibling is red */
468933707f3Ssthen if(child_parent->right == child
469933707f3Ssthen && sibling->color == BLACK
470933707f3Ssthen && sibling->right->color == RED
471933707f3Ssthen && sibling->left->color == BLACK)
472933707f3Ssthen {
473933707f3Ssthen sibling->color = RED;
474933707f3Ssthen sibling->right->color = BLACK;
475933707f3Ssthen rbtree_rotate_left(rbtree, sibling);
476933707f3Ssthen /* new sibling after rotation */
477933707f3Ssthen if(child_parent->right == child) sibling = child_parent->left;
478933707f3Ssthen else sibling = child_parent->right;
479933707f3Ssthen }
480933707f3Ssthen else if(child_parent->left == child
481933707f3Ssthen && sibling->color == BLACK
482933707f3Ssthen && sibling->left->color == RED
483933707f3Ssthen && sibling->right->color == BLACK)
484933707f3Ssthen {
485933707f3Ssthen sibling->color = RED;
486933707f3Ssthen sibling->left->color = BLACK;
487933707f3Ssthen rbtree_rotate_right(rbtree, sibling);
488933707f3Ssthen /* new sibling after rotation */
489933707f3Ssthen if(child_parent->right == child) sibling = child_parent->left;
490933707f3Ssthen else sibling = child_parent->right;
491933707f3Ssthen }
492933707f3Ssthen
493933707f3Ssthen /* now we have a black sibling with a red child. rotate and exchange colors. */
494933707f3Ssthen sibling->color = child_parent->color;
495933707f3Ssthen child_parent->color = BLACK;
496933707f3Ssthen if(child_parent->right == child)
497933707f3Ssthen {
498933707f3Ssthen log_assert(sibling->left->color == RED);
499933707f3Ssthen sibling->left->color = BLACK;
500933707f3Ssthen rbtree_rotate_right(rbtree, child_parent);
501933707f3Ssthen }
502933707f3Ssthen else
503933707f3Ssthen {
504933707f3Ssthen log_assert(sibling->right->color == RED);
505933707f3Ssthen sibling->right->color = BLACK;
506933707f3Ssthen rbtree_rotate_left(rbtree, child_parent);
507933707f3Ssthen }
508933707f3Ssthen }
509933707f3Ssthen
510933707f3Ssthen int
rbtree_find_less_equal(rbtree_type * rbtree,const void * key,rbnode_type ** result)511*77079be7Ssthen rbtree_find_less_equal(rbtree_type *rbtree, const void *key,
512*77079be7Ssthen rbnode_type **result)
513933707f3Ssthen {
514933707f3Ssthen int r;
515*77079be7Ssthen rbnode_type *node;
516933707f3Ssthen
517933707f3Ssthen log_assert(result);
518933707f3Ssthen
519933707f3Ssthen /* We start at root... */
520933707f3Ssthen node = rbtree->root;
521933707f3Ssthen
522933707f3Ssthen *result = NULL;
523933707f3Ssthen fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
524933707f3Ssthen
525933707f3Ssthen /* While there are children... */
526933707f3Ssthen while (node != RBTREE_NULL) {
527933707f3Ssthen r = rbtree->cmp(key, node->key);
528933707f3Ssthen if (r == 0) {
529933707f3Ssthen /* Exact match */
530933707f3Ssthen *result = node;
531933707f3Ssthen return 1;
532933707f3Ssthen }
533933707f3Ssthen if (r < 0) {
534933707f3Ssthen node = node->left;
535933707f3Ssthen } else {
536933707f3Ssthen /* Temporary match */
537933707f3Ssthen *result = node;
538933707f3Ssthen node = node->right;
539933707f3Ssthen }
540933707f3Ssthen }
541933707f3Ssthen return 0;
542933707f3Ssthen }
543933707f3Ssthen
544933707f3Ssthen /*
545933707f3Ssthen * Finds the first element in the red black tree
546933707f3Ssthen *
547933707f3Ssthen */
548*77079be7Ssthen rbnode_type *
rbtree_first(rbtree_type * rbtree)549*77079be7Ssthen rbtree_first (rbtree_type *rbtree)
550933707f3Ssthen {
551*77079be7Ssthen rbnode_type *node;
552933707f3Ssthen
553933707f3Ssthen for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
554933707f3Ssthen return node;
555933707f3Ssthen }
556933707f3Ssthen
557*77079be7Ssthen rbnode_type *
rbtree_last(rbtree_type * rbtree)558*77079be7Ssthen rbtree_last (rbtree_type *rbtree)
559933707f3Ssthen {
560*77079be7Ssthen rbnode_type *node;
561933707f3Ssthen
562933707f3Ssthen for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
563933707f3Ssthen return node;
564933707f3Ssthen }
565933707f3Ssthen
566933707f3Ssthen /*
567933707f3Ssthen * Returns the next node...
568933707f3Ssthen *
569933707f3Ssthen */
570*77079be7Ssthen rbnode_type *
rbtree_next(rbnode_type * node)571*77079be7Ssthen rbtree_next (rbnode_type *node)
572933707f3Ssthen {
573*77079be7Ssthen rbnode_type *parent;
574933707f3Ssthen
575933707f3Ssthen if (node->right != RBTREE_NULL) {
576933707f3Ssthen /* One right, then keep on going left... */
577933707f3Ssthen for (node = node->right; node->left != RBTREE_NULL; node = node->left);
578933707f3Ssthen } else {
579933707f3Ssthen parent = node->parent;
580933707f3Ssthen while (parent != RBTREE_NULL && node == parent->right) {
581933707f3Ssthen node = parent;
582933707f3Ssthen parent = parent->parent;
583933707f3Ssthen }
584933707f3Ssthen node = parent;
585933707f3Ssthen }
586933707f3Ssthen return node;
587933707f3Ssthen }
588933707f3Ssthen
589*77079be7Ssthen rbnode_type *
rbtree_previous(rbnode_type * node)590*77079be7Ssthen rbtree_previous(rbnode_type *node)
591933707f3Ssthen {
592*77079be7Ssthen rbnode_type *parent;
593933707f3Ssthen
594933707f3Ssthen if (node->left != RBTREE_NULL) {
595933707f3Ssthen /* One left, then keep on going right... */
596933707f3Ssthen for (node = node->left; node->right != RBTREE_NULL; node = node->right);
597933707f3Ssthen } else {
598933707f3Ssthen parent = node->parent;
599933707f3Ssthen while (parent != RBTREE_NULL && node == parent->left) {
600933707f3Ssthen node = parent;
601933707f3Ssthen parent = parent->parent;
602933707f3Ssthen }
603933707f3Ssthen node = parent;
604933707f3Ssthen }
605933707f3Ssthen return node;
606933707f3Ssthen }
607933707f3Ssthen
608933707f3Ssthen /** recursive descent traverse */
609933707f3Ssthen static void
traverse_post(void (* func)(rbnode_type *,void *),void * arg,rbnode_type * node)610*77079be7Ssthen traverse_post(void (*func)(rbnode_type*, void*), void* arg, rbnode_type* node)
611933707f3Ssthen {
612933707f3Ssthen if(!node || node == RBTREE_NULL)
613933707f3Ssthen return;
614933707f3Ssthen /* recurse */
615933707f3Ssthen traverse_post(func, arg, node->left);
616933707f3Ssthen traverse_post(func, arg, node->right);
617933707f3Ssthen /* call user func */
618933707f3Ssthen (*func)(node, arg);
619933707f3Ssthen }
620933707f3Ssthen
621933707f3Ssthen void
traverse_postorder(rbtree_type * tree,void (* func)(rbnode_type *,void *),void * arg)622*77079be7Ssthen traverse_postorder(rbtree_type* tree, void (*func)(rbnode_type*, void*),
623*77079be7Ssthen void* arg)
624933707f3Ssthen {
625933707f3Ssthen traverse_post(func, arg, tree->root);
626933707f3Ssthen }
627