Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / core / ngx_rbtree.c
blob914ca7e884b06b2ebbdc801ff6590923b6744168
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
13 * The red-black tree code is based on the algorithm described in
14 * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
18 static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root,
19 ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
20 static ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_node_t **root,
21 ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
24 void
25 ngx_rbtree_insert(ngx_thread_volatile ngx_rbtree_t *tree,
26 ngx_rbtree_node_t *node)
28 ngx_rbtree_node_t **root, *temp, *sentinel;
30 /* a binary tree insert */
32 root = (ngx_rbtree_node_t **) &tree->root;
33 sentinel = tree->sentinel;
35 if (*root == sentinel) {
36 node->parent = NULL;
37 node->left = sentinel;
38 node->right = sentinel;
39 ngx_rbt_black(node);
40 *root = node;
42 return;
45 tree->insert(*root, node, sentinel);
47 /* re-balance tree */
49 while (node != *root && ngx_rbt_is_red(node->parent)) {
51 if (node->parent == node->parent->parent->left) {
52 temp = node->parent->parent->right;
54 if (ngx_rbt_is_red(temp)) {
55 ngx_rbt_black(node->parent);
56 ngx_rbt_black(temp);
57 ngx_rbt_red(node->parent->parent);
58 node = node->parent->parent;
60 } else {
61 if (node == node->parent->right) {
62 node = node->parent;
63 ngx_rbtree_left_rotate(root, sentinel, node);
66 ngx_rbt_black(node->parent);
67 ngx_rbt_red(node->parent->parent);
68 ngx_rbtree_right_rotate(root, sentinel, node->parent->parent);
71 } else {
72 temp = node->parent->parent->left;
74 if (ngx_rbt_is_red(temp)) {
75 ngx_rbt_black(node->parent);
76 ngx_rbt_black(temp);
77 ngx_rbt_red(node->parent->parent);
78 node = node->parent->parent;
80 } else {
81 if (node == node->parent->left) {
82 node = node->parent;
83 ngx_rbtree_right_rotate(root, sentinel, node);
86 ngx_rbt_black(node->parent);
87 ngx_rbt_red(node->parent->parent);
88 ngx_rbtree_left_rotate(root, sentinel, node->parent->parent);
93 ngx_rbt_black(*root);
97 void
98 ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
99 ngx_rbtree_node_t *sentinel)
101 ngx_rbtree_node_t **p;
103 for ( ;; ) {
105 p = (node->key < temp->key) ? &temp->left : &temp->right;
107 if (*p == sentinel) {
108 break;
111 temp = *p;
114 *p = node;
115 node->parent = temp;
116 node->left = sentinel;
117 node->right = sentinel;
118 ngx_rbt_red(node);
122 void
123 ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
124 ngx_rbtree_node_t *sentinel)
126 ngx_rbtree_node_t **p;
128 for ( ;; ) {
131 * Timer values
132 * 1) are spread in small range, usually several minutes,
133 * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
134 * The comparison takes into account that overflow.
137 /* node->key < temp->key */
139 p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
140 ? &temp->left : &temp->right;
142 if (*p == sentinel) {
143 break;
146 temp = *p;
149 *p = node;
150 node->parent = temp;
151 node->left = sentinel;
152 node->right = sentinel;
153 ngx_rbt_red(node);
157 void
158 ngx_rbtree_delete(ngx_thread_volatile ngx_rbtree_t *tree,
159 ngx_rbtree_node_t *node)
161 ngx_uint_t red;
162 ngx_rbtree_node_t **root, *sentinel, *subst, *temp, *w;
164 /* a binary tree delete */
166 root = (ngx_rbtree_node_t **) &tree->root;
167 sentinel = tree->sentinel;
169 if (node->left == sentinel) {
170 temp = node->right;
171 subst = node;
173 } else if (node->right == sentinel) {
174 temp = node->left;
175 subst = node;
177 } else {
178 subst = ngx_rbtree_min(node->right, sentinel);
180 if (subst->left != sentinel) {
181 temp = subst->left;
182 } else {
183 temp = subst->right;
187 if (subst == *root) {
188 *root = temp;
189 ngx_rbt_black(temp);
191 /* DEBUG stuff */
192 node->left = NULL;
193 node->right = NULL;
194 node->parent = NULL;
195 node->key = 0;
197 return;
200 red = ngx_rbt_is_red(subst);
202 if (subst == subst->parent->left) {
203 subst->parent->left = temp;
205 } else {
206 subst->parent->right = temp;
209 if (subst == node) {
211 temp->parent = subst->parent;
213 } else {
215 if (subst->parent == node) {
216 temp->parent = subst;
218 } else {
219 temp->parent = subst->parent;
222 subst->left = node->left;
223 subst->right = node->right;
224 subst->parent = node->parent;
225 ngx_rbt_copy_color(subst, node);
227 if (node == *root) {
228 *root = subst;
230 } else {
231 if (node == node->parent->left) {
232 node->parent->left = subst;
233 } else {
234 node->parent->right = subst;
238 if (subst->left != sentinel) {
239 subst->left->parent = subst;
242 if (subst->right != sentinel) {
243 subst->right->parent = subst;
247 /* DEBUG stuff */
248 node->left = NULL;
249 node->right = NULL;
250 node->parent = NULL;
251 node->key = 0;
253 if (red) {
254 return;
257 /* a delete fixup */
259 while (temp != *root && ngx_rbt_is_black(temp)) {
261 if (temp == temp->parent->left) {
262 w = temp->parent->right;
264 if (ngx_rbt_is_red(w)) {
265 ngx_rbt_black(w);
266 ngx_rbt_red(temp->parent);
267 ngx_rbtree_left_rotate(root, sentinel, temp->parent);
268 w = temp->parent->right;
271 if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
272 ngx_rbt_red(w);
273 temp = temp->parent;
275 } else {
276 if (ngx_rbt_is_black(w->right)) {
277 ngx_rbt_black(w->left);
278 ngx_rbt_red(w);
279 ngx_rbtree_right_rotate(root, sentinel, w);
280 w = temp->parent->right;
283 ngx_rbt_copy_color(w, temp->parent);
284 ngx_rbt_black(temp->parent);
285 ngx_rbt_black(w->right);
286 ngx_rbtree_left_rotate(root, sentinel, temp->parent);
287 temp = *root;
290 } else {
291 w = temp->parent->left;
293 if (ngx_rbt_is_red(w)) {
294 ngx_rbt_black(w);
295 ngx_rbt_red(temp->parent);
296 ngx_rbtree_right_rotate(root, sentinel, temp->parent);
297 w = temp->parent->left;
300 if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
301 ngx_rbt_red(w);
302 temp = temp->parent;
304 } else {
305 if (ngx_rbt_is_black(w->left)) {
306 ngx_rbt_black(w->right);
307 ngx_rbt_red(w);
308 ngx_rbtree_left_rotate(root, sentinel, w);
309 w = temp->parent->left;
312 ngx_rbt_copy_color(w, temp->parent);
313 ngx_rbt_black(temp->parent);
314 ngx_rbt_black(w->left);
315 ngx_rbtree_right_rotate(root, sentinel, temp->parent);
316 temp = *root;
321 ngx_rbt_black(temp);
325 static ngx_inline void
326 ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
327 ngx_rbtree_node_t *node)
329 ngx_rbtree_node_t *temp;
331 temp = node->right;
332 node->right = temp->left;
334 if (temp->left != sentinel) {
335 temp->left->parent = node;
338 temp->parent = node->parent;
340 if (node == *root) {
341 *root = temp;
343 } else if (node == node->parent->left) {
344 node->parent->left = temp;
346 } else {
347 node->parent->right = temp;
350 temp->left = node;
351 node->parent = temp;
355 static ngx_inline void
356 ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
357 ngx_rbtree_node_t *node)
359 ngx_rbtree_node_t *temp;
361 temp = node->left;
362 node->left = temp->right;
364 if (temp->right != sentinel) {
365 temp->right->parent = node;
368 temp->parent = node->parent;
370 if (node == *root) {
371 *root = temp;
373 } else if (node == node->parent->right) {
374 node->parent->right = temp;
376 } else {
377 node->parent->left = temp;
380 temp->right = node;
381 node->parent = temp;