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