blob: d99367a2c6fb5b40f509b3010746075fee0788db [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
230static inline void
231rb_tree_transplant (rb_tree_t * rt, rb_node_t * u, rb_node_t * v)
232{
233 rb_node_t *up;
234
235 up = rb_node_parent (rt, u);
236 if (u->parent == RBTREE_TNIL_INDEX)
237 rt->root = rb_node_index (rt, v);
238 else if (rb_node_index (rt, u) == up->left)
239 up->left = rb_node_index (rt, v);
240 else
241 up->right = rb_node_index (rt, v);
242 v->parent = u->parent;
243}
244
245void
246rb_tree_del_node (rb_tree_t * rt, rb_node_t * z)
247{
248 rb_node_color_t y_original_color;
249 rb_node_t *x, *y, *yr, *yl, *xp, *w, *wl, *wr;
250 rb_node_index_t xi, yi;
251
252 y = z;
253 y_original_color = y->color;
254
255 if (z->left == RBTREE_TNIL_INDEX)
256 {
257 x = rb_node_right (rt, z);
258 rb_tree_transplant (rt, z, x);
259 }
260 else if (z->right == RBTREE_TNIL_INDEX)
261 {
262 x = rb_node_left (rt, z);
263 rb_tree_transplant (rt, z, x);
264 }
265 else
266 {
267 y = rb_tree_min_subtree (rt, rb_node_right (rt, z));
268 y_original_color = y->color;
269 x = rb_node_right (rt, y);
270 yi = rb_node_index (rt, y);
271 if (y->parent == rb_node_index (rt, z))
272 x->parent = yi;
273 else
274 {
275 rb_tree_transplant (rt, y, rb_node_right (rt, y));
276 y->right = z->right;
277 yr = rb_node_right (rt, y);
278 yr->parent = yi;
279 }
280 rb_tree_transplant (rt, z, y);
281 y->left = z->left;
282 yl = rb_node_left (rt, y);
283 yl->parent = yi;
284 y->color = z->color;
285 }
286
287 if (y_original_color == RBTREE_RED)
288 return;
289
290 /* Tree fixup needed */
291
292 xi = rb_node_index (rt, x);
293 while (xi != rt->root && x->color == RBTREE_BLACK)
294 {
295 xp = rb_node_parent (rt, x);
296 if (xi == xp->left)
297 {
298 w = rb_node_right (rt, xp);
299 if (w->color == RBTREE_RED)
300 {
301 w->color = RBTREE_BLACK;
302 xp->color = RBTREE_RED;
303 rb_tree_rotate_left (rt, xp);
304 w = rb_node_right (rt, xp);
305 }
306 wl = rb_node_left (rt, w);
307 wr = rb_node_right (rt, w);
308 if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
309 {
310 w->color = RBTREE_RED;
311 x = xp;
312 }
313 else
314 {
315 if (wr->color == RBTREE_BLACK)
316 {
317 wl->color = RBTREE_BLACK;
318 w->color = RBTREE_RED;
319 rb_tree_rotate_right (rt, w);
320 w = rb_node_right (rt, xp);
321 }
322 w->color = xp->color;
323 xp->color = RBTREE_BLACK;
324 wr->color = RBTREE_BLACK;
325 rb_tree_rotate_left (rt, xp);
326 x = rb_node (rt, rt->root);
327 }
328 }
329 else
330 {
331 w = rb_node_left (rt, xp);
332 if (w->color == RBTREE_RED)
333 {
334 w->color = RBTREE_BLACK;
335 xp->color = RBTREE_RED;
336 rb_tree_rotate_right (rt, xp);
337 w = rb_node_left (rt, xp);
338 }
339 wl = rb_node_left (rt, w);
340 wr = rb_node_right (rt, w);
341 if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
342 {
343 w->color = RBTREE_RED;
344 x = xp;
345 }
346 else
347 {
348 if (wl->color == RBTREE_BLACK)
349 {
350 wr->color = RBTREE_BLACK;
351 w->color = RBTREE_RED;
352 rb_tree_rotate_left (rt, w);
353 w = rb_node_left (rt, xp);
354 }
355 w->color = xp->color;
356 xp->color = RBTREE_BLACK;
357 wl->color = RBTREE_BLACK;
358 rb_tree_rotate_right (rt, xp);
359 x = rb_node (rt, rt->root);
360 }
361 }
362 xi = rb_node_index (rt, x);
363 }
364 x->color = RBTREE_BLACK;
365}
366
367void
368rb_tree_del (rb_tree_t * rt, u32 key)
369{
370 rb_node_t *n;
371 n = rb_tree_search_subtree (rt, rb_node (rt, rt->root), key);
372 if (rb_node_index (rt, n) != RBTREE_TNIL_INDEX)
373 {
374 rb_tree_del_node (rt, n);
375 pool_put (rt->nodes, n);
376 }
377}
378
379u32
380rb_tree_n_nodes (rb_tree_t * rt)
381{
382 return pool_elts (rt->nodes);
383}
384
385void
386rb_tree_free_nodes (rb_tree_t * rt)
387{
388 rb_node_t *n;
389 pool_flush (n, rt->nodes,;);
390}
391
392void
393rb_tree_init (rb_tree_t * rt)
394{
395 rb_node_t *tnil;
396
397 rt->nodes = 0;
398 rt->root = RBTREE_TNIL_INDEX;
399
400 /* By convention first node, index 0, is the T.nil sentinel */
401 pool_get_zero (rt->nodes, tnil);
402 tnil->color = RBTREE_BLACK;
403}
404
405/*
406 * fd.io coding-style-patch-verification: ON
407 *
408 * Local Variables:
409 * eval: (c-set-style "gnu")
410 * End:
411 */