LCOV - code coverage report
Current view: top level - vppinfra - rbtree.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 195 279 69.9 %
Date: 2023-07-05 22:20:52 Functions: 15 22 68.2 %

          Line data    Source code
       1             : /*
       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             : 
      23             : static inline void
      24        2050 : rb_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        2050 :   xi = rb_node_index (rt, x);
      30        2050 :   yi = x->right;
      31        2050 :   y = rb_node_right (rt, x);
      32        2050 :   x->right = y->left;
      33        2050 :   if (y->left != RBTREE_TNIL_INDEX)
      34             :     {
      35        1023 :       tmp = rb_node_left (rt, y);
      36        1023 :       tmp->parent = xi;
      37             :     }
      38        2050 :   xp = rb_node_parent (rt, x);
      39        2050 :   y->parent = x->parent;
      40        2050 :   if (x->parent == RBTREE_TNIL_INDEX)
      41        1027 :     rt->root = rb_node_index (rt, y);
      42        1023 :   else if (xp->left == xi)
      43           1 :     xp->left = yi;
      44             :   else
      45        1022 :     xp->right = yi;
      46        2050 :   y->left = xi;
      47        2050 :   x->parent = yi;
      48        2050 : }
      49             : 
      50             : static inline void
      51           2 : rb_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           2 :   yi = rb_node_index (rt, y);
      57           2 :   xi = y->left;
      58           2 :   x = rb_node_left (rt, y);
      59           2 :   y->left = x->right;
      60           2 :   if (x->right != RBTREE_TNIL_INDEX)
      61             :     {
      62           1 :       rb_node_t *tmp = rb_node_right (rt, x);
      63           1 :       tmp->parent = yi;
      64             :     }
      65           2 :   yp = rb_node_parent (rt, y);
      66           2 :   x->parent = y->parent;
      67           2 :   if (y->parent == RBTREE_TNIL_INDEX)
      68           1 :     rt->root = rb_node_index (rt, x);
      69           1 :   else if (yp->right == yi)
      70           1 :     yp->right = xi;
      71             :   else
      72           0 :     yp->left = xi;
      73           2 :   x->right = yi;
      74           2 :   y->parent = xi;
      75           2 : }
      76             : 
      77             : static inline void
      78       10309 : rb_tree_fixup_inline (rb_tree_t * rt, rb_node_t * y, rb_node_t * z)
      79             : {
      80             :   rb_node_t *zpp, *zp;
      81             :   rb_node_index_t zi;
      82             : 
      83       12358 :   while (y->color == RBTREE_RED)
      84             :     {
      85        2049 :       zi = rb_node_index (rt, z);
      86        2049 :       zp = rb_node_parent (rt, z);
      87        2049 :       zpp = rb_node_parent (rt, zp);
      88        2049 :       if (z->parent == zpp->left)
      89             :         {
      90           1 :           y = rb_node_right (rt, zpp);
      91           1 :           if (y->color == RBTREE_RED)
      92             :             {
      93           0 :               zp->color = RBTREE_BLACK;
      94           0 :               y->color = RBTREE_BLACK;
      95           0 :               zpp->color = RBTREE_RED;
      96           0 :               z = zpp;
      97             :             }
      98             :           else
      99             :             {
     100           1 :               if (zi == zp->right)
     101             :                 {
     102           1 :                   z = zp;
     103           1 :                   rb_tree_rotate_left (rt, z);
     104           1 :                   zp = rb_node (rt, z->parent);
     105           1 :                   zpp = rb_node (rt, zp->parent);
     106             :                 }
     107           1 :               zp->color = RBTREE_BLACK;
     108           1 :               zpp->color = RBTREE_RED;
     109           1 :               rb_tree_rotate_right (rt, zpp);
     110             :             }
     111             :         }
     112             :       else
     113             :         {
     114        2048 :           y = rb_node (rt, zpp->left);
     115        2048 :           if (y->color == RBTREE_RED)
     116             :             {
     117        1023 :               zp->color = RBTREE_BLACK;
     118        1023 :               y->color = RBTREE_BLACK;
     119        1023 :               zpp->color = RBTREE_RED;
     120        1023 :               z = zpp;
     121             :             }
     122             :           else
     123             :             {
     124        1025 :               if (zi == zp->left)
     125             :                 {
     126           0 :                   z = zp;
     127           0 :                   rb_tree_rotate_right (rt, z);
     128           0 :                   zp = rb_node (rt, z->parent);
     129           0 :                   zpp = rb_node (rt, zp->parent);
     130             :                 }
     131        1025 :               zp->color = RBTREE_BLACK;
     132        1025 :               zpp->color = RBTREE_RED;
     133        1025 :               rb_tree_rotate_left (rt, zpp);
     134             :             }
     135             :         }
     136             :     }
     137       10309 :   rb_node (rt, rt->root)->color = RBTREE_BLACK;
     138       10309 : }
     139             : 
     140             : static void
     141           0 : rb_tree_insert (rb_tree_t * rt, rb_node_t * z)
     142             : {
     143           0 :   rb_node_index_t yi = 0, xi = rt->root;
     144             :   rb_node_t *y, *x;
     145             : 
     146           0 :   y = rb_node (rt, RBTREE_TNIL_INDEX);
     147           0 :   while (xi != RBTREE_TNIL_INDEX)
     148             :     {
     149           0 :       x = rb_node (rt, xi);
     150           0 :       y = x;
     151           0 :       if (z->key < x->key)
     152           0 :         xi = x->left;
     153             :       else
     154           0 :         xi = x->right;
     155             :     }
     156           0 :   yi = rb_node_index (rt, y);
     157           0 :   z->parent = yi;
     158           0 :   if (yi == RBTREE_TNIL_INDEX)
     159           0 :     rt->root = rb_node_index (rt, z);
     160           0 :   else if (z->key < y->key)
     161           0 :     y->left = rb_node_index (rt, z);
     162             :   else
     163           0 :     y->right = rb_node_index (rt, z);
     164             : 
     165             :   /* Tree fixup stage */
     166           0 :   rb_tree_fixup_inline (rt, y, z);
     167           0 : }
     168             : 
     169             : __clib_export rb_node_index_t
     170           0 : rb_tree_add (rb_tree_t * rt, u32 key)
     171             : {
     172             :   rb_node_t *n;
     173             : 
     174           0 :   pool_get_zero (rt->nodes, n);
     175           0 :   n->key = key;
     176           0 :   n->color = RBTREE_RED;
     177           0 :   rb_tree_insert (rt, n);
     178           0 :   return rb_node_index (rt, n);
     179             : }
     180             : 
     181             : __clib_export rb_node_index_t
     182           0 : rb_tree_add2 (rb_tree_t * rt, u32 key, uword opaque)
     183             : {
     184             :   rb_node_t *n;
     185             : 
     186           0 :   pool_get_zero (rt->nodes, n);
     187           0 :   n->key = key;
     188           0 :   n->color = RBTREE_RED;
     189           0 :   n->opaque = opaque;
     190           0 :   rb_tree_insert (rt, n);
     191           0 :   return rb_node_index (rt, n);
     192             : }
     193             : 
     194             : __clib_export rb_node_index_t
     195       10309 : rb_tree_add_custom (rb_tree_t * rt, u32 key, uword opaque, rb_tree_lt_fn ltfn)
     196             : {
     197       10309 :   rb_node_index_t yi = 0, xi = rt->root;
     198             :   rb_node_t *z, *y, *x;
     199             : 
     200       10309 :   pool_get_zero (rt->nodes, z);
     201       10309 :   z->key = key;
     202       10309 :   z->color = RBTREE_RED;
     203       10309 :   z->opaque = opaque;
     204             : 
     205       10309 :   y = rb_node (rt, RBTREE_TNIL_INDEX);
     206      536810 :   while (xi != RBTREE_TNIL_INDEX)
     207             :     {
     208      526501 :       x = rb_node (rt, xi);
     209      526501 :       y = x;
     210      526501 :       ASSERT (z->key != x->key);
     211      526501 :       if (ltfn (z->key, x->key))
     212           9 :         xi = x->left;
     213             :       else
     214      526492 :         xi = x->right;
     215             :     }
     216       10309 :   yi = rb_node_index (rt, y);
     217       10309 :   z->parent = yi;
     218       10309 :   if (yi == RBTREE_TNIL_INDEX)
     219        7086 :     rt->root = rb_node_index (rt, z);
     220        3223 :   else if (ltfn (z->key, y->key))
     221           4 :     y->left = rb_node_index (rt, z);
     222             :   else
     223        3219 :     y->right = rb_node_index (rt, z);
     224             : 
     225       10309 :   rb_tree_fixup_inline (rt, y, z);
     226             : 
     227       10309 :   return rb_node_index (rt, z);
     228             : }
     229             : 
     230             : __clib_export rb_node_t *
     231           0 : rb_tree_search_subtree (rb_tree_t * rt, rb_node_t * x, u32 key)
     232             : {
     233           0 :   while (rb_node_index (rt, x) != RBTREE_TNIL_INDEX && key != x->key)
     234           0 :     if (key < x->key)
     235           0 :       x = rb_node_left (rt, x);
     236             :     else
     237           0 :       x = rb_node_right (rt, x);
     238           0 :   return x;
     239             : }
     240             : 
     241             : __clib_export rb_node_t *
     242          25 : rb_tree_search_subtree_custom (rb_tree_t * rt, rb_node_t * x, u32 key,
     243             :                                rb_tree_lt_fn ltfn)
     244             : {
     245          46 :   while (rb_node_index (rt, x) != RBTREE_TNIL_INDEX && key != x->key)
     246          21 :     if (ltfn (key, x->key))
     247          12 :       x = rb_node_left (rt, x);
     248             :     else
     249           9 :       x = rb_node_right (rt, x);
     250          25 :   return x;
     251             : }
     252             : 
     253             : __clib_export rb_node_t *
     254           1 : rb_tree_min_subtree (rb_tree_t * rt, rb_node_t * x)
     255             : {
     256           2 :   while (x->left != RBTREE_TNIL_INDEX)
     257           1 :     x = rb_node_left (rt, x);
     258           1 :   return x;
     259             : }
     260             : 
     261             : __clib_export rb_node_t *
     262           0 : rb_tree_max_subtree (rb_tree_t * rt, rb_node_t * x)
     263             : {
     264           0 :   while (x->right != RBTREE_TNIL_INDEX)
     265           0 :     x = rb_node_right (rt, x);
     266           0 :   return x;
     267             : }
     268             : 
     269             : __clib_export rb_node_t *
     270           0 : rb_tree_successor (rb_tree_t * rt, rb_node_t * x)
     271             : {
     272             :   rb_node_t *y;
     273             : 
     274           0 :   if (x->right != RBTREE_TNIL_INDEX)
     275           0 :     return rb_tree_min_subtree (rt, rb_node_right (rt, x));
     276             : 
     277           0 :   y = rb_node_parent (rt, x);
     278           0 :   while (!rb_node_is_tnil (rt, y) && y->right == rb_node_index (rt, x))
     279             :     {
     280           0 :       x = y;
     281           0 :       y = rb_node_parent (rt, y);
     282             :     }
     283           0 :   return y;
     284             : }
     285             : 
     286             : __clib_export rb_node_t *
     287        1025 : rb_tree_predecessor (rb_tree_t * rt, rb_node_t * x)
     288             : {
     289             :   rb_node_t *y;
     290             : 
     291        1025 :   if (x->left != RBTREE_TNIL_INDEX)
     292           0 :     return rb_tree_max_subtree (rt, rb_node_left (rt, x));
     293             : 
     294        1025 :   y = rb_node_parent (rt, x);
     295        2045 :   while (!rb_node_is_tnil (rt, y) && y->left == rb_node_index (rt, x))
     296             :     {
     297        1020 :       x = y;
     298        1020 :       y = rb_node_parent (rt, y);
     299             :     }
     300        1025 :   return y;
     301             : }
     302             : 
     303             : static inline void
     304       10059 : rb_tree_transplant (rb_tree_t * rt, rb_node_t * u, rb_node_t * v)
     305             : {
     306             :   rb_node_t *up;
     307             : 
     308       10059 :   up = rb_node_parent (rt, u);
     309       10059 :   if (u->parent == RBTREE_TNIL_INDEX)
     310        8001 :     rt->root = rb_node_index (rt, v);
     311        2058 :   else if (rb_node_index (rt, u) == up->left)
     312        2053 :     up->left = rb_node_index (rt, v);
     313             :   else
     314           5 :     up->right = rb_node_index (rt, v);
     315       10059 :   v->parent = u->parent;
     316       10059 : }
     317             : 
     318             : static void
     319       10058 : rb_tree_del_node_internal (rb_tree_t * rt, rb_node_t * z)
     320             : {
     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       10058 :   y = z;
     326       10058 :   y_original_color = y->color;
     327             : 
     328       10058 :   if (z->left == RBTREE_TNIL_INDEX)
     329             :     {
     330       10057 :       x = rb_node_right (rt, z);
     331       10057 :       rb_tree_transplant (rt, z, x);
     332             :     }
     333           1 :   else if (z->right == RBTREE_TNIL_INDEX)
     334             :     {
     335           0 :       x = rb_node_left (rt, z);
     336           0 :       rb_tree_transplant (rt, z, x);
     337             :     }
     338             :   else
     339             :     {
     340           1 :       y = rb_tree_min_subtree (rt, rb_node_right (rt, z));
     341           1 :       y_original_color = y->color;
     342           1 :       x = rb_node_right (rt, y);
     343           1 :       yi = rb_node_index (rt, y);
     344           1 :       if (y->parent == rb_node_index (rt, z))
     345           0 :         x->parent = yi;
     346             :       else
     347             :         {
     348           1 :           rb_tree_transplant (rt, y, x);
     349           1 :           y->right = z->right;
     350           1 :           yr = rb_node_right (rt, y);
     351           1 :           yr->parent = yi;
     352             :         }
     353           1 :       rb_tree_transplant (rt, z, y);
     354           1 :       y->left = z->left;
     355           1 :       yl = rb_node_left (rt, y);
     356           1 :       yl->parent = yi;
     357           1 :       y->color = z->color;
     358             :     }
     359             : 
     360       10058 :   if (y_original_color == RBTREE_RED)
     361           5 :     return;
     362             : 
     363             :   /* Tree fixup needed */
     364             : 
     365       10053 :   xi = rb_node_index (rt, x);
     366       11082 :   while (xi != rt->root && x->color == RBTREE_BLACK)
     367             :     {
     368        1029 :       xp = rb_node_parent (rt, x);
     369        1029 :       if (xi == xp->left)
     370             :         {
     371        1028 :           w = rb_node_right (rt, xp);
     372        1028 :           if (w->color == RBTREE_RED)
     373             :             {
     374        1019 :               w->color = RBTREE_BLACK;
     375        1019 :               xp->color = RBTREE_RED;
     376        1019 :               rb_tree_rotate_left (rt, xp);
     377        1019 :               w = rb_node_right (rt, xp);
     378             :             }
     379        1028 :           wl = rb_node_left (rt, w);
     380        1028 :           wr = rb_node_right (rt, w);
     381        1028 :           if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
     382             :             {
     383        1023 :               if (!rb_node_is_tnil (rt, w))
     384        1023 :                 w->color = RBTREE_RED;
     385        1023 :               x = xp;
     386             :             }
     387             :           else
     388             :             {
     389           5 :               if (wr->color == RBTREE_BLACK)
     390             :                 {
     391           0 :                   wl->color = RBTREE_BLACK;
     392           0 :                   w->color = RBTREE_RED;
     393           0 :                   rb_tree_rotate_right (rt, w);
     394           0 :                   w = rb_node_right (rt, xp);
     395           0 :                   wr = rb_node_right (rt, w);
     396             :                 }
     397           5 :               w->color = xp->color;
     398           5 :               xp->color = RBTREE_BLACK;
     399           5 :               wr->color = RBTREE_BLACK;
     400           5 :               rb_tree_rotate_left (rt, xp);
     401           5 :               x = rb_node (rt, rt->root);
     402             :             }
     403             :         }
     404             :       else
     405             :         {
     406           1 :           w = rb_node_left (rt, xp);
     407           1 :           if (w->color == RBTREE_RED)
     408             :             {
     409           0 :               w->color = RBTREE_BLACK;
     410           0 :               xp->color = RBTREE_RED;
     411           0 :               rb_tree_rotate_right (rt, xp);
     412           0 :               w = rb_node_left (rt, xp);
     413             :             }
     414           1 :           wl = rb_node_left (rt, w);
     415           1 :           wr = rb_node_right (rt, w);
     416           1 :           if (wl->color == RBTREE_BLACK && wr->color == RBTREE_BLACK)
     417             :             {
     418           0 :               if (!rb_node_is_tnil (rt, w))
     419           0 :                 w->color = RBTREE_RED;
     420           0 :               x = xp;
     421             :             }
     422             :           else
     423             :             {
     424           1 :               if (wl->color == RBTREE_BLACK)
     425             :                 {
     426           0 :                   wr->color = RBTREE_BLACK;
     427           0 :                   w->color = RBTREE_RED;
     428           0 :                   rb_tree_rotate_left (rt, w);
     429           0 :                   w = rb_node_left (rt, xp);
     430           0 :                   wl = rb_node_left (rt, w);
     431             :                 }
     432           1 :               w->color = xp->color;
     433           1 :               xp->color = RBTREE_BLACK;
     434           1 :               wl->color = RBTREE_BLACK;
     435           1 :               rb_tree_rotate_right (rt, xp);
     436           1 :               x = rb_node (rt, rt->root);
     437             :             }
     438             :         }
     439        1029 :       xi = rb_node_index (rt, x);
     440             :     }
     441       10053 :   x->color = RBTREE_BLACK;
     442             : }
     443             : 
     444             : __clib_export void
     445       10058 : rb_tree_del_node (rb_tree_t * rt, rb_node_t * z)
     446             : {
     447       10058 :   rb_tree_del_node_internal (rt, z);
     448       10058 :   pool_put (rt->nodes, z);
     449       10058 : }
     450             : 
     451             : __clib_export void
     452           0 : rb_tree_del (rb_tree_t * rt, u32 key)
     453             : {
     454             :   rb_node_t *n;
     455           0 :   n = rb_tree_search_subtree (rt, rb_node (rt, rt->root), key);
     456           0 :   if (rb_node_index (rt, n) != RBTREE_TNIL_INDEX)
     457           0 :     rb_tree_del_node (rt, n);
     458           0 : }
     459             : 
     460             : __clib_export void
     461          20 : rb_tree_del_custom (rb_tree_t * rt, u32 key, rb_tree_lt_fn ltfn)
     462             : {
     463             :   rb_node_t *n;
     464          20 :   n = rb_tree_search_subtree_custom (rt, rb_node (rt, rt->root), key, ltfn);
     465          20 :   if (rb_node_index (rt, n) != RBTREE_TNIL_INDEX)
     466          20 :     rb_tree_del_node (rt, n);
     467          20 : }
     468             : 
     469             : __clib_export u32
     470      827231 : rb_tree_n_nodes (rb_tree_t * rt)
     471             : {
     472      827231 :   return pool_elts (rt->nodes);
     473             : }
     474             : 
     475             : __clib_export void
     476        1411 : rb_tree_free_nodes (rb_tree_t * rt)
     477             : {
     478        1411 :   pool_free (rt->nodes);
     479        1411 :   rt->root = RBTREE_TNIL_INDEX;
     480        1411 : }
     481             : 
     482             : __clib_export void
     483         554 : rb_tree_init (rb_tree_t * rt)
     484             : {
     485             :   rb_node_t *tnil;
     486             : 
     487         554 :   rt->nodes = 0;
     488         554 :   rt->root = RBTREE_TNIL_INDEX;
     489             : 
     490             :   /* By convention first node, index 0, is the T.nil sentinel */
     491         554 :   pool_get_zero (rt->nodes, tnil);
     492         554 :   tnil->color = RBTREE_BLACK;
     493         554 : }
     494             : 
     495             : __clib_export int
     496       36026 : rb_tree_is_init (rb_tree_t * rt)
     497             : {
     498       36026 :   if (pool_elts (rt->nodes) == 0)
     499       24129 :     return 0;
     500       11897 :   return 1;
     501             : }
     502             : 
     503             : /*
     504             :  * fd.io coding-style-patch-verification: ON
     505             :  *
     506             :  * Local Variables:
     507             :  * eval: (c-set-style "gnu")
     508             :  * End:
     509             :  */

Generated by: LCOV version 1.14