blob: b8ee6f6c43d38f12b51877da5b37ba1d3edc5507 [file] [log] [blame]
Florin Coras672d5fc2019-04-15 17:28:51 -07001/*
2 * Copyright (c) 2019 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * Algorithm from:
17 * Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009).
18 * Introduction to algorithms. MIT press, 3rd Edition, Ch. 13
19 */
20
21#include <vppinfra/rbtree.h>
22
Florin Coras672d5fc2019-04-15 17:28:51 -070023static inline void
24rb_tree_rotate_left (rb_tree_t * rt, rb_node_t * x)
25{
26 rb_node_t *y, *tmp, *xp;
27 rb_node_index_t xi, yi;
28
29 xi = rb_node_index (rt, x);
30 yi = x->right;
31 y = rb_node_right (rt, x);
32 x->right = y->left;
33 if (y->left != RBTREE_TNIL_INDEX)
34 {
35 tmp = rb_node_left (rt, y);
36 tmp->parent = xi;
37 }
38 xp = rb_node_parent (rt, x);
39 y->parent = x->parent;
40 if (x->parent == RBTREE_TNIL_INDEX)
41 rt->root = rb_node_index (rt, y);
42 else if (xp->left == xi)
43 xp->left = yi;
44 else
45 xp->right = yi;
46 y->left = xi;
47 x->parent = yi;
48}
49
50static inline void
51rb_tree_rotate_right (rb_tree_t * rt, rb_node_t * y)
52{
53 rb_node_index_t yi, xi;
54 rb_node_t *x, *yp;
55
56 yi = rb_node_index (rt, y);
57 xi = y->left;
58 x = rb_node_left (rt, y);
59 y->left = x->right;
60 if (x->right != RBTREE_TNIL_INDEX)
61 {
62 rb_node_t *tmp = rb_node_right (rt, x);
63 tmp->parent = yi;
64 }
65 yp = rb_node_parent (rt, y);
66 x->parent = y->parent;
67 if (y->parent == RBTREE_TNIL_INDEX)
68 rt->root = rb_node_index (rt, x);
69 else if (yp->right == yi)
70 yp->right = xi;
71 else
72 yp->left = xi;
73 x->right = yi;
74 y->parent = xi;
75}
76
Florin Corasbadf38a2019-06-17 11:11:15 -070077static inline void
78rb_tree_fixup_inline (rb_tree_t * rt, rb_node_t * y, rb_node_t * z)
Florin Coras672d5fc2019-04-15 17:28:51 -070079{
Florin Corasbadf38a2019-06-17 11:11:15 -070080 rb_node_t *zpp, *zp;
81 rb_node_index_t zi;
Florin Coras672d5fc2019-04-15 17:28:51 -070082
Florin Coras672d5fc2019-04-15 17:28:51 -070083 while (y->color == RBTREE_RED)
84 {
85 zi = rb_node_index (rt, z);
86 zp = rb_node_parent (rt, z);
87 zpp = rb_node_parent (rt, zp);
88 if (z->parent == zpp->left)
89 {
90 y = rb_node_right (rt, zpp);
91 if (y->color == RBTREE_RED)
92 {
93 zp->color = RBTREE_BLACK;
94 y->color = RBTREE_BLACK;
95 zpp->color = RBTREE_RED;
96 z = zpp;
97 }
98 else
99 {
100 if (zi == zp->right)
101 {
102 z = zp;
103 rb_tree_rotate_left (rt, z);
104 zp = rb_node (rt, z->parent);
105 zpp = rb_node (rt, zp->parent);
106 }
107 zp->color = RBTREE_BLACK;
108 zpp->color = RBTREE_RED;
109 rb_tree_rotate_right (rt, zpp);
110 }
111 }
112 else
113 {
114 y = rb_node (rt, zpp->left);
115 if (y->color == RBTREE_RED)
116 {
117 zp->color = RBTREE_BLACK;
118 y->color = RBTREE_BLACK;
119 zpp->color = RBTREE_RED;
120 z = zpp;
121 }
122 else
123 {
124 if (zi == zp->left)
125 {
126 z = zp;
127 rb_tree_rotate_right (rt, z);
128 zp = rb_node (rt, z->parent);
129 zpp = rb_node (rt, zp->parent);
130 }
131 zp->color = RBTREE_BLACK;
132 zpp->color = RBTREE_RED;
133 rb_tree_rotate_left (rt, zpp);
134 }
135 }
136 }
137 rb_node (rt, rt->root)->color = RBTREE_BLACK;
138}
139
Florin Corasbadf38a2019-06-17 11:11:15 -0700140static void
141rb_tree_insert (rb_tree_t * rt, rb_node_t * z)
142{
143 rb_node_index_t yi = 0, xi = rt->root;
144 rb_node_t *y, *x;
145
146 y = rb_node (rt, RBTREE_TNIL_INDEX);
147 while (xi != RBTREE_TNIL_INDEX)
148 {
149 x = rb_node (rt, xi);
150 y = x;
151 if (z->key < x->key)
152 xi = x->left;
153 else
154 xi = x->right;
155 }
156 yi = rb_node_index (rt, y);
157 z->parent = yi;
158 if (yi == RBTREE_TNIL_INDEX)
159 rt->root = rb_node_index (rt, z);
160 else if (z->key < y->key)
161 y->left = rb_node_index (rt, z);
162 else
163 y->right = rb_node_index (rt, z);
164
165 /* Tree fixup stage */
166 rb_tree_fixup_inline (rt, y, z);
167}
168
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200169__clib_export rb_node_index_t
Florin Coras672d5fc2019-04-15 17:28:51 -0700170rb_tree_add (rb_tree_t * rt, u32 key)
171{
172 rb_node_t *n;
173
174 pool_get_zero (rt->nodes, n);
175 n->key = key;
176 n->color = RBTREE_RED;
177 rb_tree_insert (rt, n);
178 return rb_node_index (rt, n);
179}
180
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200181__clib_export rb_node_index_t
Florin Coras4375fa32019-04-19 15:56:00 -0700182rb_tree_add2 (rb_tree_t * rt, u32 key, uword opaque)
Florin Coras672d5fc2019-04-15 17:28:51 -0700183{
184 rb_node_t *n;
185
186 pool_get_zero (rt->nodes, n);
187 n->key = key;
188 n->color = RBTREE_RED;
189 n->opaque = opaque;
190 rb_tree_insert (rt, n);
191 return rb_node_index (rt, n);
192}
193
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200194__clib_export rb_node_index_t
Florin Corasbadf38a2019-06-17 11:11:15 -0700195rb_tree_add_custom (rb_tree_t * rt, u32 key, uword opaque, rb_tree_lt_fn ltfn)
196{
197 rb_node_index_t yi = 0, xi = rt->root;
198 rb_node_t *z, *y, *x;
199
200 pool_get_zero (rt->nodes, z);
201 z->key = key;
202 z->color = RBTREE_RED;
203 z->opaque = opaque;
204
205 y = rb_node (rt, RBTREE_TNIL_INDEX);
206 while (xi != RBTREE_TNIL_INDEX)
207 {
208 x = rb_node (rt, xi);
209 y = x;
Florin Corasf22f4e52019-12-19 16:10:58 -0800210 ASSERT (z->key != x->key);
Florin Corasbadf38a2019-06-17 11:11:15 -0700211 if (ltfn (z->key, x->key))
212 xi = x->left;
213 else
214 xi = x->right;
215 }
216 yi = rb_node_index (rt, y);
217 z->parent = yi;
218 if (yi == RBTREE_TNIL_INDEX)
219 rt->root = rb_node_index (rt, z);
220 else if (ltfn (z->key, y->key))
221 y->left = rb_node_index (rt, z);
222 else
223 y->right = rb_node_index (rt, z);
224
225 rb_tree_fixup_inline (rt, y, z);
226
227 return rb_node_index (rt, z);
228}
229
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200230__clib_export rb_node_t *
Florin Coras672d5fc2019-04-15 17:28:51 -0700231rb_tree_search_subtree (rb_tree_t * rt, rb_node_t * x, u32 key)
232{
233 while (rb_node_index (rt, x) != RBTREE_TNIL_INDEX && key != x->key)
234 if (key < x->key)
235 x = rb_node_left (rt, x);
236 else
237 x = rb_node_right (rt, x);
238 return x;
239}
240
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200241__clib_export rb_node_t *
Florin Corasbadf38a2019-06-17 11:11:15 -0700242rb_tree_search_subtree_custom (rb_tree_t * rt, rb_node_t * x, u32 key,
243 rb_tree_lt_fn ltfn)
244{
245 while (rb_node_index (rt, x) != RBTREE_TNIL_INDEX && key != x->key)
246 if (ltfn (key, x->key))
247 x = rb_node_left (rt, x);
248 else
249 x = rb_node_right (rt, x);
250 return x;
251}
252
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200253__clib_export rb_node_t *
Florin Coras672d5fc2019-04-15 17:28:51 -0700254rb_tree_min_subtree (rb_tree_t * rt, rb_node_t * x)
255{
256 while (x->left != RBTREE_TNIL_INDEX)
257 x = rb_node_left (rt, x);
258 return x;
259}
260
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200261__clib_export rb_node_t *
Florin Coras672d5fc2019-04-15 17:28:51 -0700262rb_tree_max_subtree (rb_tree_t * rt, rb_node_t * x)
263{
264 while (x->right != RBTREE_TNIL_INDEX)
265 x = rb_node_right (rt, x);
266 return x;
267}
268
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200269__clib_export rb_node_t *
Florin Corasf7cda7a2019-04-19 18:50:34 -0700270rb_tree_successor (rb_tree_t * rt, rb_node_t * x)
271{
272 rb_node_t *y;
273
274 if (x->right != RBTREE_TNIL_INDEX)
275 return rb_tree_min_subtree (rt, rb_node_right (rt, x));
276
277 y = rb_node_parent (rt, x);
278 while (!rb_node_is_tnil (rt, y) && y->right == rb_node_index (rt, x))
279 {
280 x = y;
281 y = rb_node_parent (rt, y);
282 }
283 return y;
284}
285
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200286__clib_export rb_node_t *
Florin Corasf7cda7a2019-04-19 18:50:34 -0700287rb_tree_predecessor (rb_tree_t * rt, rb_node_t * x)
288{
289 rb_node_t *y;
290
291 if (x->left != RBTREE_TNIL_INDEX)
292 return rb_tree_max_subtree (rt, rb_node_left (rt, x));
293
294 y = rb_node_parent (rt, x);
295 while (!rb_node_is_tnil (rt, y) && y->left == rb_node_index (rt, x))
296 {
297 x = y;
298 y = rb_node_parent (rt, y);
299 }
300 return y;
301}
302
Florin Coras672d5fc2019-04-15 17:28:51 -0700303static inline void
304rb_tree_transplant (rb_tree_t * rt, rb_node_t * u, rb_node_t * v)
305{
306 rb_node_t *up;
307
308 up = rb_node_parent (rt, u);
309 if (u->parent == RBTREE_TNIL_INDEX)
310 rt->root = rb_node_index (rt, v);
311 else if (rb_node_index (rt, u) == up->left)
312 up->left = rb_node_index (rt, v);
313 else
314 up->right = rb_node_index (rt, v);
315 v->parent = u->parent;
316}
317
Florin Corasf22f4e52019-12-19 16:10:58 -0800318static void
319rb_tree_del_node_internal (rb_tree_t * rt, rb_node_t * z)
Florin Coras672d5fc2019-04-15 17:28:51 -0700320{
321 rb_node_color_t y_original_color;
322 rb_node_t *x, *y, *yr, *yl, *xp, *w, *wl, *wr;
323 rb_node_index_t xi, yi;
324
325 y = z;
326 y_original_color = y->color;
327
328 if (z->left == RBTREE_TNIL_INDEX)
329 {
330 x = rb_node_right (rt, z);
331 rb_tree_transplant (rt, z, x);
332 }
333 else if (z->right == RBTREE_TNIL_INDEX)
334 {
335 x = rb_node_left (rt, z);
336 rb_tree_transplant (rt, z, x);
337 }
338 else
339 {
340 y = rb_tree_min_subtree (rt, rb_node_right (rt, z));
341 y_original_color = y->color;
342 x = rb_node_right (rt, y);
343 yi = rb_node_index (rt, y);
344 if (y->parent == rb_node_index (rt, z))
345 x->parent = yi;
346 else
347 {
Florin Corasd3149632019-06-19 16:45:09 -0700348 rb_tree_transplant (rt, y, x);
Florin Coras672d5fc2019-04-15 17:28:51 -0700349 y->right = z->right;
350 yr = rb_node_right (rt, y);
351 yr->parent = yi;
352 }
353 rb_tree_transplant (rt, z, y);
354 y->left = z->left;
355 yl = rb_node_left (rt, y);
356 yl->parent = yi;
357 y->color = z->color;
358 }
359
360 if (y_original_color == RBTREE_RED)
361 return;
362
363 /* Tree fixup needed */
364
365 xi = rb_node_index (rt, x);
366 while (xi != rt->root && x->color == RBTREE_BLACK)
367 {
368 xp = rb_node_parent (rt, x);
369 if (xi == xp->left)
370 {
371 w = rb_node_right (rt, xp);
372 if (w->color == RBTREE_RED)
373 {
374 w->color = RBTREE_BLACK;
375 xp->color = RBTREE_RED;
376 rb_tree_rotate_left (rt, xp);
377 w = rb_node_right (rt, xp);
378 }
379 wl = rb_node_left (rt, w);
380 wr = rb_node_right (rt, w);
381 if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
382 {
Florin Corasd3149632019-06-19 16:45:09 -0700383 if (!rb_node_is_tnil (rt, w))
384 w->color = RBTREE_RED;
Florin Coras672d5fc2019-04-15 17:28:51 -0700385 x = xp;
386 }
387 else
388 {
389 if (wr->color == RBTREE_BLACK)
390 {
391 wl->color = RBTREE_BLACK;
392 w->color = RBTREE_RED;
393 rb_tree_rotate_right (rt, w);
394 w = rb_node_right (rt, xp);
Florin Corasd3149632019-06-19 16:45:09 -0700395 wr = rb_node_right (rt, w);
Florin Coras672d5fc2019-04-15 17:28:51 -0700396 }
397 w->color = xp->color;
398 xp->color = RBTREE_BLACK;
399 wr->color = RBTREE_BLACK;
400 rb_tree_rotate_left (rt, xp);
401 x = rb_node (rt, rt->root);
402 }
403 }
404 else
405 {
406 w = rb_node_left (rt, xp);
407 if (w->color == RBTREE_RED)
408 {
409 w->color = RBTREE_BLACK;
410 xp->color = RBTREE_RED;
411 rb_tree_rotate_right (rt, xp);
412 w = rb_node_left (rt, xp);
413 }
414 wl = rb_node_left (rt, w);
415 wr = rb_node_right (rt, w);
416 if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
417 {
Florin Corasd3149632019-06-19 16:45:09 -0700418 if (!rb_node_is_tnil (rt, w))
419 w->color = RBTREE_RED;
Florin Coras672d5fc2019-04-15 17:28:51 -0700420 x = xp;
421 }
422 else
423 {
424 if (wl->color == RBTREE_BLACK)
425 {
426 wr->color = RBTREE_BLACK;
427 w->color = RBTREE_RED;
428 rb_tree_rotate_left (rt, w);
429 w = rb_node_left (rt, xp);
Florin Corasd3149632019-06-19 16:45:09 -0700430 wl = rb_node_left (rt, w);
Florin Coras672d5fc2019-04-15 17:28:51 -0700431 }
432 w->color = xp->color;
433 xp->color = RBTREE_BLACK;
434 wl->color = RBTREE_BLACK;
435 rb_tree_rotate_right (rt, xp);
436 x = rb_node (rt, rt->root);
437 }
438 }
439 xi = rb_node_index (rt, x);
440 }
441 x->color = RBTREE_BLACK;
442}
443
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200444__clib_export void
Florin Corasf22f4e52019-12-19 16:10:58 -0800445rb_tree_del_node (rb_tree_t * rt, rb_node_t * z)
446{
447 rb_tree_del_node_internal (rt, z);
448 pool_put (rt->nodes, z);
449}
450
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200451__clib_export void
Florin Coras672d5fc2019-04-15 17:28:51 -0700452rb_tree_del (rb_tree_t * rt, u32 key)
453{
454 rb_node_t *n;
455 n = rb_tree_search_subtree (rt, rb_node (rt, rt->root), key);
456 if (rb_node_index (rt, n) != RBTREE_TNIL_INDEX)
Florin Corasf22f4e52019-12-19 16:10:58 -0800457 rb_tree_del_node (rt, n);
Florin Coras672d5fc2019-04-15 17:28:51 -0700458}
459
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200460__clib_export void
Florin Corasbadf38a2019-06-17 11:11:15 -0700461rb_tree_del_custom (rb_tree_t * rt, u32 key, rb_tree_lt_fn ltfn)
462{
463 rb_node_t *n;
464 n = rb_tree_search_subtree_custom (rt, rb_node (rt, rt->root), key, ltfn);
465 if (rb_node_index (rt, n) != RBTREE_TNIL_INDEX)
Florin Corasf22f4e52019-12-19 16:10:58 -0800466 rb_tree_del_node (rt, n);
Florin Corasbadf38a2019-06-17 11:11:15 -0700467}
468
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200469__clib_export u32
Florin Coras672d5fc2019-04-15 17:28:51 -0700470rb_tree_n_nodes (rb_tree_t * rt)
471{
472 return pool_elts (rt->nodes);
473}
474
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200475__clib_export void
Florin Coras672d5fc2019-04-15 17:28:51 -0700476rb_tree_free_nodes (rb_tree_t * rt)
477{
Florin Corasb095a3c2019-04-25 12:58:46 -0700478 pool_free (rt->nodes);
479 rt->root = RBTREE_TNIL_INDEX;
Florin Coras672d5fc2019-04-15 17:28:51 -0700480}
481
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200482__clib_export void
Florin Coras672d5fc2019-04-15 17:28:51 -0700483rb_tree_init (rb_tree_t * rt)
484{
485 rb_node_t *tnil;
486
487 rt->nodes = 0;
488 rt->root = RBTREE_TNIL_INDEX;
489
490 /* By convention first node, index 0, is the T.nil sentinel */
491 pool_get_zero (rt->nodes, tnil);
492 tnil->color = RBTREE_BLACK;
493}
494
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200495__clib_export int
Florin Corasf22f4e52019-12-19 16:10:58 -0800496rb_tree_is_init (rb_tree_t * rt)
497{
498 if (pool_elts (rt->nodes) == 0)
499 return 0;
500 return 1;
501}
502
Florin Coras672d5fc2019-04-15 17:28:51 -0700503/*
504 * fd.io coding-style-patch-verification: ON
505 *
506 * Local Variables:
507 * eval: (c-set-style "gnu")
508 * End:
509 */