LCOV - code coverage report
Current view: top level - src/backend/lib - rbtree.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 48.4 % 308 149
Test Date: 2026-01-26 10:56:24 Functions: 52.9 % 17 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 35.6 % 163 58

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * rbtree.c
       4                 :             :  *        implementation for PostgreSQL generic Red-Black binary tree package
       5                 :             :  *        Adopted from http://algolist.manual.ru/ds/rbtree.php
       6                 :             :  *
       7                 :             :  * This code comes from Thomas Niemann's "Sorting and Searching Algorithms:
       8                 :             :  * a Cookbook".
       9                 :             :  *
      10                 :             :  * See https://web.archive.org/web/20131202103513/http://www.cs.auckland.ac.nz/software/AlgAnim/niemann/s_man.htm
      11                 :             :  * for license terms: "Source code, when part of a software project, may be
      12                 :             :  * used freely without reference to the author."
      13                 :             :  *
      14                 :             :  * Red-black trees are a type of balanced binary tree wherein (1) any child of
      15                 :             :  * a red node is always black, and (2) every path from root to leaf traverses
      16                 :             :  * an equal number of black nodes.  From these properties, it follows that the
      17                 :             :  * longest path from root to leaf is only about twice as long as the shortest,
      18                 :             :  * so lookups are guaranteed to run in O(lg n) time.
      19                 :             :  *
      20                 :             :  * Copyright (c) 2009-2026, PostgreSQL Global Development Group
      21                 :             :  *
      22                 :             :  * IDENTIFICATION
      23                 :             :  *        src/backend/lib/rbtree.c
      24                 :             :  *
      25                 :             :  *-------------------------------------------------------------------------
      26                 :             :  */
      27                 :             : #include "postgres.h"
      28                 :             : 
      29                 :             : #include "lib/rbtree.h"
      30                 :             : 
      31                 :             : 
      32                 :             : /*
      33                 :             :  * Colors of nodes (values of RBTNode.color)
      34                 :             :  */
      35                 :             : #define RBTBLACK        (0)
      36                 :             : #define RBTRED          (1)
      37                 :             : 
      38                 :             : /*
      39                 :             :  * RBTree control structure
      40                 :             :  */
      41                 :             : struct RBTree
      42                 :             : {
      43                 :             :         RBTNode    *root;                       /* root node, or RBTNIL if tree is empty */
      44                 :             : 
      45                 :             :         /* Remaining fields are constant after rbt_create */
      46                 :             : 
      47                 :             :         Size            node_size;              /* actual size of tree nodes */
      48                 :             :         /* The caller-supplied manipulation functions */
      49                 :             :         rbt_comparator comparator;
      50                 :             :         rbt_combiner combiner;
      51                 :             :         rbt_allocfunc allocfunc;
      52                 :             :         rbt_freefunc freefunc;
      53                 :             :         /* Passthrough arg passed to all manipulation functions */
      54                 :             :         void       *arg;
      55                 :             : };
      56                 :             : 
      57                 :             : /*
      58                 :             :  * all leafs are sentinels, use customized NIL name to prevent
      59                 :             :  * collision with system-wide constant NIL which is actually NULL
      60                 :             :  */
      61                 :             : #define RBTNIL (&sentinel)
      62                 :             : 
      63                 :             : static RBTNode sentinel =
      64                 :             : {
      65                 :             :         .color = RBTBLACK,.left = RBTNIL,.right = RBTNIL,.parent = NULL
      66                 :             : };
      67                 :             : 
      68                 :             : 
      69                 :             : /*
      70                 :             :  * rbt_create: create an empty RBTree
      71                 :             :  *
      72                 :             :  * Arguments are:
      73                 :             :  *      node_size: actual size of tree nodes (> sizeof(RBTNode))
      74                 :             :  *      The manipulation functions:
      75                 :             :  *      comparator: compare two RBTNodes for less/equal/greater
      76                 :             :  *      combiner: merge an existing tree entry with a new one
      77                 :             :  *      allocfunc: allocate a new RBTNode
      78                 :             :  *      freefunc: free an old RBTNode
      79                 :             :  *      arg: passthrough pointer that will be passed to the manipulation functions
      80                 :             :  *
      81                 :             :  * Note that the combiner's righthand argument will be a "proposed" tree node,
      82                 :             :  * ie the input to rbt_insert, in which the RBTNode fields themselves aren't
      83                 :             :  * valid.  Similarly, either input to the comparator may be a "proposed" node.
      84                 :             :  * This shouldn't matter since the functions aren't supposed to look at the
      85                 :             :  * RBTNode fields, only the extra fields of the struct the RBTNode is embedded
      86                 :             :  * in.
      87                 :             :  *
      88                 :             :  * The freefunc should just be pfree or equivalent; it should NOT attempt
      89                 :             :  * to free any subsidiary data, because the node passed to it may not contain
      90                 :             :  * valid data!  freefunc can be NULL if caller doesn't require retail
      91                 :             :  * space reclamation.
      92                 :             :  *
      93                 :             :  * The RBTree node is palloc'd in the caller's memory context.  Note that
      94                 :             :  * all contents of the tree are actually allocated by the caller, not here.
      95                 :             :  *
      96                 :             :  * Since tree contents are managed by the caller, there is currently not
      97                 :             :  * an explicit "destroy" operation; typically a tree would be freed by
      98                 :             :  * resetting or deleting the memory context it's stored in.  You can pfree
      99                 :             :  * the RBTree node if you feel the urge.
     100                 :             :  */
     101                 :             : RBTree *
     102                 :          22 : rbt_create(Size node_size,
     103                 :             :                    rbt_comparator comparator,
     104                 :             :                    rbt_combiner combiner,
     105                 :             :                    rbt_allocfunc allocfunc,
     106                 :             :                    rbt_freefunc freefunc,
     107                 :             :                    void *arg)
     108                 :             : {
     109                 :          22 :         RBTree     *tree = palloc_object(RBTree);
     110                 :             : 
     111         [ +  - ]:          22 :         Assert(node_size > sizeof(RBTNode));
     112                 :             : 
     113                 :          22 :         tree->root = RBTNIL;
     114                 :          22 :         tree->node_size = node_size;
     115                 :          22 :         tree->comparator = comparator;
     116                 :          22 :         tree->combiner = combiner;
     117                 :          22 :         tree->allocfunc = allocfunc;
     118                 :          22 :         tree->freefunc = freefunc;
     119                 :             : 
     120                 :          22 :         tree->arg = arg;
     121                 :             : 
     122                 :          44 :         return tree;
     123                 :          22 : }
     124                 :             : 
     125                 :             : /* Copy the additional data fields from one RBTNode to another */
     126                 :             : static inline void
     127                 :       75500 : rbt_copy_data(RBTree *rbt, RBTNode *dest, const RBTNode *src)
     128                 :             : {
     129                 :       75500 :         memcpy(dest + 1, src + 1, rbt->node_size - sizeof(RBTNode));
     130                 :       75500 : }
     131                 :             : 
     132                 :             : /**********************************************************************
     133                 :             :  *                                                Search                                                                          *
     134                 :             :  **********************************************************************/
     135                 :             : 
     136                 :             : /*
     137                 :             :  * rbt_find: search for a value in an RBTree
     138                 :             :  *
     139                 :             :  * data represents the value to try to find.  Its RBTNode fields need not
     140                 :             :  * be valid, it's the extra data in the larger struct that is of interest.
     141                 :             :  *
     142                 :             :  * Returns the matching tree entry, or NULL if no match is found.
     143                 :             :  */
     144                 :             : RBTNode *
     145                 :           0 : rbt_find(RBTree *rbt, const RBTNode *data)
     146                 :             : {
     147                 :           0 :         RBTNode    *node = rbt->root;
     148                 :             : 
     149         [ #  # ]:           0 :         while (node != RBTNIL)
     150                 :             :         {
     151                 :           0 :                 int                     cmp = rbt->comparator(data, node, rbt->arg);
     152                 :             : 
     153         [ #  # ]:           0 :                 if (cmp == 0)
     154                 :           0 :                         return node;
     155         [ #  # ]:           0 :                 else if (cmp < 0)
     156                 :           0 :                         node = node->left;
     157                 :             :                 else
     158                 :           0 :                         node = node->right;
     159         [ #  # ]:           0 :         }
     160                 :             : 
     161                 :           0 :         return NULL;
     162                 :           0 : }
     163                 :             : 
     164                 :             : /*
     165                 :             :  * rbt_find_great: search for a greater value in an RBTree
     166                 :             :  *
     167                 :             :  * If equal_match is true, this will be a great or equal search.
     168                 :             :  *
     169                 :             :  * Returns the matching tree entry, or NULL if no match is found.
     170                 :             :  */
     171                 :             : RBTNode *
     172                 :           0 : rbt_find_great(RBTree *rbt, const RBTNode *data, bool equal_match)
     173                 :             : {
     174                 :           0 :         RBTNode    *node = rbt->root;
     175                 :           0 :         RBTNode    *greater = NULL;
     176                 :             : 
     177         [ #  # ]:           0 :         while (node != RBTNIL)
     178                 :             :         {
     179                 :           0 :                 int                     cmp = rbt->comparator(data, node, rbt->arg);
     180                 :             : 
     181   [ #  #  #  # ]:           0 :                 if (equal_match && cmp == 0)
     182                 :           0 :                         return node;
     183         [ #  # ]:           0 :                 else if (cmp < 0)
     184                 :             :                 {
     185                 :           0 :                         greater = node;
     186                 :           0 :                         node = node->left;
     187                 :           0 :                 }
     188                 :             :                 else
     189                 :           0 :                         node = node->right;
     190         [ #  # ]:           0 :         }
     191                 :             : 
     192                 :           0 :         return greater;
     193                 :           0 : }
     194                 :             : 
     195                 :             : /*
     196                 :             :  * rbt_find_less: search for a lesser value in an RBTree
     197                 :             :  *
     198                 :             :  * If equal_match is true, this will be a less or equal search.
     199                 :             :  *
     200                 :             :  * Returns the matching tree entry, or NULL if no match is found.
     201                 :             :  */
     202                 :             : RBTNode *
     203                 :           0 : rbt_find_less(RBTree *rbt, const RBTNode *data, bool equal_match)
     204                 :             : {
     205                 :           0 :         RBTNode    *node = rbt->root;
     206                 :           0 :         RBTNode    *lesser = NULL;
     207                 :             : 
     208         [ #  # ]:           0 :         while (node != RBTNIL)
     209                 :             :         {
     210                 :           0 :                 int                     cmp = rbt->comparator(data, node, rbt->arg);
     211                 :             : 
     212   [ #  #  #  # ]:           0 :                 if (equal_match && cmp == 0)
     213                 :           0 :                         return node;
     214         [ #  # ]:           0 :                 else if (cmp > 0)
     215                 :             :                 {
     216                 :           0 :                         lesser = node;
     217                 :           0 :                         node = node->right;
     218                 :           0 :                 }
     219                 :             :                 else
     220                 :           0 :                         node = node->left;
     221         [ #  # ]:           0 :         }
     222                 :             : 
     223                 :           0 :         return lesser;
     224                 :           0 : }
     225                 :             : 
     226                 :             : /*
     227                 :             :  * rbt_leftmost: fetch the leftmost (smallest-valued) tree node.
     228                 :             :  * Returns NULL if tree is empty.
     229                 :             :  *
     230                 :             :  * Note: in the original implementation this included an unlink step, but
     231                 :             :  * that's a bit awkward.  Just call rbt_delete on the result if that's what
     232                 :             :  * you want.
     233                 :             :  */
     234                 :             : RBTNode *
     235                 :           0 : rbt_leftmost(RBTree *rbt)
     236                 :             : {
     237                 :           0 :         RBTNode    *node = rbt->root;
     238                 :           0 :         RBTNode    *leftmost = rbt->root;
     239                 :             : 
     240         [ #  # ]:           0 :         while (node != RBTNIL)
     241                 :             :         {
     242                 :           0 :                 leftmost = node;
     243                 :           0 :                 node = node->left;
     244                 :             :         }
     245                 :             : 
     246         [ #  # ]:           0 :         if (leftmost != RBTNIL)
     247                 :           0 :                 return leftmost;
     248                 :             : 
     249                 :           0 :         return NULL;
     250                 :           0 : }
     251                 :             : 
     252                 :             : /**********************************************************************
     253                 :             :  *                                                        Insertion                                                               *
     254                 :             :  **********************************************************************/
     255                 :             : 
     256                 :             : /*
     257                 :             :  * Rotate node x to left.
     258                 :             :  *
     259                 :             :  * x's right child takes its place in the tree, and x becomes the left
     260                 :             :  * child of that node.
     261                 :             :  */
     262                 :             : static void
     263                 :       72602 : rbt_rotate_left(RBTree *rbt, RBTNode *x)
     264                 :             : {
     265                 :       72602 :         RBTNode    *y = x->right;
     266                 :             : 
     267                 :             :         /* establish x->right link */
     268                 :       72602 :         x->right = y->left;
     269         [ +  + ]:       72602 :         if (y->left != RBTNIL)
     270                 :       35967 :                 y->left->parent = x;
     271                 :             : 
     272                 :             :         /* establish y->parent link */
     273         [ -  + ]:       72602 :         if (y != RBTNIL)
     274                 :       72602 :                 y->parent = x->parent;
     275         [ +  + ]:       72602 :         if (x->parent)
     276                 :             :         {
     277         [ +  + ]:       72566 :                 if (x == x->parent->left)
     278                 :       21084 :                         x->parent->left = y;
     279                 :             :                 else
     280                 :       51482 :                         x->parent->right = y;
     281                 :       72566 :         }
     282                 :             :         else
     283                 :             :         {
     284                 :          36 :                 rbt->root = y;
     285                 :             :         }
     286                 :             : 
     287                 :             :         /* link x and y */
     288                 :       72602 :         y->left = x;
     289         [ -  + ]:       72602 :         if (x != RBTNIL)
     290                 :       72602 :                 x->parent = y;
     291                 :       72602 : }
     292                 :             : 
     293                 :             : /*
     294                 :             :  * Rotate node x to right.
     295                 :             :  *
     296                 :             :  * x's left right child takes its place in the tree, and x becomes the right
     297                 :             :  * child of that node.
     298                 :             :  */
     299                 :             : static void
     300                 :       16367 : rbt_rotate_right(RBTree *rbt, RBTNode *x)
     301                 :             : {
     302                 :       16367 :         RBTNode    *y = x->left;
     303                 :             : 
     304                 :             :         /* establish x->left link */
     305                 :       16367 :         x->left = y->right;
     306         [ +  + ]:       16367 :         if (y->right != RBTNIL)
     307                 :        5459 :                 y->right->parent = x;
     308                 :             : 
     309                 :             :         /* establish y->parent link */
     310         [ -  + ]:       16367 :         if (y != RBTNIL)
     311                 :       16367 :                 y->parent = x->parent;
     312         [ +  + ]:       16367 :         if (x->parent)
     313                 :             :         {
     314         [ +  + ]:       16354 :                 if (x == x->parent->right)
     315                 :       15925 :                         x->parent->right = y;
     316                 :             :                 else
     317                 :         429 :                         x->parent->left = y;
     318                 :       16354 :         }
     319                 :             :         else
     320                 :             :         {
     321                 :          13 :                 rbt->root = y;
     322                 :             :         }
     323                 :             : 
     324                 :             :         /* link x and y */
     325                 :       16367 :         y->right = x;
     326         [ -  + ]:       16367 :         if (x != RBTNIL)
     327                 :       16367 :                 x->parent = y;
     328                 :       16367 : }
     329                 :             : 
     330                 :             : /*
     331                 :             :  * Maintain Red-Black tree balance after inserting node x.
     332                 :             :  *
     333                 :             :  * The newly inserted node is always initially marked red.  That may lead to
     334                 :             :  * a situation where a red node has a red child, which is prohibited.  We can
     335                 :             :  * always fix the problem by a series of color changes and/or "rotations",
     336                 :             :  * which move the problem progressively higher up in the tree.  If one of the
     337                 :             :  * two red nodes is the root, we can always fix the problem by changing the
     338                 :             :  * root from red to black.
     339                 :             :  *
     340                 :             :  * (This does not work lower down in the tree because we must also maintain
     341                 :             :  * the invariant that every leaf has equal black-height.)
     342                 :             :  */
     343                 :             : static void
     344                 :       75500 : rbt_insert_fixup(RBTree *rbt, RBTNode *x)
     345                 :             : {
     346                 :             :         /*
     347                 :             :          * x is always a red node.  Initially, it is the newly inserted node. Each
     348                 :             :          * iteration of this loop moves it higher up in the tree.
     349                 :             :          */
     350   [ +  +  +  + ]:      221874 :         while (x != rbt->root && x->parent->color == RBTRED)
     351                 :             :         {
     352                 :             :                 /*
     353                 :             :                  * x and x->parent are both red.  Fix depends on whether x->parent is
     354                 :             :                  * a left or right child.  In either case, we define y to be the
     355                 :             :                  * "uncle" of x, that is, the other child of x's grandparent.
     356                 :             :                  *
     357                 :             :                  * If the uncle is red, we flip the grandparent to red and its two
     358                 :             :                  * children to black.  Then we loop around again to check whether the
     359                 :             :                  * grandparent still has a problem.
     360                 :             :                  *
     361                 :             :                  * If the uncle is black, we will perform one or two "rotations" to
     362                 :             :                  * balance the tree.  Either x or x->parent will take the
     363                 :             :                  * grandparent's position in the tree and recolored black, and the
     364                 :             :                  * original grandparent will be recolored red and become a child of
     365                 :             :                  * that node. This always leaves us with a valid red-black tree, so
     366                 :             :                  * the loop will terminate.
     367                 :             :                  */
     368         [ +  + ]:      146374 :                 if (x->parent == x->parent->parent->left)
     369                 :             :                 {
     370                 :       16964 :                         RBTNode    *y = x->parent->parent->right;
     371                 :             : 
     372         [ +  + ]:       16964 :                         if (y->color == RBTRED)
     373                 :             :                         {
     374                 :             :                                 /* uncle is RBTRED */
     375                 :         999 :                                 x->parent->color = RBTBLACK;
     376                 :         999 :                                 y->color = RBTBLACK;
     377                 :         999 :                                 x->parent->parent->color = RBTRED;
     378                 :             : 
     379                 :         999 :                                 x = x->parent->parent;
     380                 :         999 :                         }
     381                 :             :                         else
     382                 :             :                         {
     383                 :             :                                 /* uncle is RBTBLACK */
     384         [ +  + ]:       15965 :                                 if (x == x->parent->right)
     385                 :             :                                 {
     386                 :             :                                         /* make x a left child */
     387                 :       15617 :                                         x = x->parent;
     388                 :       15617 :                                         rbt_rotate_left(rbt, x);
     389                 :       15617 :                                 }
     390                 :             : 
     391                 :             :                                 /* recolor and rotate */
     392                 :       15965 :                                 x->parent->color = RBTBLACK;
     393                 :       15965 :                                 x->parent->parent->color = RBTRED;
     394                 :             : 
     395                 :       15965 :                                 rbt_rotate_right(rbt, x->parent->parent);
     396                 :             :                         }
     397                 :       16964 :                 }
     398                 :             :                 else
     399                 :             :                 {
     400                 :             :                         /* mirror image of above code */
     401                 :      129410 :                         RBTNode    *y = x->parent->parent->left;
     402                 :             : 
     403         [ +  + ]:      129410 :                         if (y->color == RBTRED)
     404                 :             :                         {
     405                 :             :                                 /* uncle is RBTRED */
     406                 :       72425 :                                 x->parent->color = RBTBLACK;
     407                 :       72425 :                                 y->color = RBTBLACK;
     408                 :       72425 :                                 x->parent->parent->color = RBTRED;
     409                 :             : 
     410                 :       72425 :                                 x = x->parent->parent;
     411                 :       72425 :                         }
     412                 :             :                         else
     413                 :             :                         {
     414                 :             :                                 /* uncle is RBTBLACK */
     415         [ +  + ]:       56985 :                                 if (x == x->parent->left)
     416                 :             :                                 {
     417                 :         402 :                                         x = x->parent;
     418                 :         402 :                                         rbt_rotate_right(rbt, x);
     419                 :         402 :                                 }
     420                 :       56985 :                                 x->parent->color = RBTBLACK;
     421                 :       56985 :                                 x->parent->parent->color = RBTRED;
     422                 :             : 
     423                 :       56985 :                                 rbt_rotate_left(rbt, x->parent->parent);
     424                 :             :                         }
     425                 :      129410 :                 }
     426                 :             :         }
     427                 :             : 
     428                 :             :         /*
     429                 :             :          * The root may already have been black; if not, the black-height of every
     430                 :             :          * node in the tree increases by one.
     431                 :             :          */
     432                 :       75500 :         rbt->root->color = RBTBLACK;
     433                 :       75500 : }
     434                 :             : 
     435                 :             : /*
     436                 :             :  * rbt_insert: insert a new value into the tree.
     437                 :             :  *
     438                 :             :  * data represents the value to insert.  Its RBTNode fields need not
     439                 :             :  * be valid, it's the extra data in the larger struct that is of interest.
     440                 :             :  *
     441                 :             :  * If the value represented by "data" is not present in the tree, then
     442                 :             :  * we copy "data" into a new tree entry and return that node, setting *isNew
     443                 :             :  * to true.
     444                 :             :  *
     445                 :             :  * If the value represented by "data" is already present, then we call the
     446                 :             :  * combiner function to merge data into the existing node, and return the
     447                 :             :  * existing node, setting *isNew to false.
     448                 :             :  *
     449                 :             :  * "data" is unmodified in either case; it's typically just a local
     450                 :             :  * variable in the caller.
     451                 :             :  */
     452                 :             : RBTNode *
     453                 :      269654 : rbt_insert(RBTree *rbt, const RBTNode *data, bool *isNew)
     454                 :             : {
     455                 :      269654 :         RBTNode    *current,
     456                 :             :                            *parent,
     457                 :             :                            *x;
     458                 :      269654 :         int                     cmp;
     459                 :             : 
     460                 :             :         /* find where node belongs */
     461                 :      269654 :         current = rbt->root;
     462                 :      269654 :         parent = NULL;
     463                 :      269654 :         cmp = 0;                                        /* just to prevent compiler warning */
     464                 :             : 
     465         [ +  + ]:     3857789 :         while (current != RBTNIL)
     466                 :             :         {
     467                 :     3782289 :                 cmp = rbt->comparator(data, current, rbt->arg);
     468         [ +  + ]:     3782289 :                 if (cmp == 0)
     469                 :             :                 {
     470                 :             :                         /*
     471                 :             :                          * Found node with given key.  Apply combiner.
     472                 :             :                          */
     473                 :      194154 :                         rbt->combiner(current, data, rbt->arg);
     474                 :      194154 :                         *isNew = false;
     475                 :      194154 :                         return current;
     476                 :             :                 }
     477                 :     3588135 :                 parent = current;
     478         [ +  + ]:     3588135 :                 current = (cmp < 0) ? current->left : current->right;
     479                 :             :         }
     480                 :             : 
     481                 :             :         /*
     482                 :             :          * Value is not present, so create a new node containing data.
     483                 :             :          */
     484                 :       75500 :         *isNew = true;
     485                 :             : 
     486                 :       75500 :         x = rbt->allocfunc(rbt->arg);
     487                 :             : 
     488                 :       75500 :         x->color = RBTRED;
     489                 :             : 
     490                 :       75500 :         x->left = RBTNIL;
     491                 :       75500 :         x->right = RBTNIL;
     492                 :       75500 :         x->parent = parent;
     493                 :       75500 :         rbt_copy_data(rbt, x, data);
     494                 :             : 
     495                 :             :         /* insert node in tree */
     496         [ +  + ]:       75500 :         if (parent)
     497                 :             :         {
     498         [ +  + ]:       75483 :                 if (cmp < 0)
     499                 :       12007 :                         parent->left = x;
     500                 :             :                 else
     501                 :       63476 :                         parent->right = x;
     502                 :       75483 :         }
     503                 :             :         else
     504                 :             :         {
     505                 :          17 :                 rbt->root = x;
     506                 :             :         }
     507                 :             : 
     508                 :       75500 :         rbt_insert_fixup(rbt, x);
     509                 :             : 
     510                 :       75500 :         return x;
     511                 :      269654 : }
     512                 :             : 
     513                 :             : /**********************************************************************
     514                 :             :  *                                                      Deletion                                                                  *
     515                 :             :  **********************************************************************/
     516                 :             : 
     517                 :             : /*
     518                 :             :  * Maintain Red-Black tree balance after deleting a black node.
     519                 :             :  */
     520                 :             : static void
     521                 :           0 : rbt_delete_fixup(RBTree *rbt, RBTNode *x)
     522                 :             : {
     523                 :             :         /*
     524                 :             :          * x is always a black node.  Initially, it is the former child of the
     525                 :             :          * deleted node.  Each iteration of this loop moves it higher up in the
     526                 :             :          * tree.
     527                 :             :          */
     528   [ #  #  #  # ]:           0 :         while (x != rbt->root && x->color == RBTBLACK)
     529                 :             :         {
     530                 :             :                 /*
     531                 :             :                  * Left and right cases are symmetric.  Any nodes that are children of
     532                 :             :                  * x have a black-height one less than the remainder of the nodes in
     533                 :             :                  * the tree.  We rotate and recolor nodes to move the problem up the
     534                 :             :                  * tree: at some stage we'll either fix the problem, or reach the root
     535                 :             :                  * (where the black-height is allowed to decrease).
     536                 :             :                  */
     537         [ #  # ]:           0 :                 if (x == x->parent->left)
     538                 :             :                 {
     539                 :           0 :                         RBTNode    *w = x->parent->right;
     540                 :             : 
     541         [ #  # ]:           0 :                         if (w->color == RBTRED)
     542                 :             :                         {
     543                 :           0 :                                 w->color = RBTBLACK;
     544                 :           0 :                                 x->parent->color = RBTRED;
     545                 :             : 
     546                 :           0 :                                 rbt_rotate_left(rbt, x->parent);
     547                 :           0 :                                 w = x->parent->right;
     548                 :           0 :                         }
     549                 :             : 
     550   [ #  #  #  # ]:           0 :                         if (w->left->color == RBTBLACK && w->right->color == RBTBLACK)
     551                 :             :                         {
     552                 :           0 :                                 w->color = RBTRED;
     553                 :             : 
     554                 :           0 :                                 x = x->parent;
     555                 :           0 :                         }
     556                 :             :                         else
     557                 :             :                         {
     558         [ #  # ]:           0 :                                 if (w->right->color == RBTBLACK)
     559                 :             :                                 {
     560                 :           0 :                                         w->left->color = RBTBLACK;
     561                 :           0 :                                         w->color = RBTRED;
     562                 :             : 
     563                 :           0 :                                         rbt_rotate_right(rbt, w);
     564                 :           0 :                                         w = x->parent->right;
     565                 :           0 :                                 }
     566                 :           0 :                                 w->color = x->parent->color;
     567                 :           0 :                                 x->parent->color = RBTBLACK;
     568                 :           0 :                                 w->right->color = RBTBLACK;
     569                 :             : 
     570                 :           0 :                                 rbt_rotate_left(rbt, x->parent);
     571                 :           0 :                                 x = rbt->root;       /* Arrange for loop to terminate. */
     572                 :             :                         }
     573                 :           0 :                 }
     574                 :             :                 else
     575                 :             :                 {
     576                 :           0 :                         RBTNode    *w = x->parent->left;
     577                 :             : 
     578         [ #  # ]:           0 :                         if (w->color == RBTRED)
     579                 :             :                         {
     580                 :           0 :                                 w->color = RBTBLACK;
     581                 :           0 :                                 x->parent->color = RBTRED;
     582                 :             : 
     583                 :           0 :                                 rbt_rotate_right(rbt, x->parent);
     584                 :           0 :                                 w = x->parent->left;
     585                 :           0 :                         }
     586                 :             : 
     587   [ #  #  #  # ]:           0 :                         if (w->right->color == RBTBLACK && w->left->color == RBTBLACK)
     588                 :             :                         {
     589                 :           0 :                                 w->color = RBTRED;
     590                 :             : 
     591                 :           0 :                                 x = x->parent;
     592                 :           0 :                         }
     593                 :             :                         else
     594                 :             :                         {
     595         [ #  # ]:           0 :                                 if (w->left->color == RBTBLACK)
     596                 :             :                                 {
     597                 :           0 :                                         w->right->color = RBTBLACK;
     598                 :           0 :                                         w->color = RBTRED;
     599                 :             : 
     600                 :           0 :                                         rbt_rotate_left(rbt, w);
     601                 :           0 :                                         w = x->parent->left;
     602                 :           0 :                                 }
     603                 :           0 :                                 w->color = x->parent->color;
     604                 :           0 :                                 x->parent->color = RBTBLACK;
     605                 :           0 :                                 w->left->color = RBTBLACK;
     606                 :             : 
     607                 :           0 :                                 rbt_rotate_right(rbt, x->parent);
     608                 :           0 :                                 x = rbt->root;       /* Arrange for loop to terminate. */
     609                 :             :                         }
     610                 :           0 :                 }
     611                 :             :         }
     612                 :           0 :         x->color = RBTBLACK;
     613                 :           0 : }
     614                 :             : 
     615                 :             : /*
     616                 :             :  * Delete node z from tree.
     617                 :             :  */
     618                 :             : static void
     619                 :           0 : rbt_delete_node(RBTree *rbt, RBTNode *z)
     620                 :             : {
     621                 :           0 :         RBTNode    *x,
     622                 :             :                            *y;
     623                 :             : 
     624                 :             :         /* This is just paranoia: we should only get called on a valid node */
     625   [ #  #  #  # ]:           0 :         if (!z || z == RBTNIL)
     626                 :           0 :                 return;
     627                 :             : 
     628                 :             :         /*
     629                 :             :          * y is the node that will actually be removed from the tree.  This will
     630                 :             :          * be z if z has fewer than two children, or the tree successor of z
     631                 :             :          * otherwise.
     632                 :             :          */
     633   [ #  #  #  # ]:           0 :         if (z->left == RBTNIL || z->right == RBTNIL)
     634                 :             :         {
     635                 :             :                 /* y has a RBTNIL node as a child */
     636                 :           0 :                 y = z;
     637                 :           0 :         }
     638                 :             :         else
     639                 :             :         {
     640                 :             :                 /* find tree successor */
     641                 :           0 :                 y = z->right;
     642         [ #  # ]:           0 :                 while (y->left != RBTNIL)
     643                 :           0 :                         y = y->left;
     644                 :             :         }
     645                 :             : 
     646                 :             :         /* x is y's only child */
     647         [ #  # ]:           0 :         if (y->left != RBTNIL)
     648                 :           0 :                 x = y->left;
     649                 :             :         else
     650                 :           0 :                 x = y->right;
     651                 :             : 
     652                 :             :         /* Remove y from the tree. */
     653                 :           0 :         x->parent = y->parent;
     654         [ #  # ]:           0 :         if (y->parent)
     655                 :             :         {
     656         [ #  # ]:           0 :                 if (y == y->parent->left)
     657                 :           0 :                         y->parent->left = x;
     658                 :             :                 else
     659                 :           0 :                         y->parent->right = x;
     660                 :           0 :         }
     661                 :             :         else
     662                 :             :         {
     663                 :           0 :                 rbt->root = x;
     664                 :             :         }
     665                 :             : 
     666                 :             :         /*
     667                 :             :          * If we removed the tree successor of z rather than z itself, then move
     668                 :             :          * the data for the removed node to the one we were supposed to remove.
     669                 :             :          */
     670         [ #  # ]:           0 :         if (y != z)
     671                 :           0 :                 rbt_copy_data(rbt, z, y);
     672                 :             : 
     673                 :             :         /*
     674                 :             :          * Removing a black node might make some paths from root to leaf contain
     675                 :             :          * fewer black nodes than others, or it might make two red nodes adjacent.
     676                 :             :          */
     677         [ #  # ]:           0 :         if (y->color == RBTBLACK)
     678                 :           0 :                 rbt_delete_fixup(rbt, x);
     679                 :             : 
     680                 :             :         /* Now we can recycle the y node */
     681         [ #  # ]:           0 :         if (rbt->freefunc)
     682                 :           0 :                 rbt->freefunc(y, rbt->arg);
     683         [ #  # ]:           0 : }
     684                 :             : 
     685                 :             : /*
     686                 :             :  * rbt_delete: remove the given tree entry
     687                 :             :  *
     688                 :             :  * "node" must have previously been found via rbt_find or rbt_leftmost.
     689                 :             :  * It is caller's responsibility to free any subsidiary data attached
     690                 :             :  * to the node before calling rbt_delete.  (Do *not* try to push that
     691                 :             :  * responsibility off to the freefunc, as some other physical node
     692                 :             :  * may be the one actually freed!)
     693                 :             :  */
     694                 :             : void
     695                 :           0 : rbt_delete(RBTree *rbt, RBTNode *node)
     696                 :             : {
     697                 :           0 :         rbt_delete_node(rbt, node);
     698                 :           0 : }
     699                 :             : 
     700                 :             : /**********************************************************************
     701                 :             :  *                                                Traverse                                                                        *
     702                 :             :  **********************************************************************/
     703                 :             : 
     704                 :             : static RBTNode *
     705                 :       75517 : rbt_left_right_iterator(RBTreeIterator *iter)
     706                 :             : {
     707         [ +  + ]:       75517 :         if (iter->last_visited == NULL)
     708                 :             :         {
     709                 :          17 :                 iter->last_visited = iter->rbt->root;
     710         [ +  + ]:         126 :                 while (iter->last_visited->left != RBTNIL)
     711                 :         109 :                         iter->last_visited = iter->last_visited->left;
     712                 :             : 
     713                 :          17 :                 return iter->last_visited;
     714                 :             :         }
     715                 :             : 
     716         [ +  + ]:       75500 :         if (iter->last_visited->right != RBTNIL)
     717                 :             :         {
     718                 :       37749 :                 iter->last_visited = iter->last_visited->right;
     719         [ +  + ]:       75374 :                 while (iter->last_visited->left != RBTNIL)
     720                 :       37625 :                         iter->last_visited = iter->last_visited->left;
     721                 :             : 
     722                 :       37749 :                 return iter->last_visited;
     723                 :             :         }
     724                 :             : 
     725                 :       75500 :         for (;;)
     726                 :             :         {
     727                 :       75500 :                 RBTNode    *came_from = iter->last_visited;
     728                 :             : 
     729                 :       75500 :                 iter->last_visited = iter->last_visited->parent;
     730         [ +  + ]:       75500 :                 if (iter->last_visited == NULL)
     731                 :             :                 {
     732                 :          17 :                         iter->is_over = true;
     733                 :          17 :                         break;
     734                 :             :                 }
     735                 :             : 
     736         [ +  + ]:       75483 :                 if (iter->last_visited->left == came_from)
     737                 :       37734 :                         break;                          /* came from left sub-tree, return current
     738                 :             :                                                                  * node */
     739                 :             : 
     740                 :             :                 /* else - came from right sub-tree, continue to move up */
     741      [ -  +  + ]:       75500 :         }
     742                 :             : 
     743                 :       37751 :         return iter->last_visited;
     744                 :       75517 : }
     745                 :             : 
     746                 :             : static RBTNode *
     747                 :           0 : rbt_right_left_iterator(RBTreeIterator *iter)
     748                 :             : {
     749         [ #  # ]:           0 :         if (iter->last_visited == NULL)
     750                 :             :         {
     751                 :           0 :                 iter->last_visited = iter->rbt->root;
     752         [ #  # ]:           0 :                 while (iter->last_visited->right != RBTNIL)
     753                 :           0 :                         iter->last_visited = iter->last_visited->right;
     754                 :             : 
     755                 :           0 :                 return iter->last_visited;
     756                 :             :         }
     757                 :             : 
     758         [ #  # ]:           0 :         if (iter->last_visited->left != RBTNIL)
     759                 :             :         {
     760                 :           0 :                 iter->last_visited = iter->last_visited->left;
     761         [ #  # ]:           0 :                 while (iter->last_visited->right != RBTNIL)
     762                 :           0 :                         iter->last_visited = iter->last_visited->right;
     763                 :             : 
     764                 :           0 :                 return iter->last_visited;
     765                 :             :         }
     766                 :             : 
     767                 :           0 :         for (;;)
     768                 :             :         {
     769                 :           0 :                 RBTNode    *came_from = iter->last_visited;
     770                 :             : 
     771                 :           0 :                 iter->last_visited = iter->last_visited->parent;
     772         [ #  # ]:           0 :                 if (iter->last_visited == NULL)
     773                 :             :                 {
     774                 :           0 :                         iter->is_over = true;
     775                 :           0 :                         break;
     776                 :             :                 }
     777                 :             : 
     778         [ #  # ]:           0 :                 if (iter->last_visited->right == came_from)
     779                 :           0 :                         break;                          /* came from right sub-tree, return current
     780                 :             :                                                                  * node */
     781                 :             : 
     782                 :             :                 /* else - came from left sub-tree, continue to move up */
     783      [ #  #  # ]:           0 :         }
     784                 :             : 
     785                 :           0 :         return iter->last_visited;
     786                 :           0 : }
     787                 :             : 
     788                 :             : /*
     789                 :             :  * rbt_begin_iterate: prepare to traverse the tree in any of several orders
     790                 :             :  *
     791                 :             :  * After calling rbt_begin_iterate, call rbt_iterate repeatedly until it
     792                 :             :  * returns NULL or the traversal stops being of interest.
     793                 :             :  *
     794                 :             :  * If the tree is changed during traversal, results of further calls to
     795                 :             :  * rbt_iterate are unspecified.  Multiple concurrent iterators on the same
     796                 :             :  * tree are allowed.
     797                 :             :  *
     798                 :             :  * The iterator state is stored in the 'iter' struct.  The caller should
     799                 :             :  * treat it as an opaque struct.
     800                 :             :  */
     801                 :             : void
     802                 :          22 : rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter)
     803                 :             : {
     804                 :             :         /* Common initialization for all traversal orders */
     805                 :          22 :         iter->rbt = rbt;
     806                 :          22 :         iter->last_visited = NULL;
     807                 :          22 :         iter->is_over = (rbt->root == RBTNIL);
     808                 :             : 
     809      [ -  +  - ]:          22 :         switch (ctrl)
     810                 :             :         {
     811                 :             :                 case LeftRightWalk:             /* visit left, then self, then right */
     812                 :          22 :                         iter->iterate = rbt_left_right_iterator;
     813                 :          22 :                         break;
     814                 :             :                 case RightLeftWalk:             /* visit right, then self, then left */
     815                 :           0 :                         iter->iterate = rbt_right_left_iterator;
     816                 :           0 :                         break;
     817                 :             :                 default:
     818   [ #  #  #  # ]:           0 :                         elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl);
     819                 :           0 :         }
     820                 :          22 : }
     821                 :             : 
     822                 :             : /*
     823                 :             :  * rbt_iterate: return the next node in traversal order, or NULL if no more
     824                 :             :  */
     825                 :             : RBTNode *
     826                 :       75522 : rbt_iterate(RBTreeIterator *iter)
     827                 :             : {
     828         [ +  + ]:       75522 :         if (iter->is_over)
     829                 :           5 :                 return NULL;
     830                 :             : 
     831                 :       75517 :         return iter->iterate(iter);
     832                 :       75522 : }
        

Generated by: LCOV version 2.3.2-1