1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer * rbtree.c -- generic red black tree
3825eb42bSJan Lentfer *
4825eb42bSJan Lentfer * Taken from Unbound, modified for ldns
5825eb42bSJan Lentfer *
6825eb42bSJan Lentfer * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
7825eb42bSJan Lentfer *
8825eb42bSJan Lentfer * This software is open source.
9825eb42bSJan Lentfer *
10825eb42bSJan Lentfer * Redistribution and use in source and binary forms, with or without
11825eb42bSJan Lentfer * modification, are permitted provided that the following conditions
12825eb42bSJan Lentfer * are met:
13825eb42bSJan Lentfer *
14825eb42bSJan Lentfer * Redistributions of source code must retain the above copyright notice,
15825eb42bSJan Lentfer * this list of conditions and the following disclaimer.
16825eb42bSJan Lentfer *
17825eb42bSJan Lentfer * Redistributions in binary form must reproduce the above copyright notice,
18825eb42bSJan Lentfer * this list of conditions and the following disclaimer in the documentation
19825eb42bSJan Lentfer * and/or other materials provided with the distribution.
20825eb42bSJan Lentfer *
21825eb42bSJan Lentfer * Neither the name of the NLNET LABS nor the names of its contributors may
22825eb42bSJan Lentfer * be used to endorse or promote products derived from this software without
23825eb42bSJan Lentfer * specific prior written permission.
24825eb42bSJan Lentfer *
25825eb42bSJan Lentfer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
265340022aSzrj * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
275340022aSzrj * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
285340022aSzrj * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
295340022aSzrj * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
305340022aSzrj * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
315340022aSzrj * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
325340022aSzrj * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
335340022aSzrj * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
345340022aSzrj * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
355340022aSzrj * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36825eb42bSJan Lentfer *
37825eb42bSJan Lentfer */
38825eb42bSJan Lentfer
39825eb42bSJan Lentfer /**
40825eb42bSJan Lentfer * \file
41825eb42bSJan Lentfer * Implementation of a redblack tree.
42825eb42bSJan Lentfer */
43825eb42bSJan Lentfer
44825eb42bSJan Lentfer #include <ldns/config.h>
45825eb42bSJan Lentfer #include <ldns/rbtree.h>
46d1b2b5caSJohn Marino #include <ldns/util.h>
47825eb42bSJan Lentfer #include <stdlib.h>
48825eb42bSJan Lentfer
49825eb42bSJan Lentfer /** Node colour black */
50825eb42bSJan Lentfer #define BLACK 0
51825eb42bSJan Lentfer /** Node colour red */
52825eb42bSJan Lentfer #define RED 1
53825eb42bSJan Lentfer
54825eb42bSJan Lentfer /** the NULL node, global alloc */
55825eb42bSJan Lentfer ldns_rbnode_t ldns_rbtree_null_node = {
56825eb42bSJan Lentfer LDNS_RBTREE_NULL, /* Parent. */
57825eb42bSJan Lentfer LDNS_RBTREE_NULL, /* Left. */
58825eb42bSJan Lentfer LDNS_RBTREE_NULL, /* Right. */
59825eb42bSJan Lentfer NULL, /* Key. */
60825eb42bSJan Lentfer NULL, /* Data. */
61825eb42bSJan Lentfer BLACK /* Color. */
62825eb42bSJan Lentfer };
63825eb42bSJan Lentfer
64825eb42bSJan Lentfer /** rotate subtree left (to preserve redblack property) */
65825eb42bSJan Lentfer static void ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
66825eb42bSJan Lentfer /** rotate subtree right (to preserve redblack property) */
67825eb42bSJan Lentfer static void ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
68825eb42bSJan Lentfer /** Fixup node colours when insert happened */
69825eb42bSJan Lentfer static void ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
70825eb42bSJan Lentfer /** Fixup node colours when delete happened */
71825eb42bSJan Lentfer static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent);
72825eb42bSJan Lentfer
73825eb42bSJan Lentfer /*
74*ee791febSAntonio Huete Jimenez * Creates a new red black tree, initializes and returns a pointer to it.
75825eb42bSJan Lentfer *
76825eb42bSJan Lentfer * Return NULL on failure.
77825eb42bSJan Lentfer *
78825eb42bSJan Lentfer */
79825eb42bSJan Lentfer ldns_rbtree_t *
ldns_rbtree_create(int (* cmpf)(const void *,const void *))80825eb42bSJan Lentfer ldns_rbtree_create (int (*cmpf)(const void *, const void *))
81825eb42bSJan Lentfer {
82825eb42bSJan Lentfer ldns_rbtree_t *rbtree;
83825eb42bSJan Lentfer
84825eb42bSJan Lentfer /* Allocate memory for it */
85d1b2b5caSJohn Marino rbtree = (ldns_rbtree_t *) LDNS_MALLOC(ldns_rbtree_t);
86825eb42bSJan Lentfer if (!rbtree) {
87825eb42bSJan Lentfer return NULL;
88825eb42bSJan Lentfer }
89825eb42bSJan Lentfer
90825eb42bSJan Lentfer /* Initialize it */
91825eb42bSJan Lentfer ldns_rbtree_init(rbtree, cmpf);
92825eb42bSJan Lentfer
93825eb42bSJan Lentfer return rbtree;
94825eb42bSJan Lentfer }
95825eb42bSJan Lentfer
96825eb42bSJan Lentfer void
ldns_rbtree_init(ldns_rbtree_t * rbtree,int (* cmpf)(const void *,const void *))97825eb42bSJan Lentfer ldns_rbtree_init(ldns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *))
98825eb42bSJan Lentfer {
99825eb42bSJan Lentfer /* Initialize it */
100825eb42bSJan Lentfer rbtree->root = LDNS_RBTREE_NULL;
101825eb42bSJan Lentfer rbtree->count = 0;
102825eb42bSJan Lentfer rbtree->cmp = cmpf;
103825eb42bSJan Lentfer }
104825eb42bSJan Lentfer
105825eb42bSJan Lentfer void
ldns_rbtree_free(ldns_rbtree_t * rbtree)106825eb42bSJan Lentfer ldns_rbtree_free(ldns_rbtree_t *rbtree)
107825eb42bSJan Lentfer {
108d1b2b5caSJohn Marino LDNS_FREE(rbtree);
109825eb42bSJan Lentfer }
110825eb42bSJan Lentfer
111825eb42bSJan Lentfer /*
112825eb42bSJan Lentfer * Rotates the node to the left.
113825eb42bSJan Lentfer *
114825eb42bSJan Lentfer */
115825eb42bSJan Lentfer static void
ldns_rbtree_rotate_left(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)116825eb42bSJan Lentfer ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
117825eb42bSJan Lentfer {
118825eb42bSJan Lentfer ldns_rbnode_t *right = node->right;
119825eb42bSJan Lentfer node->right = right->left;
120825eb42bSJan Lentfer if (right->left != LDNS_RBTREE_NULL)
121825eb42bSJan Lentfer right->left->parent = node;
122825eb42bSJan Lentfer
123825eb42bSJan Lentfer right->parent = node->parent;
124825eb42bSJan Lentfer
125825eb42bSJan Lentfer if (node->parent != LDNS_RBTREE_NULL) {
126825eb42bSJan Lentfer if (node == node->parent->left) {
127825eb42bSJan Lentfer node->parent->left = right;
128825eb42bSJan Lentfer } else {
129825eb42bSJan Lentfer node->parent->right = right;
130825eb42bSJan Lentfer }
131825eb42bSJan Lentfer } else {
132825eb42bSJan Lentfer rbtree->root = right;
133825eb42bSJan Lentfer }
134825eb42bSJan Lentfer right->left = node;
135825eb42bSJan Lentfer node->parent = right;
136825eb42bSJan Lentfer }
137825eb42bSJan Lentfer
138825eb42bSJan Lentfer /*
139825eb42bSJan Lentfer * Rotates the node to the right.
140825eb42bSJan Lentfer *
141825eb42bSJan Lentfer */
142825eb42bSJan Lentfer static void
ldns_rbtree_rotate_right(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)143825eb42bSJan Lentfer ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
144825eb42bSJan Lentfer {
145825eb42bSJan Lentfer ldns_rbnode_t *left = node->left;
146825eb42bSJan Lentfer node->left = left->right;
147825eb42bSJan Lentfer if (left->right != LDNS_RBTREE_NULL)
148825eb42bSJan Lentfer left->right->parent = node;
149825eb42bSJan Lentfer
150825eb42bSJan Lentfer left->parent = node->parent;
151825eb42bSJan Lentfer
152825eb42bSJan Lentfer if (node->parent != LDNS_RBTREE_NULL) {
153825eb42bSJan Lentfer if (node == node->parent->right) {
154825eb42bSJan Lentfer node->parent->right = left;
155825eb42bSJan Lentfer } else {
156825eb42bSJan Lentfer node->parent->left = left;
157825eb42bSJan Lentfer }
158825eb42bSJan Lentfer } else {
159825eb42bSJan Lentfer rbtree->root = left;
160825eb42bSJan Lentfer }
161825eb42bSJan Lentfer left->right = node;
162825eb42bSJan Lentfer node->parent = left;
163825eb42bSJan Lentfer }
164825eb42bSJan Lentfer
165825eb42bSJan Lentfer static void
ldns_rbtree_insert_fixup(ldns_rbtree_t * rbtree,ldns_rbnode_t * node)166825eb42bSJan Lentfer ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
167825eb42bSJan Lentfer {
168825eb42bSJan Lentfer ldns_rbnode_t *uncle;
169825eb42bSJan Lentfer
170825eb42bSJan Lentfer /* While not at the root and need fixing... */
171825eb42bSJan Lentfer while (node != rbtree->root && node->parent->color == RED) {
172825eb42bSJan Lentfer /* If our parent is left child of our grandparent... */
173825eb42bSJan Lentfer if (node->parent == node->parent->parent->left) {
174825eb42bSJan Lentfer uncle = node->parent->parent->right;
175825eb42bSJan Lentfer
176825eb42bSJan Lentfer /* If our uncle is red... */
177825eb42bSJan Lentfer if (uncle->color == RED) {
178825eb42bSJan Lentfer /* Paint the parent and the uncle black... */
179825eb42bSJan Lentfer node->parent->color = BLACK;
180825eb42bSJan Lentfer uncle->color = BLACK;
181825eb42bSJan Lentfer
182825eb42bSJan Lentfer /* And the grandparent red... */
183825eb42bSJan Lentfer node->parent->parent->color = RED;
184825eb42bSJan Lentfer
185825eb42bSJan Lentfer /* And continue fixing the grandparent */
186825eb42bSJan Lentfer node = node->parent->parent;
187825eb42bSJan Lentfer } else { /* Our uncle is black... */
188825eb42bSJan Lentfer /* Are we the right child? */
189825eb42bSJan Lentfer if (node == node->parent->right) {
190825eb42bSJan Lentfer node = node->parent;
191825eb42bSJan Lentfer ldns_rbtree_rotate_left(rbtree, node);
192825eb42bSJan Lentfer }
193825eb42bSJan Lentfer /* Now we're the left child, repaint and rotate... */
194825eb42bSJan Lentfer node->parent->color = BLACK;
195825eb42bSJan Lentfer node->parent->parent->color = RED;
196825eb42bSJan Lentfer ldns_rbtree_rotate_right(rbtree, node->parent->parent);
197825eb42bSJan Lentfer }
198825eb42bSJan Lentfer } else {
199825eb42bSJan Lentfer uncle = node->parent->parent->left;
200825eb42bSJan Lentfer
201825eb42bSJan Lentfer /* If our uncle is red... */
202825eb42bSJan Lentfer if (uncle->color == RED) {
203825eb42bSJan Lentfer /* Paint the parent and the uncle black... */
204825eb42bSJan Lentfer node->parent->color = BLACK;
205825eb42bSJan Lentfer uncle->color = BLACK;
206825eb42bSJan Lentfer
207825eb42bSJan Lentfer /* And the grandparent red... */
208825eb42bSJan Lentfer node->parent->parent->color = RED;
209825eb42bSJan Lentfer
210825eb42bSJan Lentfer /* And continue fixing the grandparent */
211825eb42bSJan Lentfer node = node->parent->parent;
212825eb42bSJan Lentfer } else { /* Our uncle is black... */
213825eb42bSJan Lentfer /* Are we the right child? */
214825eb42bSJan Lentfer if (node == node->parent->left) {
215825eb42bSJan Lentfer node = node->parent;
216825eb42bSJan Lentfer ldns_rbtree_rotate_right(rbtree, node);
217825eb42bSJan Lentfer }
218825eb42bSJan Lentfer /* Now we're the right child, repaint and rotate... */
219825eb42bSJan Lentfer node->parent->color = BLACK;
220825eb42bSJan Lentfer node->parent->parent->color = RED;
221825eb42bSJan Lentfer ldns_rbtree_rotate_left(rbtree, node->parent->parent);
222825eb42bSJan Lentfer }
223825eb42bSJan Lentfer }
224825eb42bSJan Lentfer }
225825eb42bSJan Lentfer rbtree->root->color = BLACK;
226825eb42bSJan Lentfer }
227825eb42bSJan Lentfer
228825eb42bSJan Lentfer void
ldns_rbtree_insert_vref(ldns_rbnode_t * data,void * rbtree)229825eb42bSJan Lentfer ldns_rbtree_insert_vref(ldns_rbnode_t *data, void *rbtree)
230825eb42bSJan Lentfer {
231825eb42bSJan Lentfer (void) ldns_rbtree_insert((ldns_rbtree_t *) rbtree,
232825eb42bSJan Lentfer data);
233825eb42bSJan Lentfer }
234825eb42bSJan Lentfer
235825eb42bSJan Lentfer /*
236825eb42bSJan Lentfer * Inserts a node into a red black tree.
237825eb42bSJan Lentfer *
238825eb42bSJan Lentfer * Returns NULL on failure or the pointer to the newly added node
239825eb42bSJan Lentfer * otherwise.
240825eb42bSJan Lentfer */
241825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_insert(ldns_rbtree_t * rbtree,ldns_rbnode_t * data)242825eb42bSJan Lentfer ldns_rbtree_insert (ldns_rbtree_t *rbtree, ldns_rbnode_t *data)
243825eb42bSJan Lentfer {
244825eb42bSJan Lentfer /* XXX Not necessary, but keeps compiler quiet... */
245825eb42bSJan Lentfer int r = 0;
246825eb42bSJan Lentfer
247825eb42bSJan Lentfer /* We start at the root of the tree */
248825eb42bSJan Lentfer ldns_rbnode_t *node = rbtree->root;
249825eb42bSJan Lentfer ldns_rbnode_t *parent = LDNS_RBTREE_NULL;
250825eb42bSJan Lentfer
251825eb42bSJan Lentfer /* Lets find the new parent... */
252825eb42bSJan Lentfer while (node != LDNS_RBTREE_NULL) {
253825eb42bSJan Lentfer /* Compare two keys, do we have a duplicate? */
254825eb42bSJan Lentfer if ((r = rbtree->cmp(data->key, node->key)) == 0) {
255825eb42bSJan Lentfer return NULL;
256825eb42bSJan Lentfer }
257825eb42bSJan Lentfer parent = node;
258825eb42bSJan Lentfer
259825eb42bSJan Lentfer if (r < 0) {
260825eb42bSJan Lentfer node = node->left;
261825eb42bSJan Lentfer } else {
262825eb42bSJan Lentfer node = node->right;
263825eb42bSJan Lentfer }
264825eb42bSJan Lentfer }
265825eb42bSJan Lentfer
266825eb42bSJan Lentfer /* Initialize the new node */
267825eb42bSJan Lentfer data->parent = parent;
268825eb42bSJan Lentfer data->left = data->right = LDNS_RBTREE_NULL;
269825eb42bSJan Lentfer data->color = RED;
270825eb42bSJan Lentfer rbtree->count++;
271825eb42bSJan Lentfer
272825eb42bSJan Lentfer /* Insert it into the tree... */
273825eb42bSJan Lentfer if (parent != LDNS_RBTREE_NULL) {
274825eb42bSJan Lentfer if (r < 0) {
275825eb42bSJan Lentfer parent->left = data;
276825eb42bSJan Lentfer } else {
277825eb42bSJan Lentfer parent->right = data;
278825eb42bSJan Lentfer }
279825eb42bSJan Lentfer } else {
280825eb42bSJan Lentfer rbtree->root = data;
281825eb42bSJan Lentfer }
282825eb42bSJan Lentfer
283825eb42bSJan Lentfer /* Fix up the red-black properties... */
284825eb42bSJan Lentfer ldns_rbtree_insert_fixup(rbtree, data);
285825eb42bSJan Lentfer
286825eb42bSJan Lentfer return data;
287825eb42bSJan Lentfer }
288825eb42bSJan Lentfer
289825eb42bSJan Lentfer /*
290825eb42bSJan Lentfer * Searches the red black tree, returns the data if key is found or NULL otherwise.
291825eb42bSJan Lentfer *
292825eb42bSJan Lentfer */
293825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_search(ldns_rbtree_t * rbtree,const void * key)294825eb42bSJan Lentfer ldns_rbtree_search (ldns_rbtree_t *rbtree, const void *key)
295825eb42bSJan Lentfer {
296825eb42bSJan Lentfer ldns_rbnode_t *node;
297825eb42bSJan Lentfer
298825eb42bSJan Lentfer if (ldns_rbtree_find_less_equal(rbtree, key, &node)) {
299825eb42bSJan Lentfer return node;
300825eb42bSJan Lentfer } else {
301825eb42bSJan Lentfer return NULL;
302825eb42bSJan Lentfer }
303825eb42bSJan Lentfer }
304825eb42bSJan Lentfer
305825eb42bSJan Lentfer /** helpers for delete: swap node colours */
swap_int8(uint8_t * x,uint8_t * y)306825eb42bSJan Lentfer static void swap_int8(uint8_t* x, uint8_t* y)
307825eb42bSJan Lentfer {
308825eb42bSJan Lentfer uint8_t t = *x; *x = *y; *y = t;
309825eb42bSJan Lentfer }
310825eb42bSJan Lentfer
311825eb42bSJan Lentfer /** helpers for delete: swap node pointers */
swap_np(ldns_rbnode_t ** x,ldns_rbnode_t ** y)312825eb42bSJan Lentfer static void swap_np(ldns_rbnode_t** x, ldns_rbnode_t** y)
313825eb42bSJan Lentfer {
314825eb42bSJan Lentfer ldns_rbnode_t* t = *x; *x = *y; *y = t;
315825eb42bSJan Lentfer }
316825eb42bSJan Lentfer
317825eb42bSJan Lentfer /** Update parent pointers of child trees of 'parent' */
change_parent_ptr(ldns_rbtree_t * rbtree,ldns_rbnode_t * parent,ldns_rbnode_t * old,ldns_rbnode_t * new)318825eb42bSJan Lentfer static void change_parent_ptr(ldns_rbtree_t* rbtree, ldns_rbnode_t* parent, ldns_rbnode_t* old, ldns_rbnode_t* new)
319825eb42bSJan Lentfer {
320825eb42bSJan Lentfer if(parent == LDNS_RBTREE_NULL)
321825eb42bSJan Lentfer {
322825eb42bSJan Lentfer if(rbtree->root == old) rbtree->root = new;
323825eb42bSJan Lentfer return;
324825eb42bSJan Lentfer }
325825eb42bSJan Lentfer if(parent->left == old) parent->left = new;
326825eb42bSJan Lentfer if(parent->right == old) parent->right = new;
327825eb42bSJan Lentfer }
328825eb42bSJan Lentfer /** Update parent pointer of a node 'child' */
change_child_ptr(ldns_rbnode_t * child,ldns_rbnode_t * old,ldns_rbnode_t * new)329825eb42bSJan Lentfer static void change_child_ptr(ldns_rbnode_t* child, ldns_rbnode_t* old, ldns_rbnode_t* new)
330825eb42bSJan Lentfer {
331825eb42bSJan Lentfer if(child == LDNS_RBTREE_NULL) return;
332825eb42bSJan Lentfer if(child->parent == old) child->parent = new;
333825eb42bSJan Lentfer }
334825eb42bSJan Lentfer
335825eb42bSJan Lentfer ldns_rbnode_t*
ldns_rbtree_delete(ldns_rbtree_t * rbtree,const void * key)336825eb42bSJan Lentfer ldns_rbtree_delete(ldns_rbtree_t *rbtree, const void *key)
337825eb42bSJan Lentfer {
338825eb42bSJan Lentfer ldns_rbnode_t *to_delete;
339825eb42bSJan Lentfer ldns_rbnode_t *child;
340825eb42bSJan Lentfer if((to_delete = ldns_rbtree_search(rbtree, key)) == 0) return 0;
341825eb42bSJan Lentfer rbtree->count--;
342825eb42bSJan Lentfer
343825eb42bSJan Lentfer /* make sure we have at most one non-leaf child */
344825eb42bSJan Lentfer if(to_delete->left != LDNS_RBTREE_NULL &&
345825eb42bSJan Lentfer to_delete->right != LDNS_RBTREE_NULL)
346825eb42bSJan Lentfer {
347825eb42bSJan Lentfer /* swap with smallest from right subtree (or largest from left) */
348825eb42bSJan Lentfer ldns_rbnode_t *smright = to_delete->right;
349825eb42bSJan Lentfer while(smright->left != LDNS_RBTREE_NULL)
350825eb42bSJan Lentfer smright = smright->left;
351825eb42bSJan Lentfer /* swap the smright and to_delete elements in the tree,
352825eb42bSJan Lentfer * but the ldns_rbnode_t is first part of user data struct
353825eb42bSJan Lentfer * so cannot just swap the keys and data pointers. Instead
354825eb42bSJan Lentfer * readjust the pointers left,right,parent */
355825eb42bSJan Lentfer
356825eb42bSJan Lentfer /* swap colors - colors are tied to the position in the tree */
357825eb42bSJan Lentfer swap_int8(&to_delete->color, &smright->color);
358825eb42bSJan Lentfer
359825eb42bSJan Lentfer /* swap child pointers in parents of smright/to_delete */
360825eb42bSJan Lentfer change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
361825eb42bSJan Lentfer if(to_delete->right != smright)
362825eb42bSJan Lentfer change_parent_ptr(rbtree, smright->parent, smright, to_delete);
363825eb42bSJan Lentfer
364825eb42bSJan Lentfer /* swap parent pointers in children of smright/to_delete */
365825eb42bSJan Lentfer change_child_ptr(smright->left, smright, to_delete);
366825eb42bSJan Lentfer change_child_ptr(smright->left, smright, to_delete);
367825eb42bSJan Lentfer change_child_ptr(smright->right, smright, to_delete);
368825eb42bSJan Lentfer change_child_ptr(smright->right, smright, to_delete);
369825eb42bSJan Lentfer change_child_ptr(to_delete->left, to_delete, smright);
370825eb42bSJan Lentfer if(to_delete->right != smright)
371825eb42bSJan Lentfer change_child_ptr(to_delete->right, to_delete, smright);
372825eb42bSJan Lentfer if(to_delete->right == smright)
373825eb42bSJan Lentfer {
374825eb42bSJan Lentfer /* set up so after swap they work */
375825eb42bSJan Lentfer to_delete->right = to_delete;
376825eb42bSJan Lentfer smright->parent = smright;
377825eb42bSJan Lentfer }
378825eb42bSJan Lentfer
379825eb42bSJan Lentfer /* swap pointers in to_delete/smright nodes */
380825eb42bSJan Lentfer swap_np(&to_delete->parent, &smright->parent);
381825eb42bSJan Lentfer swap_np(&to_delete->left, &smright->left);
382825eb42bSJan Lentfer swap_np(&to_delete->right, &smright->right);
383825eb42bSJan Lentfer
384825eb42bSJan Lentfer /* now delete to_delete (which is at the location where the smright previously was) */
385825eb42bSJan Lentfer }
386825eb42bSJan Lentfer
387825eb42bSJan Lentfer if(to_delete->left != LDNS_RBTREE_NULL) child = to_delete->left;
388825eb42bSJan Lentfer else child = to_delete->right;
389825eb42bSJan Lentfer
390825eb42bSJan Lentfer /* unlink to_delete from the tree, replace to_delete with child */
391825eb42bSJan Lentfer change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
392825eb42bSJan Lentfer change_child_ptr(child, to_delete, to_delete->parent);
393825eb42bSJan Lentfer
394825eb42bSJan Lentfer if(to_delete->color == RED)
395825eb42bSJan Lentfer {
396825eb42bSJan Lentfer /* if node is red then the child (black) can be swapped in */
397825eb42bSJan Lentfer }
398825eb42bSJan Lentfer else if(child->color == RED)
399825eb42bSJan Lentfer {
400825eb42bSJan Lentfer /* change child to BLACK, removing a RED node is no problem */
401825eb42bSJan Lentfer if(child!=LDNS_RBTREE_NULL) child->color = BLACK;
402825eb42bSJan Lentfer }
403825eb42bSJan Lentfer else ldns_rbtree_delete_fixup(rbtree, child, to_delete->parent);
404825eb42bSJan Lentfer
405825eb42bSJan Lentfer /* unlink completely */
406825eb42bSJan Lentfer to_delete->parent = LDNS_RBTREE_NULL;
407825eb42bSJan Lentfer to_delete->left = LDNS_RBTREE_NULL;
408825eb42bSJan Lentfer to_delete->right = LDNS_RBTREE_NULL;
409825eb42bSJan Lentfer to_delete->color = BLACK;
410825eb42bSJan Lentfer return to_delete;
411825eb42bSJan Lentfer }
412825eb42bSJan Lentfer
ldns_rbtree_delete_fixup(ldns_rbtree_t * rbtree,ldns_rbnode_t * child,ldns_rbnode_t * child_parent)413825eb42bSJan Lentfer static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent)
414825eb42bSJan Lentfer {
415825eb42bSJan Lentfer ldns_rbnode_t* sibling;
416825eb42bSJan Lentfer int go_up = 1;
417825eb42bSJan Lentfer
418825eb42bSJan Lentfer /* determine sibling to the node that is one-black short */
419825eb42bSJan Lentfer if(child_parent->right == child) sibling = child_parent->left;
420825eb42bSJan Lentfer else sibling = child_parent->right;
421825eb42bSJan Lentfer
422825eb42bSJan Lentfer while(go_up)
423825eb42bSJan Lentfer {
424825eb42bSJan Lentfer if(child_parent == LDNS_RBTREE_NULL)
425825eb42bSJan Lentfer {
426825eb42bSJan Lentfer /* removed parent==black from root, every path, so ok */
427825eb42bSJan Lentfer return;
428825eb42bSJan Lentfer }
429825eb42bSJan Lentfer
430825eb42bSJan Lentfer if(sibling->color == RED)
431825eb42bSJan Lentfer { /* rotate to get a black sibling */
432825eb42bSJan Lentfer child_parent->color = RED;
433825eb42bSJan Lentfer sibling->color = BLACK;
434825eb42bSJan Lentfer if(child_parent->right == child)
435825eb42bSJan Lentfer ldns_rbtree_rotate_right(rbtree, child_parent);
436825eb42bSJan Lentfer else ldns_rbtree_rotate_left(rbtree, child_parent);
437825eb42bSJan Lentfer /* new sibling after rotation */
438825eb42bSJan Lentfer if(child_parent->right == child) sibling = child_parent->left;
439825eb42bSJan Lentfer else sibling = child_parent->right;
440825eb42bSJan Lentfer }
441825eb42bSJan Lentfer
442825eb42bSJan Lentfer if(child_parent->color == BLACK
443825eb42bSJan Lentfer && sibling->color == BLACK
444825eb42bSJan Lentfer && sibling->left->color == BLACK
445825eb42bSJan Lentfer && sibling->right->color == BLACK)
446825eb42bSJan Lentfer { /* fixup local with recolor of sibling */
447825eb42bSJan Lentfer if(sibling != LDNS_RBTREE_NULL)
448825eb42bSJan Lentfer sibling->color = RED;
449825eb42bSJan Lentfer
450825eb42bSJan Lentfer child = child_parent;
451825eb42bSJan Lentfer child_parent = child_parent->parent;
452825eb42bSJan Lentfer /* prepare to go up, new sibling */
453825eb42bSJan Lentfer if(child_parent->right == child) sibling = child_parent->left;
454825eb42bSJan Lentfer else sibling = child_parent->right;
455825eb42bSJan Lentfer }
456825eb42bSJan Lentfer else go_up = 0;
457825eb42bSJan Lentfer }
458825eb42bSJan Lentfer
459825eb42bSJan Lentfer if(child_parent->color == RED
460825eb42bSJan Lentfer && sibling->color == BLACK
461825eb42bSJan Lentfer && sibling->left->color == BLACK
462825eb42bSJan Lentfer && sibling->right->color == BLACK)
463825eb42bSJan Lentfer {
464825eb42bSJan Lentfer /* move red to sibling to rebalance */
465825eb42bSJan Lentfer if(sibling != LDNS_RBTREE_NULL)
466825eb42bSJan Lentfer sibling->color = RED;
467825eb42bSJan Lentfer child_parent->color = BLACK;
468825eb42bSJan Lentfer return;
469825eb42bSJan Lentfer }
470825eb42bSJan Lentfer
471825eb42bSJan Lentfer /* get a new sibling, by rotating at sibling. See which child
472825eb42bSJan Lentfer of sibling is red */
473825eb42bSJan Lentfer if(child_parent->right == child
474825eb42bSJan Lentfer && sibling->color == BLACK
475825eb42bSJan Lentfer && sibling->right->color == RED
476825eb42bSJan Lentfer && sibling->left->color == BLACK)
477825eb42bSJan Lentfer {
478825eb42bSJan Lentfer sibling->color = RED;
479825eb42bSJan Lentfer sibling->right->color = BLACK;
480825eb42bSJan Lentfer ldns_rbtree_rotate_left(rbtree, sibling);
481825eb42bSJan Lentfer /* new sibling after rotation */
482825eb42bSJan Lentfer if(child_parent->right == child) sibling = child_parent->left;
483825eb42bSJan Lentfer else sibling = child_parent->right;
484825eb42bSJan Lentfer }
485825eb42bSJan Lentfer else if(child_parent->left == child
486825eb42bSJan Lentfer && sibling->color == BLACK
487825eb42bSJan Lentfer && sibling->left->color == RED
488825eb42bSJan Lentfer && sibling->right->color == BLACK)
489825eb42bSJan Lentfer {
490825eb42bSJan Lentfer sibling->color = RED;
491825eb42bSJan Lentfer sibling->left->color = BLACK;
492825eb42bSJan Lentfer ldns_rbtree_rotate_right(rbtree, sibling);
493825eb42bSJan Lentfer /* new sibling after rotation */
494825eb42bSJan Lentfer if(child_parent->right == child) sibling = child_parent->left;
495825eb42bSJan Lentfer else sibling = child_parent->right;
496825eb42bSJan Lentfer }
497825eb42bSJan Lentfer
498825eb42bSJan Lentfer /* now we have a black sibling with a red child. rotate and exchange colors. */
499825eb42bSJan Lentfer sibling->color = child_parent->color;
500825eb42bSJan Lentfer child_parent->color = BLACK;
501825eb42bSJan Lentfer if(child_parent->right == child)
502825eb42bSJan Lentfer {
503825eb42bSJan Lentfer sibling->left->color = BLACK;
504825eb42bSJan Lentfer ldns_rbtree_rotate_right(rbtree, child_parent);
505825eb42bSJan Lentfer }
506825eb42bSJan Lentfer else
507825eb42bSJan Lentfer {
508825eb42bSJan Lentfer sibling->right->color = BLACK;
509825eb42bSJan Lentfer ldns_rbtree_rotate_left(rbtree, child_parent);
510825eb42bSJan Lentfer }
511825eb42bSJan Lentfer }
512825eb42bSJan Lentfer
513825eb42bSJan Lentfer int
ldns_rbtree_find_less_equal(ldns_rbtree_t * rbtree,const void * key,ldns_rbnode_t ** result)514825eb42bSJan Lentfer ldns_rbtree_find_less_equal(ldns_rbtree_t *rbtree, const void *key, ldns_rbnode_t **result)
515825eb42bSJan Lentfer {
516825eb42bSJan Lentfer int r;
517825eb42bSJan Lentfer ldns_rbnode_t *node;
518825eb42bSJan Lentfer
519825eb42bSJan Lentfer /* We start at root... */
520825eb42bSJan Lentfer node = rbtree->root;
521825eb42bSJan Lentfer
522825eb42bSJan Lentfer *result = NULL;
523825eb42bSJan Lentfer
524825eb42bSJan Lentfer /* While there are children... */
525825eb42bSJan Lentfer while (node != LDNS_RBTREE_NULL) {
526825eb42bSJan Lentfer r = rbtree->cmp(key, node->key);
527825eb42bSJan Lentfer if (r == 0) {
528825eb42bSJan Lentfer /* Exact match */
529825eb42bSJan Lentfer *result = node;
530825eb42bSJan Lentfer return 1;
531825eb42bSJan Lentfer }
532825eb42bSJan Lentfer if (r < 0) {
533825eb42bSJan Lentfer node = node->left;
534825eb42bSJan Lentfer } else {
535825eb42bSJan Lentfer /* Temporary match */
536825eb42bSJan Lentfer *result = node;
537825eb42bSJan Lentfer node = node->right;
538825eb42bSJan Lentfer }
539825eb42bSJan Lentfer }
540825eb42bSJan Lentfer return 0;
541825eb42bSJan Lentfer }
542825eb42bSJan Lentfer
543825eb42bSJan Lentfer /*
544825eb42bSJan Lentfer * Finds the first element in the red black tree
545825eb42bSJan Lentfer *
546825eb42bSJan Lentfer */
547825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_first(const ldns_rbtree_t * rbtree)5485340022aSzrj ldns_rbtree_first(const ldns_rbtree_t *rbtree)
549825eb42bSJan Lentfer {
550ac996e71SJan Lentfer ldns_rbnode_t *node = rbtree->root;
551825eb42bSJan Lentfer
552ac996e71SJan Lentfer if (rbtree->root != LDNS_RBTREE_NULL) {
553825eb42bSJan Lentfer for (node = rbtree->root; node->left != LDNS_RBTREE_NULL; node = node->left);
554ac996e71SJan Lentfer }
555825eb42bSJan Lentfer return node;
556825eb42bSJan Lentfer }
557825eb42bSJan Lentfer
558825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_last(const ldns_rbtree_t * rbtree)5595340022aSzrj ldns_rbtree_last(const ldns_rbtree_t *rbtree)
560825eb42bSJan Lentfer {
561ac996e71SJan Lentfer ldns_rbnode_t *node = rbtree->root;
562825eb42bSJan Lentfer
563ac996e71SJan Lentfer if (rbtree->root != LDNS_RBTREE_NULL) {
564825eb42bSJan Lentfer for (node = rbtree->root; node->right != LDNS_RBTREE_NULL; node = node->right);
565ac996e71SJan Lentfer }
566825eb42bSJan Lentfer return node;
567825eb42bSJan Lentfer }
568825eb42bSJan Lentfer
569825eb42bSJan Lentfer /*
570825eb42bSJan Lentfer * Returns the next node...
571825eb42bSJan Lentfer *
572825eb42bSJan Lentfer */
573825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_next(ldns_rbnode_t * node)574825eb42bSJan Lentfer ldns_rbtree_next(ldns_rbnode_t *node)
575825eb42bSJan Lentfer {
576825eb42bSJan Lentfer ldns_rbnode_t *parent;
577825eb42bSJan Lentfer
578825eb42bSJan Lentfer if (node->right != LDNS_RBTREE_NULL) {
579825eb42bSJan Lentfer /* One right, then keep on going left... */
580825eb42bSJan Lentfer for (node = node->right;
581825eb42bSJan Lentfer node->left != LDNS_RBTREE_NULL;
582825eb42bSJan Lentfer node = node->left);
583825eb42bSJan Lentfer } else {
584825eb42bSJan Lentfer parent = node->parent;
585825eb42bSJan Lentfer while (parent != LDNS_RBTREE_NULL && node == parent->right) {
586825eb42bSJan Lentfer node = parent;
587825eb42bSJan Lentfer parent = parent->parent;
588825eb42bSJan Lentfer }
589825eb42bSJan Lentfer node = parent;
590825eb42bSJan Lentfer }
591825eb42bSJan Lentfer return node;
592825eb42bSJan Lentfer }
593825eb42bSJan Lentfer
594825eb42bSJan Lentfer ldns_rbnode_t *
ldns_rbtree_previous(ldns_rbnode_t * node)595825eb42bSJan Lentfer ldns_rbtree_previous(ldns_rbnode_t *node)
596825eb42bSJan Lentfer {
597825eb42bSJan Lentfer ldns_rbnode_t *parent;
598825eb42bSJan Lentfer
599825eb42bSJan Lentfer if (node->left != LDNS_RBTREE_NULL) {
600825eb42bSJan Lentfer /* One left, then keep on going right... */
601825eb42bSJan Lentfer for (node = node->left;
602825eb42bSJan Lentfer node->right != LDNS_RBTREE_NULL;
603825eb42bSJan Lentfer node = node->right);
604825eb42bSJan Lentfer } else {
605825eb42bSJan Lentfer parent = node->parent;
606825eb42bSJan Lentfer while (parent != LDNS_RBTREE_NULL && node == parent->left) {
607825eb42bSJan Lentfer node = parent;
608825eb42bSJan Lentfer parent = parent->parent;
609825eb42bSJan Lentfer }
610825eb42bSJan Lentfer node = parent;
611825eb42bSJan Lentfer }
612825eb42bSJan Lentfer return node;
613825eb42bSJan Lentfer }
614825eb42bSJan Lentfer
615825eb42bSJan Lentfer /**
616825eb42bSJan Lentfer * split off elements number of elements from the start
617825eb42bSJan Lentfer * of the name tree and return a new tree
618825eb42bSJan Lentfer */
619825eb42bSJan Lentfer ldns_rbtree_t *
ldns_rbtree_split(ldns_rbtree_t * tree,size_t elements)620825eb42bSJan Lentfer ldns_rbtree_split(ldns_rbtree_t *tree,
621825eb42bSJan Lentfer size_t elements)
622825eb42bSJan Lentfer {
623825eb42bSJan Lentfer ldns_rbtree_t *new_tree;
624825eb42bSJan Lentfer ldns_rbnode_t *cur_node;
625825eb42bSJan Lentfer ldns_rbnode_t *move_node;
626825eb42bSJan Lentfer size_t count = 0;
627825eb42bSJan Lentfer
628825eb42bSJan Lentfer new_tree = ldns_rbtree_create(tree->cmp);
629825eb42bSJan Lentfer
630825eb42bSJan Lentfer cur_node = ldns_rbtree_first(tree);
631825eb42bSJan Lentfer while (count < elements && cur_node != LDNS_RBTREE_NULL) {
632825eb42bSJan Lentfer move_node = ldns_rbtree_delete(tree, cur_node->key);
633fd185f4dSJan Lentfer (void)ldns_rbtree_insert(new_tree, move_node);
634825eb42bSJan Lentfer cur_node = ldns_rbtree_first(tree);
635825eb42bSJan Lentfer count++;
636825eb42bSJan Lentfer }
637825eb42bSJan Lentfer
638825eb42bSJan Lentfer return new_tree;
639825eb42bSJan Lentfer }
640825eb42bSJan Lentfer
641825eb42bSJan Lentfer /*
642825eb42bSJan Lentfer * add all node from the second tree to the first (removing them from the
643825eb42bSJan Lentfer * second), and fix up nsec(3)s if present
644825eb42bSJan Lentfer */
645825eb42bSJan Lentfer void
ldns_rbtree_join(ldns_rbtree_t * tree1,ldns_rbtree_t * tree2)646825eb42bSJan Lentfer ldns_rbtree_join(ldns_rbtree_t *tree1, ldns_rbtree_t *tree2)
647825eb42bSJan Lentfer {
648825eb42bSJan Lentfer ldns_traverse_postorder(tree2, ldns_rbtree_insert_vref, tree1);
649825eb42bSJan Lentfer }
650825eb42bSJan Lentfer
651825eb42bSJan Lentfer /** recursive descent traverse */
652825eb42bSJan Lentfer static void
traverse_post(void (* func)(ldns_rbnode_t *,void *),void * arg,ldns_rbnode_t * node)653825eb42bSJan Lentfer traverse_post(void (*func)(ldns_rbnode_t*, void*), void* arg,
654825eb42bSJan Lentfer ldns_rbnode_t* node)
655825eb42bSJan Lentfer {
656825eb42bSJan Lentfer if(!node || node == LDNS_RBTREE_NULL)
657825eb42bSJan Lentfer return;
658825eb42bSJan Lentfer /* recurse */
659825eb42bSJan Lentfer traverse_post(func, arg, node->left);
660825eb42bSJan Lentfer traverse_post(func, arg, node->right);
661825eb42bSJan Lentfer /* call user func */
662825eb42bSJan Lentfer (*func)(node, arg);
663825eb42bSJan Lentfer }
664825eb42bSJan Lentfer
665825eb42bSJan Lentfer void
ldns_traverse_postorder(ldns_rbtree_t * tree,void (* func)(ldns_rbnode_t *,void *),void * arg)666825eb42bSJan Lentfer ldns_traverse_postorder(ldns_rbtree_t* tree,
667825eb42bSJan Lentfer void (*func)(ldns_rbnode_t*, void*), void* arg)
668825eb42bSJan Lentfer {
669825eb42bSJan Lentfer traverse_post(func, arg, tree->root);
670825eb42bSJan Lentfer }
671