xref: /unit/src/test/nxt_rbtree1.c (revision 384:8f86d3ff3e29)
1*384Szelenkov@nginx.com 
2*384Szelenkov@nginx.com /*
3*384Szelenkov@nginx.com  * Copyright (C) Igor Sysoev
4*384Szelenkov@nginx.com  * Copyright (C) Nginx, Inc.
5*384Szelenkov@nginx.com  */
6*384Szelenkov@nginx.com 
7*384Szelenkov@nginx.com 
8*384Szelenkov@nginx.com #include <nxt_main.h>
9*384Szelenkov@nginx.com #include "nxt_rbtree1.h"
10*384Szelenkov@nginx.com 
11*384Szelenkov@nginx.com 
12*384Szelenkov@nginx.com /*
13*384Szelenkov@nginx.com  * The red-black tree code is based on the algorithm described in
14*384Szelenkov@nginx.com  * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
15*384Szelenkov@nginx.com  */
16*384Szelenkov@nginx.com 
17*384Szelenkov@nginx.com 
18*384Szelenkov@nginx.com nxt_inline void nxt_rbtree1_left_rotate(nxt_rbtree1_node_t **root,
19*384Szelenkov@nginx.com     nxt_rbtree1_node_t *sentinel, nxt_rbtree1_node_t *node);
20*384Szelenkov@nginx.com nxt_inline void nxt_rbtree1_right_rotate(nxt_rbtree1_node_t **root,
21*384Szelenkov@nginx.com     nxt_rbtree1_node_t *sentinel, nxt_rbtree1_node_t *node);
22*384Szelenkov@nginx.com 
23*384Szelenkov@nginx.com 
24*384Szelenkov@nginx.com void
nxt_rbtree1_insert(nxt_rbtree1_t * tree,nxt_rbtree1_node_t * node)25*384Szelenkov@nginx.com nxt_rbtree1_insert(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node)
26*384Szelenkov@nginx.com {
27*384Szelenkov@nginx.com     nxt_rbtree1_node_t  **root, *temp, *sentinel;
28*384Szelenkov@nginx.com 
29*384Szelenkov@nginx.com     /* a binary tree insert */
30*384Szelenkov@nginx.com 
31*384Szelenkov@nginx.com     root = (nxt_rbtree1_node_t **) &tree->root;
32*384Szelenkov@nginx.com     sentinel = tree->sentinel;
33*384Szelenkov@nginx.com 
34*384Szelenkov@nginx.com     if (*root == sentinel) {
35*384Szelenkov@nginx.com         node->parent = NULL;
36*384Szelenkov@nginx.com         node->left = sentinel;
37*384Szelenkov@nginx.com         node->right = sentinel;
38*384Szelenkov@nginx.com         nxt_rbtree1_black(node);
39*384Szelenkov@nginx.com         *root = node;
40*384Szelenkov@nginx.com 
41*384Szelenkov@nginx.com         return;
42*384Szelenkov@nginx.com     }
43*384Szelenkov@nginx.com 
44*384Szelenkov@nginx.com     tree->insert(*root, node, sentinel);
45*384Szelenkov@nginx.com 
46*384Szelenkov@nginx.com     /* re-balance tree */
47*384Szelenkov@nginx.com 
48*384Szelenkov@nginx.com     while (node != *root && nxt_rbtree1_is_red(node->parent)) {
49*384Szelenkov@nginx.com 
50*384Szelenkov@nginx.com         if (node->parent == node->parent->parent->left) {
51*384Szelenkov@nginx.com             temp = node->parent->parent->right;
52*384Szelenkov@nginx.com 
53*384Szelenkov@nginx.com             if (nxt_rbtree1_is_red(temp)) {
54*384Szelenkov@nginx.com                 nxt_rbtree1_black(node->parent);
55*384Szelenkov@nginx.com                 nxt_rbtree1_black(temp);
56*384Szelenkov@nginx.com                 nxt_rbtree1_red(node->parent->parent);
57*384Szelenkov@nginx.com                 node = node->parent->parent;
58*384Szelenkov@nginx.com 
59*384Szelenkov@nginx.com             } else {
60*384Szelenkov@nginx.com                 if (node == node->parent->right) {
61*384Szelenkov@nginx.com                     node = node->parent;
62*384Szelenkov@nginx.com                     nxt_rbtree1_left_rotate(root, sentinel, node);
63*384Szelenkov@nginx.com                 }
64*384Szelenkov@nginx.com 
65*384Szelenkov@nginx.com                 nxt_rbtree1_black(node->parent);
66*384Szelenkov@nginx.com                 nxt_rbtree1_red(node->parent->parent);
67*384Szelenkov@nginx.com                 nxt_rbtree1_right_rotate(root, sentinel, node->parent->parent);
68*384Szelenkov@nginx.com             }
69*384Szelenkov@nginx.com 
70*384Szelenkov@nginx.com         } else {
71*384Szelenkov@nginx.com             temp = node->parent->parent->left;
72*384Szelenkov@nginx.com 
73*384Szelenkov@nginx.com             if (nxt_rbtree1_is_red(temp)) {
74*384Szelenkov@nginx.com                 nxt_rbtree1_black(node->parent);
75*384Szelenkov@nginx.com                 nxt_rbtree1_black(temp);
76*384Szelenkov@nginx.com                 nxt_rbtree1_red(node->parent->parent);
77*384Szelenkov@nginx.com                 node = node->parent->parent;
78*384Szelenkov@nginx.com 
79*384Szelenkov@nginx.com             } else {
80*384Szelenkov@nginx.com                 if (node == node->parent->left) {
81*384Szelenkov@nginx.com                     node = node->parent;
82*384Szelenkov@nginx.com                     nxt_rbtree1_right_rotate(root, sentinel, node);
83*384Szelenkov@nginx.com                 }
84*384Szelenkov@nginx.com 
85*384Szelenkov@nginx.com                 nxt_rbtree1_black(node->parent);
86*384Szelenkov@nginx.com                 nxt_rbtree1_red(node->parent->parent);
87*384Szelenkov@nginx.com                 nxt_rbtree1_left_rotate(root, sentinel, node->parent->parent);
88*384Szelenkov@nginx.com             }
89*384Szelenkov@nginx.com         }
90*384Szelenkov@nginx.com     }
91*384Szelenkov@nginx.com 
92*384Szelenkov@nginx.com     nxt_rbtree1_black(*root);
93*384Szelenkov@nginx.com }
94*384Szelenkov@nginx.com 
95*384Szelenkov@nginx.com 
96*384Szelenkov@nginx.com void
nxt_rbtree1_insert_value(nxt_rbtree1_node_t * temp,nxt_rbtree1_node_t * node,nxt_rbtree1_node_t * sentinel)97*384Szelenkov@nginx.com nxt_rbtree1_insert_value(nxt_rbtree1_node_t *temp, nxt_rbtree1_node_t *node,
98*384Szelenkov@nginx.com     nxt_rbtree1_node_t *sentinel)
99*384Szelenkov@nginx.com {
100*384Szelenkov@nginx.com     nxt_rbtree1_node_t  **p;
101*384Szelenkov@nginx.com 
102*384Szelenkov@nginx.com     for ( ;; ) {
103*384Szelenkov@nginx.com 
104*384Szelenkov@nginx.com         p = (node->key < temp->key) ? &temp->left : &temp->right;
105*384Szelenkov@nginx.com 
106*384Szelenkov@nginx.com         if (*p == sentinel) {
107*384Szelenkov@nginx.com             break;
108*384Szelenkov@nginx.com         }
109*384Szelenkov@nginx.com 
110*384Szelenkov@nginx.com         temp = *p;
111*384Szelenkov@nginx.com     }
112*384Szelenkov@nginx.com 
113*384Szelenkov@nginx.com     *p = node;
114*384Szelenkov@nginx.com     node->parent = temp;
115*384Szelenkov@nginx.com     node->left = sentinel;
116*384Szelenkov@nginx.com     node->right = sentinel;
117*384Szelenkov@nginx.com     nxt_rbtree1_red(node);
118*384Szelenkov@nginx.com }
119*384Szelenkov@nginx.com 
120*384Szelenkov@nginx.com 
121*384Szelenkov@nginx.com void
nxt_rbtree1_insert_timer_value(nxt_rbtree1_node_t * temp,nxt_rbtree1_node_t * node,nxt_rbtree1_node_t * sentinel)122*384Szelenkov@nginx.com nxt_rbtree1_insert_timer_value(nxt_rbtree1_node_t *temp,
123*384Szelenkov@nginx.com     nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel)
124*384Szelenkov@nginx.com {
125*384Szelenkov@nginx.com     nxt_rbtree1_node_t  **p;
126*384Szelenkov@nginx.com 
127*384Szelenkov@nginx.com     for ( ;; ) {
128*384Szelenkov@nginx.com 
129*384Szelenkov@nginx.com         /*
130*384Szelenkov@nginx.com          * Timer values
131*384Szelenkov@nginx.com          * 1) are spread in small range, usually several minutes,
132*384Szelenkov@nginx.com          * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
133*384Szelenkov@nginx.com          * The comparison takes into account that overflow.
134*384Szelenkov@nginx.com          */
135*384Szelenkov@nginx.com 
136*384Szelenkov@nginx.com         /*  node->key < temp->key */
137*384Szelenkov@nginx.com 
138*384Szelenkov@nginx.com         p = ((nxt_rbtree1_key_int_t) (node->key - temp->key) < 0)
139*384Szelenkov@nginx.com             ? &temp->left : &temp->right;
140*384Szelenkov@nginx.com 
141*384Szelenkov@nginx.com         if (*p == sentinel) {
142*384Szelenkov@nginx.com             break;
143*384Szelenkov@nginx.com         }
144*384Szelenkov@nginx.com 
145*384Szelenkov@nginx.com         temp = *p;
146*384Szelenkov@nginx.com     }
147*384Szelenkov@nginx.com 
148*384Szelenkov@nginx.com     *p = node;
149*384Szelenkov@nginx.com     node->parent = temp;
150*384Szelenkov@nginx.com     node->left = sentinel;
151*384Szelenkov@nginx.com     node->right = sentinel;
152*384Szelenkov@nginx.com     nxt_rbtree1_red(node);
153*384Szelenkov@nginx.com }
154*384Szelenkov@nginx.com 
155*384Szelenkov@nginx.com 
156*384Szelenkov@nginx.com void
nxt_rbtree1_delete(nxt_rbtree1_t * tree,nxt_rbtree1_node_t * node)157*384Szelenkov@nginx.com nxt_rbtree1_delete(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node)
158*384Szelenkov@nginx.com {
159*384Szelenkov@nginx.com     nxt_uint_t      red;
160*384Szelenkov@nginx.com     nxt_rbtree1_node_t  **root, *sentinel, *subst, *temp, *w;
161*384Szelenkov@nginx.com 
162*384Szelenkov@nginx.com     /* a binary tree delete */
163*384Szelenkov@nginx.com 
164*384Szelenkov@nginx.com     root = (nxt_rbtree1_node_t **) &tree->root;
165*384Szelenkov@nginx.com     sentinel = tree->sentinel;
166*384Szelenkov@nginx.com 
167*384Szelenkov@nginx.com     if (node->left == sentinel) {
168*384Szelenkov@nginx.com         temp = node->right;
169*384Szelenkov@nginx.com         subst = node;
170*384Szelenkov@nginx.com 
171*384Szelenkov@nginx.com     } else if (node->right == sentinel) {
172*384Szelenkov@nginx.com         temp = node->left;
173*384Szelenkov@nginx.com         subst = node;
174*384Szelenkov@nginx.com 
175*384Szelenkov@nginx.com     } else {
176*384Szelenkov@nginx.com         subst = nxt_rbtree1_min(node->right, sentinel);
177*384Szelenkov@nginx.com 
178*384Szelenkov@nginx.com         if (subst->left != sentinel) {
179*384Szelenkov@nginx.com             temp = subst->left;
180*384Szelenkov@nginx.com         } else {
181*384Szelenkov@nginx.com             temp = subst->right;
182*384Szelenkov@nginx.com         }
183*384Szelenkov@nginx.com     }
184*384Szelenkov@nginx.com 
185*384Szelenkov@nginx.com     if (subst == *root) {
186*384Szelenkov@nginx.com         *root = temp;
187*384Szelenkov@nginx.com         nxt_rbtree1_black(temp);
188*384Szelenkov@nginx.com 
189*384Szelenkov@nginx.com         /* DEBUG stuff */
190*384Szelenkov@nginx.com         node->left = NULL;
191*384Szelenkov@nginx.com         node->right = NULL;
192*384Szelenkov@nginx.com         node->parent = NULL;
193*384Szelenkov@nginx.com         node->key = 0;
194*384Szelenkov@nginx.com 
195*384Szelenkov@nginx.com         return;
196*384Szelenkov@nginx.com     }
197*384Szelenkov@nginx.com 
198*384Szelenkov@nginx.com     red = nxt_rbtree1_is_red(subst);
199*384Szelenkov@nginx.com 
200*384Szelenkov@nginx.com     if (subst == subst->parent->left) {
201*384Szelenkov@nginx.com         subst->parent->left = temp;
202*384Szelenkov@nginx.com 
203*384Szelenkov@nginx.com     } else {
204*384Szelenkov@nginx.com         subst->parent->right = temp;
205*384Szelenkov@nginx.com     }
206*384Szelenkov@nginx.com 
207*384Szelenkov@nginx.com     if (subst == node) {
208*384Szelenkov@nginx.com 
209*384Szelenkov@nginx.com         temp->parent = subst->parent;
210*384Szelenkov@nginx.com 
211*384Szelenkov@nginx.com     } else {
212*384Szelenkov@nginx.com 
213*384Szelenkov@nginx.com         if (subst->parent == node) {
214*384Szelenkov@nginx.com             temp->parent = subst;
215*384Szelenkov@nginx.com 
216*384Szelenkov@nginx.com         } else {
217*384Szelenkov@nginx.com             temp->parent = subst->parent;
218*384Szelenkov@nginx.com         }
219*384Szelenkov@nginx.com 
220*384Szelenkov@nginx.com         subst->left = node->left;
221*384Szelenkov@nginx.com         subst->right = node->right;
222*384Szelenkov@nginx.com         subst->parent = node->parent;
223*384Szelenkov@nginx.com         nxt_rbtree1_copy_color(subst, node);
224*384Szelenkov@nginx.com 
225*384Szelenkov@nginx.com         if (node == *root) {
226*384Szelenkov@nginx.com             *root = subst;
227*384Szelenkov@nginx.com 
228*384Szelenkov@nginx.com         } else {
229*384Szelenkov@nginx.com             if (node == node->parent->left) {
230*384Szelenkov@nginx.com                 node->parent->left = subst;
231*384Szelenkov@nginx.com             } else {
232*384Szelenkov@nginx.com                 node->parent->right = subst;
233*384Szelenkov@nginx.com             }
234*384Szelenkov@nginx.com         }
235*384Szelenkov@nginx.com 
236*384Szelenkov@nginx.com         if (subst->left != sentinel) {
237*384Szelenkov@nginx.com             subst->left->parent = subst;
238*384Szelenkov@nginx.com         }
239*384Szelenkov@nginx.com 
240*384Szelenkov@nginx.com         if (subst->right != sentinel) {
241*384Szelenkov@nginx.com             subst->right->parent = subst;
242*384Szelenkov@nginx.com         }
243*384Szelenkov@nginx.com     }
244*384Szelenkov@nginx.com 
245*384Szelenkov@nginx.com     /* DEBUG stuff */
246*384Szelenkov@nginx.com     node->left = NULL;
247*384Szelenkov@nginx.com     node->right = NULL;
248*384Szelenkov@nginx.com     node->parent = NULL;
249*384Szelenkov@nginx.com     node->key = 0;
250*384Szelenkov@nginx.com 
251*384Szelenkov@nginx.com     if (red) {
252*384Szelenkov@nginx.com         return;
253*384Szelenkov@nginx.com     }
254*384Szelenkov@nginx.com 
255*384Szelenkov@nginx.com     /* a delete fixup */
256*384Szelenkov@nginx.com 
257*384Szelenkov@nginx.com     while (temp != *root && nxt_rbtree1_is_black(temp)) {
258*384Szelenkov@nginx.com 
259*384Szelenkov@nginx.com         if (temp == temp->parent->left) {
260*384Szelenkov@nginx.com             w = temp->parent->right;
261*384Szelenkov@nginx.com 
262*384Szelenkov@nginx.com             if (nxt_rbtree1_is_red(w)) {
263*384Szelenkov@nginx.com                 nxt_rbtree1_black(w);
264*384Szelenkov@nginx.com                 nxt_rbtree1_red(temp->parent);
265*384Szelenkov@nginx.com                 nxt_rbtree1_left_rotate(root, sentinel, temp->parent);
266*384Szelenkov@nginx.com                 w = temp->parent->right;
267*384Szelenkov@nginx.com             }
268*384Szelenkov@nginx.com 
269*384Szelenkov@nginx.com             if (nxt_rbtree1_is_black(w->left) && nxt_rbtree1_is_black(w->right))
270*384Szelenkov@nginx.com             {
271*384Szelenkov@nginx.com                 nxt_rbtree1_red(w);
272*384Szelenkov@nginx.com                 temp = temp->parent;
273*384Szelenkov@nginx.com 
274*384Szelenkov@nginx.com             } else {
275*384Szelenkov@nginx.com                 if (nxt_rbtree1_is_black(w->right)) {
276*384Szelenkov@nginx.com                     nxt_rbtree1_black(w->left);
277*384Szelenkov@nginx.com                     nxt_rbtree1_red(w);
278*384Szelenkov@nginx.com                     nxt_rbtree1_right_rotate(root, sentinel, w);
279*384Szelenkov@nginx.com                     w = temp->parent->right;
280*384Szelenkov@nginx.com                 }
281*384Szelenkov@nginx.com 
282*384Szelenkov@nginx.com                 nxt_rbtree1_copy_color(w, temp->parent);
283*384Szelenkov@nginx.com                 nxt_rbtree1_black(temp->parent);
284*384Szelenkov@nginx.com                 nxt_rbtree1_black(w->right);
285*384Szelenkov@nginx.com                 nxt_rbtree1_left_rotate(root, sentinel, temp->parent);
286*384Szelenkov@nginx.com                 temp = *root;
287*384Szelenkov@nginx.com             }
288*384Szelenkov@nginx.com 
289*384Szelenkov@nginx.com         } else {
290*384Szelenkov@nginx.com             w = temp->parent->left;
291*384Szelenkov@nginx.com 
292*384Szelenkov@nginx.com             if (nxt_rbtree1_is_red(w)) {
293*384Szelenkov@nginx.com                 nxt_rbtree1_black(w);
294*384Szelenkov@nginx.com                 nxt_rbtree1_red(temp->parent);
295*384Szelenkov@nginx.com                 nxt_rbtree1_right_rotate(root, sentinel, temp->parent);
296*384Szelenkov@nginx.com                 w = temp->parent->left;
297*384Szelenkov@nginx.com             }
298*384Szelenkov@nginx.com 
299*384Szelenkov@nginx.com             if (nxt_rbtree1_is_black(w->left) && nxt_rbtree1_is_black(w->right))
300*384Szelenkov@nginx.com             {
301*384Szelenkov@nginx.com                 nxt_rbtree1_red(w);
302*384Szelenkov@nginx.com                 temp = temp->parent;
303*384Szelenkov@nginx.com 
304*384Szelenkov@nginx.com             } else {
305*384Szelenkov@nginx.com                 if (nxt_rbtree1_is_black(w->left)) {
306*384Szelenkov@nginx.com                     nxt_rbtree1_black(w->right);
307*384Szelenkov@nginx.com                     nxt_rbtree1_red(w);
308*384Szelenkov@nginx.com                     nxt_rbtree1_left_rotate(root, sentinel, w);
309*384Szelenkov@nginx.com                     w = temp->parent->left;
310*384Szelenkov@nginx.com                 }
311*384Szelenkov@nginx.com 
312*384Szelenkov@nginx.com                 nxt_rbtree1_copy_color(w, temp->parent);
313*384Szelenkov@nginx.com                 nxt_rbtree1_black(temp->parent);
314*384Szelenkov@nginx.com                 nxt_rbtree1_black(w->left);
315*384Szelenkov@nginx.com                 nxt_rbtree1_right_rotate(root, sentinel, temp->parent);
316*384Szelenkov@nginx.com                 temp = *root;
317*384Szelenkov@nginx.com             }
318*384Szelenkov@nginx.com         }
319*384Szelenkov@nginx.com     }
320*384Szelenkov@nginx.com 
321*384Szelenkov@nginx.com     nxt_rbtree1_black(temp);
322*384Szelenkov@nginx.com }
323*384Szelenkov@nginx.com 
324*384Szelenkov@nginx.com 
325*384Szelenkov@nginx.com nxt_inline void
nxt_rbtree1_left_rotate(nxt_rbtree1_node_t ** root,nxt_rbtree1_node_t * sentinel,nxt_rbtree1_node_t * node)326*384Szelenkov@nginx.com nxt_rbtree1_left_rotate(nxt_rbtree1_node_t **root, nxt_rbtree1_node_t *sentinel,
327*384Szelenkov@nginx.com     nxt_rbtree1_node_t *node)
328*384Szelenkov@nginx.com {
329*384Szelenkov@nginx.com     nxt_rbtree1_node_t  *temp;
330*384Szelenkov@nginx.com 
331*384Szelenkov@nginx.com     temp = node->right;
332*384Szelenkov@nginx.com     node->right = temp->left;
333*384Szelenkov@nginx.com 
334*384Szelenkov@nginx.com     if (temp->left != sentinel) {
335*384Szelenkov@nginx.com         temp->left->parent = node;
336*384Szelenkov@nginx.com     }
337*384Szelenkov@nginx.com 
338*384Szelenkov@nginx.com     temp->parent = node->parent;
339*384Szelenkov@nginx.com 
340*384Szelenkov@nginx.com     if (node == *root) {
341*384Szelenkov@nginx.com         *root = temp;
342*384Szelenkov@nginx.com 
343*384Szelenkov@nginx.com     } else if (node == node->parent->left) {
344*384Szelenkov@nginx.com         node->parent->left = temp;
345*384Szelenkov@nginx.com 
346*384Szelenkov@nginx.com     } else {
347*384Szelenkov@nginx.com         node->parent->right = temp;
348*384Szelenkov@nginx.com     }
349*384Szelenkov@nginx.com 
350*384Szelenkov@nginx.com     temp->left = node;
351*384Szelenkov@nginx.com     node->parent = temp;
352*384Szelenkov@nginx.com }
353*384Szelenkov@nginx.com 
354*384Szelenkov@nginx.com 
355*384Szelenkov@nginx.com nxt_inline void
nxt_rbtree1_right_rotate(nxt_rbtree1_node_t ** root,nxt_rbtree1_node_t * sentinel,nxt_rbtree1_node_t * node)356*384Szelenkov@nginx.com nxt_rbtree1_right_rotate(nxt_rbtree1_node_t **root,
357*384Szelenkov@nginx.com     nxt_rbtree1_node_t *sentinel, nxt_rbtree1_node_t *node)
358*384Szelenkov@nginx.com {
359*384Szelenkov@nginx.com     nxt_rbtree1_node_t  *temp;
360*384Szelenkov@nginx.com 
361*384Szelenkov@nginx.com     temp = node->left;
362*384Szelenkov@nginx.com     node->left = temp->right;
363*384Szelenkov@nginx.com 
364*384Szelenkov@nginx.com     if (temp->right != sentinel) {
365*384Szelenkov@nginx.com         temp->right->parent = node;
366*384Szelenkov@nginx.com     }
367*384Szelenkov@nginx.com 
368*384Szelenkov@nginx.com     temp->parent = node->parent;
369*384Szelenkov@nginx.com 
370*384Szelenkov@nginx.com     if (node == *root) {
371*384Szelenkov@nginx.com         *root = temp;
372*384Szelenkov@nginx.com 
373*384Szelenkov@nginx.com     } else if (node == node->parent->right) {
374*384Szelenkov@nginx.com         node->parent->right = temp;
375*384Szelenkov@nginx.com 
376*384Szelenkov@nginx.com     } else {
377*384Szelenkov@nginx.com         node->parent->left = temp;
378*384Szelenkov@nginx.com     }
379*384Szelenkov@nginx.com 
380*384Szelenkov@nginx.com     temp->right = node;
381*384Szelenkov@nginx.com     node->parent = temp;
382*384Szelenkov@nginx.com }
383