blob: 3770c2304ff99c7b841da90c233e58ddaa4630a0 [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
23static inline rb_node_t *
24rb_node_right (rb_tree_t * rt, rb_node_t * n)
25{
26 return pool_elt_at_index (rt->nodes, n->right);
27}
28
29static inline rb_node_t *
30rb_node_left (rb_tree_t * rt, rb_node_t * n)
31{
32 return pool_elt_at_index (rt->nodes, n->left);
33}
34
35static inline rb_node_t *
36rb_node_parent (rb_tree_t * rt, rb_node_t * n)
37{
38 return pool_elt_at_index (rt->nodes, n->parent);
39}
40
41static inline void
42rb_tree_rotate_left (rb_tree_t * rt, rb_node_t * x)
43{
44 rb_node_t *y, *tmp, *xp;
45 rb_node_index_t xi, yi;
46
47 xi = rb_node_index (rt, x);
48 yi = x->right;
49 y = rb_node_right (rt, x);
50 x->right = y->left;
51 if (y->left != RBTREE_TNIL_INDEX)
52 {
53 tmp = rb_node_left (rt, y);
54 tmp->parent = xi;
55 }
56 xp = rb_node_parent (rt, x);
57 y->parent = x->parent;
58 if (x->parent == RBTREE_TNIL_INDEX)
59 rt->root = rb_node_index (rt, y);
60 else if (xp->left == xi)
61 xp->left = yi;
62 else
63 xp->right = yi;
64 y->left = xi;
65 x->parent = yi;
66}
67
68static inline void
69rb_tree_rotate_right (rb_tree_t * rt, rb_node_t * y)
70{
71 rb_node_index_t yi, xi;
72 rb_node_t *x, *yp;
73
74 yi = rb_node_index (rt, y);
75 xi = y->left;
76 x = rb_node_left (rt, y);
77 y->left = x->right;
78 if (x->right != RBTREE_TNIL_INDEX)
79 {
80 rb_node_t *tmp = rb_node_right (rt, x);
81 tmp->parent = yi;
82 }
83 yp = rb_node_parent (rt, y);
84 x->parent = y->parent;
85 if (y->parent == RBTREE_TNIL_INDEX)
86 rt->root = rb_node_index (rt, x);
87 else if (yp->right == yi)
88 yp->right = xi;
89 else
90 yp->left = xi;
91 x->right = yi;
92 y->parent = xi;
93}
94
95static void
96rb_tree_insert (rb_tree_t * rt, rb_node_t * z)
97{
98 rb_node_index_t yi = 0, xi = rt->root, zi;
99 rb_node_t *y, *zpp, *x, *zp;
100
101 y = rb_node (rt, RBTREE_TNIL_INDEX);
102 while (xi != RBTREE_TNIL_INDEX)
103 {
104 x = rb_node (rt, xi);
105 y = x;
106 if (z->key < x->key)
107 xi = x->left;
108 else
109 xi = x->right;
110 }
111 yi = rb_node_index (rt, y);
112 z->parent = yi;
113 if (yi == RBTREE_TNIL_INDEX)
114 rt->root = rb_node_index (rt, z);
115 else if (z->key < y->key)
116 y->left = rb_node_index (rt, z);
117 else
118 y->right = rb_node_index (rt, z);
119
120 /* Tree fixup stage */
121 while (y->color == RBTREE_RED)
122 {
123 zi = rb_node_index (rt, z);
124 zp = rb_node_parent (rt, z);
125 zpp = rb_node_parent (rt, zp);
126 if (z->parent == zpp->left)
127 {
128 y = rb_node_right (rt, zpp);
129 if (y->color == RBTREE_RED)
130 {
131 zp->color = RBTREE_BLACK;
132 y->color = RBTREE_BLACK;
133 zpp->color = RBTREE_RED;
134 z = zpp;
135 }
136 else
137 {
138 if (zi == zp->right)
139 {
140 z = zp;
141 rb_tree_rotate_left (rt, z);
142 zp = rb_node (rt, z->parent);
143 zpp = rb_node (rt, zp->parent);
144 }
145 zp->color = RBTREE_BLACK;
146 zpp->color = RBTREE_RED;
147 rb_tree_rotate_right (rt, zpp);
148 }
149 }
150 else
151 {
152 y = rb_node (rt, zpp->left);
153 if (y->color == RBTREE_RED)
154 {
155 zp->color = RBTREE_BLACK;
156 y->color = RBTREE_BLACK;
157 zpp->color = RBTREE_RED;
158 z = zpp;
159 }
160 else
161 {
162 if (zi == zp->left)
163 {
164 z = zp;
165 rb_tree_rotate_right (rt, z);
166 zp = rb_node (rt, z->parent);
167 zpp = rb_node (rt, zp->parent);
168 }
169 zp->color = RBTREE_BLACK;
170 zpp->color = RBTREE_RED;
171 rb_tree_rotate_left (rt, zpp);
172 }
173 }
174 }
175 rb_node (rt, rt->root)->color = RBTREE_BLACK;
176}
177
178rb_node_index_t
179rb_tree_add (rb_tree_t * rt, u32 key)
180{
181 rb_node_t *n;
182
183 pool_get_zero (rt->nodes, n);
184 n->key = key;
185 n->color = RBTREE_RED;
186 rb_tree_insert (rt, n);
187 return rb_node_index (rt, n);
188}
189
190rb_node_index_t
191rb_tree_add2 (rb_tree_t * rt, u32 key, u32 opaque)
192{
193 rb_node_t *n;
194
195 pool_get_zero (rt->nodes, n);
196 n->key = key;
197 n->color = RBTREE_RED;
198 n->opaque = opaque;
199 rb_tree_insert (rt, n);
200 return rb_node_index (rt, n);
201}
202
203rb_node_t *
204rb_tree_search_subtree (rb_tree_t * rt, rb_node_t * x, u32 key)
205{
206 while (rb_node_index (rt, x) != RBTREE_TNIL_INDEX && key != x->key)
207 if (key < x->key)
208 x = rb_node_left (rt, x);
209 else
210 x = rb_node_right (rt, x);
211 return x;
212}
213
214rb_node_t *
215rb_tree_min_subtree (rb_tree_t * rt, rb_node_t * x)
216{
217 while (x->left != RBTREE_TNIL_INDEX)
218 x = rb_node_left (rt, x);
219 return x;
220}
221
222rb_node_t *
223rb_tree_max_subtree (rb_tree_t * rt, rb_node_t * x)
224{
225 while (x->right != RBTREE_TNIL_INDEX)
226 x = rb_node_right (rt, x);
227 return x;
228}
229
Florin Corasf7cda7a2019-04-19 18:50:34 -0700230rb_node_t *
231rb_tree_successor (rb_tree_t * rt, rb_node_t * x)
232{
233 rb_node_t *y;
234
235 if (x->right != RBTREE_TNIL_INDEX)
236 return rb_tree_min_subtree (rt, rb_node_right (rt, x));
237
238 y = rb_node_parent (rt, x);
239 while (!rb_node_is_tnil (rt, y) && y->right == rb_node_index (rt, x))
240 {
241 x = y;
242 y = rb_node_parent (rt, y);
243 }
244 return y;
245}
246
247rb_node_t *
248rb_tree_predecessor (rb_tree_t * rt, rb_node_t * x)
249{
250 rb_node_t *y;
251
252 if (x->left != RBTREE_TNIL_INDEX)
253 return rb_tree_max_subtree (rt, rb_node_left (rt, x));
254
255 y = rb_node_parent (rt, x);
256 while (!rb_node_is_tnil (rt, y) && y->left == rb_node_index (rt, x))
257 {
258 x = y;
259 y = rb_node_parent (rt, y);
260 }
261 return y;
262}
263
Florin Coras672d5fc2019-04-15 17:28:51 -0700264static inline void
265rb_tree_transplant (rb_tree_t * rt, rb_node_t * u, rb_node_t * v)
266{
267 rb_node_t *up;
268
269 up = rb_node_parent (rt, u);
270 if (u->parent == RBTREE_TNIL_INDEX)
271 rt->root = rb_node_index (rt, v);
272 else if (rb_node_index (rt, u) == up->left)
273 up->left = rb_node_index (rt, v);
274 else
275 up->right = rb_node_index (rt, v);
276 v->parent = u->parent;
277}
278
279void
280rb_tree_del_node (rb_tree_t * rt, rb_node_t * z)
281{
282 rb_node_color_t y_original_color;
283 rb_node_t *x, *y, *yr, *yl, *xp, *w, *wl, *wr;
284 rb_node_index_t xi, yi;
285
286 y = z;
287 y_original_color = y->color;
288
289 if (z->left == RBTREE_TNIL_INDEX)
290 {
291 x = rb_node_right (rt, z);
292 rb_tree_transplant (rt, z, x);
293 }
294 else if (z->right == RBTREE_TNIL_INDEX)
295 {
296 x = rb_node_left (rt, z);
297 rb_tree_transplant (rt, z, x);
298 }
299 else
300 {
301 y = rb_tree_min_subtree (rt, rb_node_right (rt, z));
302 y_original_color = y->color;
303 x = rb_node_right (rt, y);
304 yi = rb_node_index (rt, y);
305 if (y->parent == rb_node_index (rt, z))
306 x->parent = yi;
307 else
308 {
309 rb_tree_transplant (rt, y, rb_node_right (rt, y));
310 y->right = z->right;
311 yr = rb_node_right (rt, y);
312 yr->parent = yi;
313 }
314 rb_tree_transplant (rt, z, y);
315 y->left = z->left;
316 yl = rb_node_left (rt, y);
317 yl->parent = yi;
318 y->color = z->color;
319 }
320
321 if (y_original_color == RBTREE_RED)
322 return;
323
324 /* Tree fixup needed */
325
326 xi = rb_node_index (rt, x);
327 while (xi != rt->root && x->color == RBTREE_BLACK)
328 {
329 xp = rb_node_parent (rt, x);
330 if (xi == xp->left)
331 {
332 w = rb_node_right (rt, xp);
333 if (w->color == RBTREE_RED)
334 {
335 w->color = RBTREE_BLACK;
336 xp->color = RBTREE_RED;
337 rb_tree_rotate_left (rt, xp);
338 w = rb_node_right (rt, xp);
339 }
340 wl = rb_node_left (rt, w);
341 wr = rb_node_right (rt, w);
342 if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
343 {
344 w->color = RBTREE_RED;
345 x = xp;
346 }
347 else
348 {
349 if (wr->color == RBTREE_BLACK)
350 {
351 wl->color = RBTREE_BLACK;
352 w->color = RBTREE_RED;
353 rb_tree_rotate_right (rt, w);
354 w = rb_node_right (rt, xp);
355 }
356 w->color = xp->color;
357 xp->color = RBTREE_BLACK;
358 wr->color = RBTREE_BLACK;
359 rb_tree_rotate_left (rt, xp);
360 x = rb_node (rt, rt->root);
361 }
362 }
363 else
364 {
365 w = rb_node_left (rt, xp);
366 if (w->color == RBTREE_RED)
367 {
368 w->color = RBTREE_BLACK;
369 xp->color = RBTREE_RED;
370 rb_tree_rotate_right (rt, xp);
371 w = rb_node_left (rt, xp);
372 }
373 wl = rb_node_left (rt, w);
374 wr = rb_node_right (rt, w);
375 if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
376 {
377 w->color = RBTREE_RED;
378 x = xp;
379 }
380 else
381 {
382 if (wl->color == RBTREE_BLACK)
383 {
384 wr->color = RBTREE_BLACK;
385 w->color = RBTREE_RED;
386 rb_tree_rotate_left (rt, w);
387 w = rb_node_left (rt, xp);
388 }
389 w->color = xp->color;
390 xp->color = RBTREE_BLACK;
391 wl->color = RBTREE_BLACK;
392 rb_tree_rotate_right (rt, xp);
393 x = rb_node (rt, rt->root);
394 }
395 }
396 xi = rb_node_index (rt, x);
397 }
398 x->color = RBTREE_BLACK;
399}
400
401void
402rb_tree_del (rb_tree_t * rt, u32 key)
403{
404 rb_node_t *n;
405 n = rb_tree_search_subtree (rt, rb_node (rt, rt->root), key);
406 if (rb_node_index (rt, n) != RBTREE_TNIL_INDEX)
407 {
408 rb_tree_del_node (rt, n);
409 pool_put (rt->nodes, n);
410 }
411}
412
413u32
414rb_tree_n_nodes (rb_tree_t * rt)
415{
416 return pool_elts (rt->nodes);
417}
418
419void
420rb_tree_free_nodes (rb_tree_t * rt)
421{
422 rb_node_t *n;
423 pool_flush (n, rt->nodes,;);
424}
425
426void
427rb_tree_init (rb_tree_t * rt)
428{
429 rb_node_t *tnil;
430
431 rt->nodes = 0;
432 rt->root = RBTREE_TNIL_INDEX;
433
434 /* By convention first node, index 0, is the T.nil sentinel */
435 pool_get_zero (rt->nodes, tnil);
436 tnil->color = RBTREE_BLACK;
437}
438
439/*
440 * fd.io coding-style-patch-verification: ON
441 *
442 * Local Variables:
443 * eval: (c-set-style "gnu")
444 * End:
445 */