LCOV - differential code coverage report
Current view: top level - src/backend/lib - rbtree.c (source / functions) Coverage Total Hit LBC UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 98.2 % 271 266 2 3 266
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 17 17 17
Baseline: 16@8cea358b128 Branches: 91.8 % 147 135 1 11 135
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 98.2 % 271 266 2 3 266
Function coverage date bins:
(240..) days: 100.0 % 17 17 17
Branch coverage date bins:
(240..) days: 91.8 % 147 135 1 11 135

 Age         Owner                    Branch data    TLA  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 http://www.cs.auckland.ac.nz/software/AlgAnim/niemann/s_man.htm for
                                 11                 :                :  * license terms: "Source code, when part of a software project, may be used
                                 12                 :                :  * 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-2024, 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 *
 1986 tgl@sss.pgh.pa.us         102                 :CBC         181 : 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                 :                : {
 5005                           109                 :            181 :     RBTree     *tree = (RBTree *) palloc(sizeof(RBTree));
                                110                 :                : 
 1986                           111         [ -  + ]:            181 :     Assert(node_size > sizeof(RBTNode));
                                112                 :                : 
                                113                 :            181 :     tree->root = RBTNIL;
 5005                           114                 :            181 :     tree->node_size = node_size;
 5176 teodor@sigaev.ru          115                 :            181 :     tree->comparator = comparator;
 5005 tgl@sss.pgh.pa.us         116                 :            181 :     tree->combiner = combiner;
                                117                 :            181 :     tree->allocfunc = allocfunc;
 5176 teodor@sigaev.ru          118                 :            181 :     tree->freefunc = freefunc;
                                119                 :                : 
                                120                 :            181 :     tree->arg = arg;
                                121                 :                : 
                                122                 :            181 :     return tree;
                                123                 :                : }
                                124                 :                : 
                                125                 :                : /* Copy the additional data fields from one RBTNode to another */
                                126                 :                : static inline void
 1986 tgl@sss.pgh.pa.us         127                 :         320020 : rbt_copy_data(RBTree *rbt, RBTNode *dest, const RBTNode *src)
                                128                 :                : {
                                129                 :         320020 :     memcpy(dest + 1, src + 1, rbt->node_size - sizeof(RBTNode));
 5005                           130                 :         320020 : }
                                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 *
 1986                           145                 :          40001 : rbt_find(RBTree *rbt, const RBTNode *data)
                                146                 :                : {
                                147                 :          40001 :     RBTNode    *node = rbt->root;
                                148                 :                : 
                                149         [ +  + ]:         490598 :     while (node != RBTNIL)
                                150                 :                :     {
                                151                 :         479597 :         int         cmp = rbt->comparator(data, node, rbt->arg);
                                152                 :                : 
 5176 teodor@sigaev.ru          153         [ +  + ]:         479597 :         if (cmp == 0)
 5005 tgl@sss.pgh.pa.us         154                 :          29000 :             return node;
 5176 teodor@sigaev.ru          155         [ +  + ]:         450597 :         else if (cmp < 0)
                                156                 :         260759 :             node = node->left;
                                157                 :                :         else
                                158                 :         189838 :             node = node->right;
                                159                 :                :     }
                                160                 :                : 
                                161                 :          11001 :     return NULL;
                                162                 :                : }
                                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 *
  646 akorotkov@postgresql      172                 :              3 : rbt_find_great(RBTree *rbt, const RBTNode *data, bool equal_match)
                                173                 :                : {
                                174                 :              3 :     RBTNode    *node = rbt->root;
                                175                 :              3 :     RBTNode    *greater = NULL;
                                176                 :                : 
                                177         [ +  + ]:             33 :     while (node != RBTNIL)
                                178                 :                :     {
                                179                 :             31 :         int         cmp = rbt->comparator(data, node, rbt->arg);
                                180                 :                : 
                                181   [ +  +  +  + ]:             31 :         if (equal_match && cmp == 0)
                                182                 :              1 :             return node;
                                183         [ -  + ]:             30 :         else if (cmp < 0)
                                184                 :                :         {
  646 akorotkov@postgresql      185                 :LBC     (24459) :             greater = node;
                                186                 :        (24459) :             node = node->left;
                                187                 :                :         }
                                188                 :                :         else
  646 akorotkov@postgresql      189                 :CBC          30 :             node = node->right;
                                190                 :                :     }
                                191                 :                : 
                                192                 :              2 :     return greater;
                                193                 :                : }
                                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                 :          10002 : rbt_find_less(RBTree *rbt, const RBTNode *data, bool equal_match)
                                204                 :                : {
                                205                 :          10002 :     RBTNode    *node = rbt->root;
                                206                 :          10002 :     RBTNode    *lesser = NULL;
                                207                 :                : 
                                208         [ +  + ]:         140879 :     while (node != RBTNIL)
                                209                 :                :     {
                                210                 :         130878 :         int         cmp = rbt->comparator(data, node, rbt->arg);
                                211                 :                : 
                                212   [ +  +  +  + ]:         130878 :         if (equal_match && cmp == 0)
                                213                 :              1 :             return node;
                                214         [ +  + ]:         130877 :         else if (cmp > 0)
                                215                 :                :         {
                                216                 :          67697 :             lesser = node;
                                217                 :          67697 :             node = node->right;
                                218                 :                :         }
                                219                 :                :         else
                                220                 :          63180 :             node = node->left;
                                221                 :                :     }
                                222                 :                : 
                                223                 :          10001 :     return lesser;
                                224                 :                : }
                                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 *
 1986 tgl@sss.pgh.pa.us         235                 :              3 : rbt_leftmost(RBTree *rbt)
                                236                 :                : {
                                237                 :              3 :     RBTNode    *node = rbt->root;
                                238                 :              3 :     RBTNode    *leftmost = rbt->root;
                                239                 :                : 
                                240         [ +  + ]:             15 :     while (node != RBTNIL)
                                241                 :                :     {
 5005                           242                 :             12 :         leftmost = node;
                                243                 :             12 :         node = node->left;
                                244                 :                :     }
                                245                 :                : 
 1986                           246         [ +  + ]:              3 :     if (leftmost != RBTNIL)
 5005                           247                 :              1 :         return leftmost;
                                248                 :                : 
                                249                 :              2 :     return NULL;
                                250                 :                : }
                                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
 1986                           263                 :         268583 : rbt_rotate_left(RBTree *rbt, RBTNode *x)
                                264                 :                : {
                                265                 :         268583 :     RBTNode    *y = x->right;
                                266                 :                : 
                                267                 :                :     /* establish x->right link */
 5176 teodor@sigaev.ru          268                 :         268583 :     x->right = y->left;
 1986 tgl@sss.pgh.pa.us         269         [ +  + ]:         268583 :     if (y->left != RBTNIL)
 5176 teodor@sigaev.ru          270                 :         129724 :         y->left->parent = x;
                                271                 :                : 
                                272                 :                :     /* establish y->parent link */
 1986 tgl@sss.pgh.pa.us         273         [ +  - ]:         268583 :     if (y != RBTNIL)
 5176 teodor@sigaev.ru          274                 :         268583 :         y->parent = x->parent;
                                275         [ +  + ]:         268583 :     if (x->parent)
                                276                 :                :     {
                                277         [ +  + ]:         268130 :         if (x == x->parent->left)
                                278                 :          82296 :             x->parent->left = y;
                                279                 :                :         else
                                280                 :         185834 :             x->parent->right = y;
                                281                 :                :     }
                                282                 :                :     else
                                283                 :                :     {
 1986 tgl@sss.pgh.pa.us         284                 :            453 :         rbt->root = y;
                                285                 :                :     }
                                286                 :                : 
                                287                 :                :     /* link x and y */
 5176 teodor@sigaev.ru          288                 :         268583 :     y->left = x;
 1986 tgl@sss.pgh.pa.us         289         [ +  - ]:         268583 :     if (x != RBTNIL)
 5176 teodor@sigaev.ru          290                 :         268583 :         x->parent = y;
                                291                 :         268583 : }
                                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
 1986 tgl@sss.pgh.pa.us         300                 :          70915 : rbt_rotate_right(RBTree *rbt, RBTNode *x)
                                301                 :                : {
                                302                 :          70915 :     RBTNode    *y = x->left;
                                303                 :                : 
                                304                 :                :     /* establish x->left link */
 5176 teodor@sigaev.ru          305                 :          70915 :     x->left = y->right;
 1986 tgl@sss.pgh.pa.us         306         [ +  + ]:          70915 :     if (y->right != RBTNIL)
 5176 teodor@sigaev.ru          307                 :          22722 :         y->right->parent = x;
                                308                 :                : 
                                309                 :                :     /* establish y->parent link */
 1986 tgl@sss.pgh.pa.us         310         [ +  - ]:          70915 :     if (y != RBTNIL)
 5176 teodor@sigaev.ru          311                 :          70915 :         y->parent = x->parent;
                                312         [ +  + ]:          70915 :     if (x->parent)
                                313                 :                :     {
                                314         [ +  + ]:          70864 :         if (x == x->parent->right)
                                315                 :          62604 :             x->parent->right = y;
                                316                 :                :         else
                                317                 :           8260 :             x->parent->left = y;
                                318                 :                :     }
                                319                 :                :     else
                                320                 :                :     {
 1986 tgl@sss.pgh.pa.us         321                 :             51 :         rbt->root = y;
                                322                 :                :     }
                                323                 :                : 
                                324                 :                :     /* link x and y */
 5176 teodor@sigaev.ru          325                 :          70915 :     y->right = x;
 1986 tgl@sss.pgh.pa.us         326         [ +  - ]:          70915 :     if (x != RBTNIL)
 5176 teodor@sigaev.ru          327                 :          70915 :         x->parent = y;
                                328                 :          70915 : }
                                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
 1986 tgl@sss.pgh.pa.us         344                 :         317625 : 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   [ +  +  +  + ]:         866480 :     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                 :                :          */
 5176 teodor@sigaev.ru          368         [ +  + ]:         548855 :         if (x->parent == x->parent->parent->left)
                                369                 :                :         {
 1986 tgl@sss.pgh.pa.us         370                 :          80485 :             RBTNode    *y = x->parent->parent->right;
                                371                 :                : 
                                372         [ +  + ]:          80485 :             if (y->color == RBTRED)
                                373                 :                :             {
                                374                 :                :                 /* uncle is RBTRED */
                                375                 :          19402 :                 x->parent->color = RBTBLACK;
                                376                 :          19402 :                 y->color = RBTBLACK;
                                377                 :          19402 :                 x->parent->parent->color = RBTRED;
                                378                 :                : 
 5176 teodor@sigaev.ru          379                 :          19402 :                 x = x->parent->parent;
                                380                 :                :             }
                                381                 :                :             else
                                382                 :                :             {
                                383                 :                :                 /* uncle is RBTBLACK */
                                384         [ +  + ]:          61083 :                 if (x == x->parent->right)
                                385                 :                :                 {
                                386                 :                :                     /* make x a left child */
                                387                 :          53853 :                     x = x->parent;
 1986 tgl@sss.pgh.pa.us         388                 :          53853 :                     rbt_rotate_left(rbt, x);
                                389                 :                :                 }
                                390                 :                : 
                                391                 :                :                 /* recolor and rotate */
                                392                 :          61083 :                 x->parent->color = RBTBLACK;
                                393                 :          61083 :                 x->parent->parent->color = RBTRED;
                                394                 :                : 
                                395                 :          61083 :                 rbt_rotate_right(rbt, x->parent->parent);
                                396                 :                :             }
                                397                 :                :         }
                                398                 :                :         else
                                399                 :                :         {
                                400                 :                :             /* mirror image of above code */
                                401                 :         468370 :             RBTNode    *y = x->parent->parent->left;
                                402                 :                : 
                                403         [ +  + ]:         468370 :             if (y->color == RBTRED)
                                404                 :                :             {
                                405                 :                :                 /* uncle is RBTRED */
                                406                 :         259630 :                 x->parent->color = RBTBLACK;
                                407                 :         259630 :                 y->color = RBTBLACK;
                                408                 :         259630 :                 x->parent->parent->color = RBTRED;
                                409                 :                : 
 5176 teodor@sigaev.ru          410                 :         259630 :                 x = x->parent->parent;
                                411                 :                :             }
                                412                 :                :             else
                                413                 :                :             {
                                414                 :                :                 /* uncle is RBTBLACK */
                                415         [ +  + ]:         208740 :                 if (x == x->parent->left)
                                416                 :                :                 {
                                417                 :           7620 :                     x = x->parent;
 1986 tgl@sss.pgh.pa.us         418                 :           7620 :                     rbt_rotate_right(rbt, x);
                                419                 :                :                 }
                                420                 :         208740 :                 x->parent->color = RBTBLACK;
                                421                 :         208740 :                 x->parent->parent->color = RBTRED;
                                422                 :                : 
                                423                 :         208740 :                 rbt_rotate_left(rbt, x->parent->parent);
                                424                 :                :             }
                                425                 :                :         }
                                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                 :         317625 :     rbt->root->color = RBTBLACK;
 5176 teodor@sigaev.ru          433                 :         317625 : }
                                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 *
 1986 tgl@sss.pgh.pa.us         453                 :        1321013 : rbt_insert(RBTree *rbt, const RBTNode *data, bool *isNew)
                                454                 :                : {
                                455                 :                :     RBTNode    *current,
                                456                 :                :                *parent,
                                457                 :                :                *x;
                                458                 :                :     int         cmp;
                                459                 :                : 
                                460                 :                :     /* find where node belongs */
                                461                 :        1321013 :     current = rbt->root;
 5176 teodor@sigaev.ru          462                 :        1321013 :     parent = NULL;
 5005 tgl@sss.pgh.pa.us         463                 :        1321013 :     cmp = 0;                    /* just to prevent compiler warning */
                                464                 :                : 
 1986                           465         [ +  + ]:       13766395 :     while (current != RBTNIL)
                                466                 :                :     {
                                467                 :       13448770 :         cmp = rbt->comparator(data, current, rbt->arg);
 5176 teodor@sigaev.ru          468         [ +  + ]:       13448770 :         if (cmp == 0)
                                469                 :                :         {
                                470                 :                :             /*
                                471                 :                :              * Found node with given key.  Apply combiner.
                                472                 :                :              */
 1986 tgl@sss.pgh.pa.us         473                 :        1003388 :             rbt->combiner(current, data, rbt->arg);
 5005                           474                 :        1003388 :             *isNew = false;
                                475                 :        1003388 :             return current;
                                476                 :                :         }
 5176 teodor@sigaev.ru          477                 :       12445382 :         parent = current;
                                478         [ +  + ]:       12445382 :         current = (cmp < 0) ? current->left : current->right;
                                479                 :                :     }
                                480                 :                : 
                                481                 :                :     /*
                                482                 :                :      * Value is not present, so create a new node containing data.
                                483                 :                :      */
 5005 tgl@sss.pgh.pa.us         484                 :         317625 :     *isNew = true;
                                485                 :                : 
 1986                           486                 :         317625 :     x = rbt->allocfunc(rbt->arg);
                                487                 :                : 
                                488                 :         317625 :     x->color = RBTRED;
                                489                 :                : 
                                490                 :         317625 :     x->left = RBTNIL;
                                491                 :         317625 :     x->right = RBTNIL;
 5005                           492                 :         317625 :     x->parent = parent;
 1986                           493                 :         317625 :     rbt_copy_data(rbt, x, data);
                                494                 :                : 
                                495                 :                :     /* insert node in tree */
 5176 teodor@sigaev.ru          496         [ +  + ]:         317625 :     if (parent)
                                497                 :                :     {
                                498         [ +  + ]:         317467 :         if (cmp < 0)
                                499                 :          68590 :             parent->left = x;
                                500                 :                :         else
                                501                 :         248877 :             parent->right = x;
                                502                 :                :     }
                                503                 :                :     else
                                504                 :                :     {
 1986 tgl@sss.pgh.pa.us         505                 :            158 :         rbt->root = x;
                                506                 :                :     }
                                507                 :                : 
                                508                 :         317625 :     rbt_insert_fixup(rbt, x);
                                509                 :                : 
 5005                           510                 :         317625 :     return x;
                                511                 :                : }
                                512                 :                : 
                                513                 :                : /**********************************************************************
                                514                 :                :  *                          Deletion                                  *
                                515                 :                :  **********************************************************************/
                                516                 :                : 
                                517                 :                : /*
                                518                 :                :  * Maintain Red-Black tree balance after deleting a black node.
                                519                 :                :  */
                                520                 :                : static void
 1986                           521                 :          12765 : 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   [ +  +  +  + ]:          23783 :     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                 :                :          */
 5176 teodor@sigaev.ru          537         [ +  + ]:          11018 :         if (x == x->parent->left)
                                538                 :                :         {
 1986 tgl@sss.pgh.pa.us         539                 :           9359 :             RBTNode    *w = x->parent->right;
                                540                 :                : 
                                541         [ +  + ]:           9359 :             if (w->color == RBTRED)
                                542                 :                :             {
                                543                 :           2245 :                 w->color = RBTBLACK;
                                544                 :           2245 :                 x->parent->color = RBTRED;
                                545                 :                : 
                                546                 :           2245 :                 rbt_rotate_left(rbt, x->parent);
 5176 teodor@sigaev.ru          547                 :           2245 :                 w = x->parent->right;
                                548                 :                :             }
                                549                 :                : 
 1986 tgl@sss.pgh.pa.us         550   [ +  +  +  + ]:           9359 :             if (w->left->color == RBTBLACK && w->right->color == RBTBLACK)
                                551                 :                :             {
                                552                 :           5918 :                 w->color = RBTRED;
                                553                 :                : 
 5176 teodor@sigaev.ru          554                 :           5918 :                 x = x->parent;
                                555                 :                :             }
                                556                 :                :             else
                                557                 :                :             {
 1986 tgl@sss.pgh.pa.us         558         [ +  + ]:           3441 :                 if (w->right->color == RBTBLACK)
                                559                 :                :                 {
                                560                 :           1149 :                     w->left->color = RBTBLACK;
                                561                 :           1149 :                     w->color = RBTRED;
                                562                 :                : 
                                563                 :           1149 :                     rbt_rotate_right(rbt, w);
 5176 teodor@sigaev.ru          564                 :           1149 :                     w = x->parent->right;
                                565                 :                :                 }
                                566                 :           3441 :                 w->color = x->parent->color;
 1986 tgl@sss.pgh.pa.us         567                 :           3441 :                 x->parent->color = RBTBLACK;
                                568                 :           3441 :                 w->right->color = RBTBLACK;
                                569                 :                : 
                                570                 :           3441 :                 rbt_rotate_left(rbt, x->parent);
                                571                 :           3441 :                 x = rbt->root;   /* Arrange for loop to terminate. */
                                572                 :                :             }
                                573                 :                :         }
                                574                 :                :         else
                                575                 :                :         {
                                576                 :           1659 :             RBTNode    *w = x->parent->left;
                                577                 :                : 
                                578         [ +  + ]:           1659 :             if (w->color == RBTRED)
                                579                 :                :             {
                                580                 :            176 :                 w->color = RBTBLACK;
                                581                 :            176 :                 x->parent->color = RBTRED;
                                582                 :                : 
                                583                 :            176 :                 rbt_rotate_right(rbt, x->parent);
 5176 teodor@sigaev.ru          584                 :            176 :                 w = x->parent->left;
                                585                 :                :             }
                                586                 :                : 
 1986 tgl@sss.pgh.pa.us         587   [ +  +  +  + ]:           1659 :             if (w->right->color == RBTBLACK && w->left->color == RBTBLACK)
                                588                 :                :             {
                                589                 :            772 :                 w->color = RBTRED;
                                590                 :                : 
 5176 teodor@sigaev.ru          591                 :            772 :                 x = x->parent;
                                592                 :                :             }
                                593                 :                :             else
                                594                 :                :             {
 1986 tgl@sss.pgh.pa.us         595         [ +  + ]:            887 :                 if (w->left->color == RBTBLACK)
                                596                 :                :                 {
                                597                 :            304 :                     w->right->color = RBTBLACK;
                                598                 :            304 :                     w->color = RBTRED;
                                599                 :                : 
                                600                 :            304 :                     rbt_rotate_left(rbt, w);
 5176 teodor@sigaev.ru          601                 :            304 :                     w = x->parent->left;
                                602                 :                :                 }
                                603                 :            887 :                 w->color = x->parent->color;
 1986 tgl@sss.pgh.pa.us         604                 :            887 :                 x->parent->color = RBTBLACK;
                                605                 :            887 :                 w->left->color = RBTBLACK;
                                606                 :                : 
                                607                 :            887 :                 rbt_rotate_right(rbt, x->parent);
                                608                 :            887 :                 x = rbt->root;   /* Arrange for loop to terminate. */
                                609                 :                :             }
                                610                 :                :         }
                                611                 :                :     }
                                612                 :          12765 :     x->color = RBTBLACK;
 5176 teodor@sigaev.ru          613                 :          12765 : }
                                614                 :                : 
                                615                 :                : /*
                                616                 :                :  * Delete node z from tree.
                                617                 :                :  */
                                618                 :                : static void
 1986 tgl@sss.pgh.pa.us         619                 :          15016 : rbt_delete_node(RBTree *rbt, RBTNode *z)
                                620                 :                : {
                                621                 :                :     RBTNode    *x,
                                622                 :                :                *y;
                                623                 :                : 
                                624                 :                :     /* This is just paranoia: we should only get called on a valid node */
                                625   [ +  -  -  + ]:          15016 :     if (!z || z == RBTNIL)
 5176 teodor@sigaev.ru          626                 :UBC           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                 :                :      */
 1986 tgl@sss.pgh.pa.us         633   [ +  +  +  + ]:CBC       15016 :     if (z->left == RBTNIL || z->right == RBTNIL)
                                634                 :                :     {
                                635                 :                :         /* y has a RBTNIL node as a child */
 5176 teodor@sigaev.ru          636                 :          12621 :         y = z;
                                637                 :                :     }
                                638                 :                :     else
                                639                 :                :     {
                                640                 :                :         /* find tree successor */
                                641                 :           2395 :         y = z->right;
 1986 tgl@sss.pgh.pa.us         642         [ +  + ]:           4726 :         while (y->left != RBTNIL)
 5176 teodor@sigaev.ru          643                 :           2331 :             y = y->left;
                                644                 :                :     }
                                645                 :                : 
                                646                 :                :     /* x is y's only child */
 1986 tgl@sss.pgh.pa.us         647         [ +  + ]:          15016 :     if (y->left != RBTNIL)
 5176 teodor@sigaev.ru          648                 :            678 :         x = y->left;
                                649                 :                :     else
                                650                 :          14338 :         x = y->right;
                                651                 :                : 
                                652                 :                :     /* Remove y from the tree. */
                                653                 :          15016 :     x->parent = y->parent;
                                654         [ +  + ]:          15016 :     if (y->parent)
                                655                 :                :     {
                                656         [ +  + ]:          15014 :         if (y == y->parent->left)
                                657                 :          11970 :             y->parent->left = x;
                                658                 :                :         else
                                659                 :           3044 :             y->parent->right = x;
                                660                 :                :     }
                                661                 :                :     else
                                662                 :                :     {
 1986 tgl@sss.pgh.pa.us         663                 :              2 :         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                 :                :      */
 5176 teodor@sigaev.ru          670         [ +  + ]:          15016 :     if (y != z)
 1986 tgl@sss.pgh.pa.us         671                 :           2395 :         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         [ +  + ]:          15016 :     if (y->color == RBTBLACK)
                                678                 :          12765 :         rbt_delete_fixup(rbt, x);
                                679                 :                : 
                                680                 :                :     /* Now we can recycle the y node */
                                681         [ +  - ]:          15016 :     if (rbt->freefunc)
                                682                 :          15016 :         rbt->freefunc(y, rbt->arg);
                                683                 :                : }
                                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                 :          15016 : rbt_delete(RBTree *rbt, RBTNode *node)
                                696                 :                : {
                                697                 :          15016 :     rbt_delete_node(rbt, node);
 5176 teodor@sigaev.ru          698                 :          15016 : }
                                699                 :                : 
                                700                 :                : /**********************************************************************
                                701                 :                :  *                        Traverse                                    *
                                702                 :                :  **********************************************************************/
                                703                 :                : 
                                704                 :                : static RBTNode *
 1986 tgl@sss.pgh.pa.us         705                 :         267778 : rbt_left_right_iterator(RBTreeIterator *iter)
                                706                 :                : {
 2781 heikki.linnakangas@i      707         [ +  + ]:         267778 :     if (iter->last_visited == NULL)
                                708                 :                :     {
 1986 tgl@sss.pgh.pa.us         709                 :            153 :         iter->last_visited = iter->rbt->root;
                                710         [ +  + ]:            889 :         while (iter->last_visited->left != RBTNIL)
 2781 heikki.linnakangas@i      711                 :            736 :             iter->last_visited = iter->last_visited->left;
                                712                 :                : 
                                713                 :            153 :         return iter->last_visited;
                                714                 :                :     }
                                715                 :                : 
 1986 tgl@sss.pgh.pa.us         716         [ +  + ]:         267625 :     if (iter->last_visited->right != RBTNIL)
                                717                 :                :     {
 2781 heikki.linnakangas@i      718                 :         133828 :         iter->last_visited = iter->last_visited->right;
 1986 tgl@sss.pgh.pa.us         719         [ +  + ]:         266736 :         while (iter->last_visited->left != RBTNIL)
 2781 heikki.linnakangas@i      720                 :         132908 :             iter->last_visited = iter->last_visited->left;
                                721                 :                : 
                                722                 :         133828 :         return iter->last_visited;
                                723                 :                :     }
                                724                 :                : 
                                725                 :                :     for (;;)
 5176 teodor@sigaev.ru          726                 :         133828 :     {
 1986 tgl@sss.pgh.pa.us         727                 :         267625 :         RBTNode    *came_from = iter->last_visited;
                                728                 :                : 
 2781 heikki.linnakangas@i      729                 :         267625 :         iter->last_visited = iter->last_visited->parent;
                                730         [ +  + ]:         267625 :         if (iter->last_visited == NULL)
                                731                 :                :         {
                                732                 :            153 :             iter->is_over = true;
 5176 teodor@sigaev.ru          733                 :            153 :             break;
                                734                 :                :         }
                                735                 :                : 
 2781 heikki.linnakangas@i      736         [ +  + ]:         267472 :         if (iter->last_visited->left == came_from)
                                737                 :         133644 :             break;              /* came from left sub-tree, return current
                                738                 :                :                                  * node */
                                739                 :                : 
                                740                 :                :         /* else - came from right sub-tree, continue to move up */
                                741                 :                :     }
                                742                 :                : 
                                743                 :         133797 :     return iter->last_visited;
                                744                 :                : }
                                745                 :                : 
                                746                 :                : static RBTNode *
 1986 tgl@sss.pgh.pa.us         747                 :          10001 : rbt_right_left_iterator(RBTreeIterator *iter)
                                748                 :                : {
 2781 heikki.linnakangas@i      749         [ +  + ]:          10001 :     if (iter->last_visited == NULL)
                                750                 :                :     {
 1986 tgl@sss.pgh.pa.us         751                 :              1 :         iter->last_visited = iter->rbt->root;
                                752         [ +  + ]:             13 :         while (iter->last_visited->right != RBTNIL)
 2781 heikki.linnakangas@i      753                 :             12 :             iter->last_visited = iter->last_visited->right;
                                754                 :                : 
                                755                 :              1 :         return iter->last_visited;
                                756                 :                :     }
                                757                 :                : 
 1986 tgl@sss.pgh.pa.us         758         [ +  + ]:          10000 :     if (iter->last_visited->left != RBTNIL)
                                759                 :                :     {
 2781 heikki.linnakangas@i      760                 :           4991 :         iter->last_visited = iter->last_visited->left;
 1986 tgl@sss.pgh.pa.us         761         [ +  + ]:           9987 :         while (iter->last_visited->right != RBTNIL)
 2781 heikki.linnakangas@i      762                 :           4996 :             iter->last_visited = iter->last_visited->right;
                                763                 :                : 
                                764                 :           4991 :         return iter->last_visited;
                                765                 :                :     }
                                766                 :                : 
                                767                 :                :     for (;;)
                                768                 :           4991 :     {
 1986 tgl@sss.pgh.pa.us         769                 :          10000 :         RBTNode    *came_from = iter->last_visited;
                                770                 :                : 
 2781 heikki.linnakangas@i      771                 :          10000 :         iter->last_visited = iter->last_visited->parent;
                                772         [ +  + ]:          10000 :         if (iter->last_visited == NULL)
                                773                 :                :         {
                                774                 :              1 :             iter->is_over = true;
 5176 teodor@sigaev.ru          775                 :              1 :             break;
                                776                 :                :         }
                                777                 :                : 
 2781 heikki.linnakangas@i      778         [ +  + ]:           9999 :         if (iter->last_visited->right == came_from)
                                779                 :           5008 :             break;              /* came from right sub-tree, return current
                                780                 :                :                                  * node */
                                781                 :                : 
                                782                 :                :         /* else - came from left sub-tree, continue to move up */
                                783                 :                :     }
                                784                 :                : 
                                785                 :           5009 :     return iter->last_visited;
                                786                 :                : }
                                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
 1986 tgl@sss.pgh.pa.us         802                 :            179 : rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter)
                                803                 :                : {
                                804                 :                :     /* Common initialization for all traversal orders */
                                805                 :            179 :     iter->rbt = rbt;
 2781 heikki.linnakangas@i      806                 :            179 :     iter->last_visited = NULL;
 1986 tgl@sss.pgh.pa.us         807                 :            179 :     iter->is_over = (rbt->root == RBTNIL);
                                808                 :                : 
 5176 teodor@sigaev.ru          809      [ +  +  - ]:            179 :     switch (ctrl)
                                810                 :                :     {
 5161 bruce@momjian.us          811                 :            177 :         case LeftRightWalk:     /* visit left, then self, then right */
 1986 tgl@sss.pgh.pa.us         812                 :            177 :             iter->iterate = rbt_left_right_iterator;
 5176 teodor@sigaev.ru          813                 :            177 :             break;
 5161 bruce@momjian.us          814                 :              2 :         case RightLeftWalk:     /* visit right, then self, then left */
 1986 tgl@sss.pgh.pa.us         815                 :              2 :             iter->iterate = rbt_right_left_iterator;
 5176 teodor@sigaev.ru          816                 :              2 :             break;
 5176 teodor@sigaev.ru          817                 :UBC           0 :         default:
 5005 tgl@sss.pgh.pa.us         818         [ #  # ]:              0 :             elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl);
                                819                 :                :     }
 5176 teodor@sigaev.ru          820                 :CBC         179 : }
                                821                 :                : 
                                822                 :                : /*
                                823                 :                :  * rbt_iterate: return the next node in traversal order, or NULL if no more
                                824                 :                :  */
                                825                 :                : RBTNode *
 1986 tgl@sss.pgh.pa.us         826                 :         277804 : rbt_iterate(RBTreeIterator *iter)
                                827                 :                : {
 2781 heikki.linnakangas@i      828         [ +  + ]:         277804 :     if (iter->is_over)
 5176 teodor@sigaev.ru          829                 :             25 :         return NULL;
                                830                 :                : 
 2781 heikki.linnakangas@i      831                 :         277779 :     return iter->iterate(iter);
                                832                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622