LCOV - differential code coverage report
Current view: top level - src/test/modules/test_rbtree - test_rbtree.c (source / functions) Coverage Total Hit LBC UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 82.0 % 200 164 5 31 164
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 16 16 16
Baseline: 16@8cea358b128 Branches: 40.1 % 182 73 5 104 73
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: 82.0 % 200 164 5 31 164
Function coverage date bins:
(240..) days: 100.0 % 16 16 16
Branch coverage date bins:
(240..) days: 40.1 % 182 73 5 104 73

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*--------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * test_rbtree.c
                                  4                 :                :  *      Test correctness of red-black tree operations.
                                  5                 :                :  *
                                  6                 :                :  * Copyright (c) 2009-2024, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  * IDENTIFICATION
                                  9                 :                :  *      src/test/modules/test_rbtree/test_rbtree.c
                                 10                 :                :  *
                                 11                 :                :  * -------------------------------------------------------------------------
                                 12                 :                :  */
                                 13                 :                : 
                                 14                 :                : #include "postgres.h"
                                 15                 :                : 
                                 16                 :                : #include "common/pg_prng.h"
                                 17                 :                : #include "fmgr.h"
                                 18                 :                : #include "lib/rbtree.h"
                                 19                 :                : #include "utils/memutils.h"
                                 20                 :                : 
 2408 tgl@sss.pgh.pa.us          21                 :CBC           1 : PG_MODULE_MAGIC;
                                 22                 :                : 
                                 23                 :                : 
                                 24                 :                : /*
                                 25                 :                :  * Our test trees store an integer key, and nothing else.
                                 26                 :                :  */
                                 27                 :                : typedef struct IntRBTreeNode
                                 28                 :                : {
                                 29                 :                :     RBTNode     rbtnode;
                                 30                 :                :     int         key;
                                 31                 :                : } IntRBTreeNode;
                                 32                 :                : 
                                 33                 :                : 
                                 34                 :                : /*
                                 35                 :                :  * Node comparator.  We don't worry about overflow in the subtraction,
                                 36                 :                :  * since none of our test keys are negative.
                                 37                 :                :  */
                                 38                 :                : static int
 1986                            39                 :        1339670 : irbt_cmp(const RBTNode *a, const RBTNode *b, void *arg)
                                 40                 :                : {
 2408                            41                 :        1339670 :     const IntRBTreeNode *ea = (const IntRBTreeNode *) a;
                                 42                 :        1339670 :     const IntRBTreeNode *eb = (const IntRBTreeNode *) b;
                                 43                 :                : 
                                 44                 :        1339670 :     return ea->key - eb->key;
                                 45                 :                : }
                                 46                 :                : 
                                 47                 :                : /*
                                 48                 :                :  * Node combiner.  For testing purposes, just check that library doesn't
                                 49                 :                :  * try to combine unequal keys.
                                 50                 :                :  */
                                 51                 :                : static void
 1986                            52                 :              6 : irbt_combine(RBTNode *existing, const RBTNode *newdata, void *arg)
                                 53                 :                : {
 2408                            54                 :              6 :     const IntRBTreeNode *eexist = (const IntRBTreeNode *) existing;
                                 55                 :              6 :     const IntRBTreeNode *enew = (const IntRBTreeNode *) newdata;
                                 56                 :                : 
                                 57         [ -  + ]:              6 :     if (eexist->key != enew->key)
 2408 tgl@sss.pgh.pa.us          58         [ #  # ]:UBC           0 :         elog(ERROR, "red-black tree combines %d into %d",
                                 59                 :                :              enew->key, eexist->key);
 2408 tgl@sss.pgh.pa.us          60                 :CBC           6 : }
                                 61                 :                : 
                                 62                 :                : /* Node allocator */
                                 63                 :                : static RBTNode *
 1986                            64                 :          60000 : irbt_alloc(void *arg)
                                 65                 :                : {
                                 66                 :          60000 :     return (RBTNode *) palloc(sizeof(IntRBTreeNode));
                                 67                 :                : }
                                 68                 :                : 
                                 69                 :                : /* Node freer */
                                 70                 :                : static void
                                 71                 :          15016 : irbt_free(RBTNode *node, void *arg)
                                 72                 :                : {
 2408                            73                 :          15016 :     pfree(node);
                                 74                 :          15016 : }
                                 75                 :                : 
                                 76                 :                : /*
                                 77                 :                :  * Create a red-black tree using our support functions
                                 78                 :                :  */
                                 79                 :                : static RBTree *
                                 80                 :              6 : create_int_rbtree(void)
                                 81                 :                : {
 1986                            82                 :              6 :     return rbt_create(sizeof(IntRBTreeNode),
                                 83                 :                :                       irbt_cmp,
                                 84                 :                :                       irbt_combine,
                                 85                 :                :                       irbt_alloc,
                                 86                 :                :                       irbt_free,
                                 87                 :                :                       NULL);
                                 88                 :                : }
                                 89                 :                : 
                                 90                 :                : /*
                                 91                 :                :  * Generate a random permutation of the integers 0..size-1
                                 92                 :                :  */
                                 93                 :                : static int *
 2408                            94                 :              6 : GetPermutation(int size)
                                 95                 :                : {
                                 96                 :                :     int        *permutation;
                                 97                 :                :     int         i;
                                 98                 :                : 
                                 99                 :              6 :     permutation = (int *) palloc(size * sizeof(int));
                                100                 :                : 
                                101                 :              6 :     permutation[0] = 0;
                                102                 :                : 
                                103                 :                :     /*
                                104                 :                :      * This is the "inside-out" variant of the Fisher-Yates shuffle algorithm.
                                105                 :                :      * Notionally, we append each new value to the array and then swap it with
                                106                 :                :      * a randomly-chosen array element (possibly including itself, else we
                                107                 :                :      * fail to generate permutations with the last integer last).  The swap
                                108                 :                :      * step can be optimized by combining it with the insertion.
                                109                 :                :      */
                                110         [ +  + ]:          60000 :     for (i = 1; i < size; i++)
                                111                 :                :     {
  868                           112                 :          59994 :         int         j = pg_prng_uint64_range(&pg_global_prng_state, 0, i);
                                113                 :                : 
 2408                           114         [ +  + ]:          59994 :         if (j < i)               /* avoid fetching undefined data if j=i */
                                115                 :          59936 :             permutation[i] = permutation[j];
                                116                 :          59994 :         permutation[j] = i;
                                117                 :                :     }
                                118                 :                : 
                                119                 :              6 :     return permutation;
                                120                 :                : }
                                121                 :                : 
                                122                 :                : /*
                                123                 :                :  * Populate an empty RBTree with "size" integers having the values
                                124                 :                :  * 0, step, 2*step, 3*step, ..., inserting them in random order
                                125                 :                :  */
                                126                 :                : static void
 1986                           127                 :              6 : rbt_populate(RBTree *tree, int size, int step)
                                128                 :                : {
 2408                           129                 :              6 :     int        *permutation = GetPermutation(size);
                                130                 :                :     IntRBTreeNode node;
                                131                 :                :     bool        isNew;
                                132                 :                :     int         i;
                                133                 :                : 
                                134                 :                :     /* Insert values.  We don't expect any collisions. */
                                135         [ +  + ]:          60006 :     for (i = 0; i < size; i++)
                                136                 :                :     {
                                137                 :          60000 :         node.key = step * permutation[i];
 1986                           138                 :          60000 :         rbt_insert(tree, (RBTNode *) &node, &isNew);
 2408                           139         [ -  + ]:          60000 :         if (!isNew)
 1986 tgl@sss.pgh.pa.us         140         [ #  # ]:UBC           0 :             elog(ERROR, "unexpected !isNew result from rbt_insert");
                                141                 :                :     }
                                142                 :                : 
                                143                 :                :     /*
                                144                 :                :      * Re-insert the first value to make sure collisions work right.  It's
                                145                 :                :      * probably not useful to test that case over again for all the values.
                                146                 :                :      */
 2408 tgl@sss.pgh.pa.us         147         [ +  - ]:CBC           6 :     if (size > 0)
                                148                 :                :     {
                                149                 :              6 :         node.key = step * permutation[0];
 1986                           150                 :              6 :         rbt_insert(tree, (RBTNode *) &node, &isNew);
 2408                           151         [ -  + ]:              6 :         if (isNew)
 1986 tgl@sss.pgh.pa.us         152         [ #  # ]:UBC           0 :             elog(ERROR, "unexpected isNew result from rbt_insert");
                                153                 :                :     }
                                154                 :                : 
 2408 tgl@sss.pgh.pa.us         155                 :CBC           6 :     pfree(permutation);
                                156                 :              6 : }
                                157                 :                : 
                                158                 :                : /*
                                159                 :                :  * Check the correctness of left-right traversal.
                                160                 :                :  * Left-right traversal is correct if all elements are
                                161                 :                :  * visited in increasing order.
                                162                 :                :  */
                                163                 :                : static void
                                164                 :              1 : testleftright(int size)
                                165                 :                : {
                                166                 :              1 :     RBTree     *tree = create_int_rbtree();
                                167                 :                :     IntRBTreeNode *node;
                                168                 :                :     RBTreeIterator iter;
                                169                 :              1 :     int         lastKey = -1;
                                170                 :              1 :     int         count = 0;
                                171                 :                : 
                                172                 :                :     /* check iteration over empty tree */
 1986                           173                 :              1 :     rbt_begin_iterate(tree, LeftRightWalk, &iter);
                                174         [ -  + ]:              1 :     if (rbt_iterate(&iter) != NULL)
 2408 tgl@sss.pgh.pa.us         175         [ #  # ]:UBC           0 :         elog(ERROR, "left-right walk over empty tree produced an element");
                                176                 :                : 
                                177                 :                :     /* fill tree with consecutive natural numbers */
 1986 tgl@sss.pgh.pa.us         178                 :CBC           1 :     rbt_populate(tree, size, 1);
                                179                 :                : 
                                180                 :                :     /* iterate over the tree */
                                181                 :              1 :     rbt_begin_iterate(tree, LeftRightWalk, &iter);
                                182                 :                : 
                                183         [ +  + ]:          10001 :     while ((node = (IntRBTreeNode *) rbt_iterate(&iter)) != NULL)
                                184                 :                :     {
                                185                 :                :         /* check that order is increasing */
 2408                           186         [ -  + ]:          10000 :         if (node->key <= lastKey)
 2408 tgl@sss.pgh.pa.us         187         [ #  # ]:UBC           0 :             elog(ERROR, "left-right walk gives elements not in sorted order");
 2408 tgl@sss.pgh.pa.us         188                 :CBC       10000 :         lastKey = node->key;
                                189                 :          10000 :         count++;
                                190                 :                :     }
                                191                 :                : 
                                192         [ -  + ]:              1 :     if (lastKey != size - 1)
 2408 tgl@sss.pgh.pa.us         193         [ #  # ]:UBC           0 :         elog(ERROR, "left-right walk did not reach end");
 2408 tgl@sss.pgh.pa.us         194         [ -  + ]:CBC           1 :     if (count != size)
 2408 tgl@sss.pgh.pa.us         195         [ #  # ]:UBC           0 :         elog(ERROR, "left-right walk missed some elements");
 2408 tgl@sss.pgh.pa.us         196                 :CBC           1 : }
                                197                 :                : 
                                198                 :                : /*
                                199                 :                :  * Check the correctness of right-left traversal.
                                200                 :                :  * Right-left traversal is correct if all elements are
                                201                 :                :  * visited in decreasing order.
                                202                 :                :  */
                                203                 :                : static void
                                204                 :              1 : testrightleft(int size)
                                205                 :                : {
                                206                 :              1 :     RBTree     *tree = create_int_rbtree();
                                207                 :                :     IntRBTreeNode *node;
                                208                 :                :     RBTreeIterator iter;
                                209                 :              1 :     int         lastKey = size;
                                210                 :              1 :     int         count = 0;
                                211                 :                : 
                                212                 :                :     /* check iteration over empty tree */
 1986                           213                 :              1 :     rbt_begin_iterate(tree, RightLeftWalk, &iter);
                                214         [ -  + ]:              1 :     if (rbt_iterate(&iter) != NULL)
 2408 tgl@sss.pgh.pa.us         215         [ #  # ]:UBC           0 :         elog(ERROR, "right-left walk over empty tree produced an element");
                                216                 :                : 
                                217                 :                :     /* fill tree with consecutive natural numbers */
 1986 tgl@sss.pgh.pa.us         218                 :CBC           1 :     rbt_populate(tree, size, 1);
                                219                 :                : 
                                220                 :                :     /* iterate over the tree */
                                221                 :              1 :     rbt_begin_iterate(tree, RightLeftWalk, &iter);
                                222                 :                : 
                                223         [ +  + ]:          10001 :     while ((node = (IntRBTreeNode *) rbt_iterate(&iter)) != NULL)
                                224                 :                :     {
                                225                 :                :         /* check that order is decreasing */
 2408                           226         [ -  + ]:          10000 :         if (node->key >= lastKey)
 2408 tgl@sss.pgh.pa.us         227         [ #  # ]:UBC           0 :             elog(ERROR, "right-left walk gives elements not in sorted order");
 2408 tgl@sss.pgh.pa.us         228                 :CBC       10000 :         lastKey = node->key;
                                229                 :          10000 :         count++;
                                230                 :                :     }
                                231                 :                : 
                                232         [ -  + ]:              1 :     if (lastKey != 0)
 2408 tgl@sss.pgh.pa.us         233         [ #  # ]:UBC           0 :         elog(ERROR, "right-left walk did not reach end");
 2408 tgl@sss.pgh.pa.us         234         [ -  + ]:CBC           1 :     if (count != size)
 2408 tgl@sss.pgh.pa.us         235         [ #  # ]:UBC           0 :         elog(ERROR, "right-left walk missed some elements");
 2408 tgl@sss.pgh.pa.us         236                 :CBC           1 : }
                                237                 :                : 
                                238                 :                : /*
                                239                 :                :  * Check the correctness of the rbt_find operation by searching for
                                240                 :                :  * both elements we inserted and elements we didn't.
                                241                 :                :  */
                                242                 :                : static void
                                243                 :              1 : testfind(int size)
                                244                 :                : {
                                245                 :              1 :     RBTree     *tree = create_int_rbtree();
                                246                 :                :     int         i;
                                247                 :                : 
                                248                 :                :     /* Insert even integers from 0 to 2 * (size-1) */
 1986                           249                 :              1 :     rbt_populate(tree, size, 2);
                                250                 :                : 
                                251                 :                :     /* Check that all inserted elements can be found */
 2408                           252         [ +  + ]:          10001 :     for (i = 0; i < size; i++)
                                253                 :                :     {
                                254                 :                :         IntRBTreeNode node;
                                255                 :                :         IntRBTreeNode *resultNode;
                                256                 :                : 
                                257                 :          10000 :         node.key = 2 * i;
 1986                           258                 :          10000 :         resultNode = (IntRBTreeNode *) rbt_find(tree, (RBTNode *) &node);
 2408                           259         [ -  + ]:          10000 :         if (resultNode == NULL)
 2408 tgl@sss.pgh.pa.us         260         [ #  # ]:UBC           0 :             elog(ERROR, "inserted element was not found");
 2408 tgl@sss.pgh.pa.us         261         [ -  + ]:CBC       10000 :         if (node.key != resultNode->key)
 2408 tgl@sss.pgh.pa.us         262         [ #  # ]:UBC           0 :             elog(ERROR, "find operation in rbtree gave wrong result");
                                263                 :                :     }
                                264                 :                : 
                                265                 :                :     /*
                                266                 :                :      * Check that not-inserted elements can not be found, being sure to try
                                267                 :                :      * values before the first and after the last element.
                                268                 :                :      */
 2408 tgl@sss.pgh.pa.us         269         [ +  + ]:CBC       10002 :     for (i = -1; i <= 2 * size; i += 2)
                                270                 :                :     {
                                271                 :                :         IntRBTreeNode node;
                                272                 :                :         IntRBTreeNode *resultNode;
                                273                 :                : 
                                274                 :          10001 :         node.key = i;
 1986                           275                 :          10001 :         resultNode = (IntRBTreeNode *) rbt_find(tree, (RBTNode *) &node);
 2408                           276         [ -  + ]:          10001 :         if (resultNode != NULL)
 2408 tgl@sss.pgh.pa.us         277         [ #  # ]:UBC           0 :             elog(ERROR, "not-inserted element was found");
                                278                 :                :     }
 2408 tgl@sss.pgh.pa.us         279                 :CBC           1 : }
                                280                 :                : 
                                281                 :                : /*
                                282                 :                :  * Check the correctness of the rbt_find_less() and rbt_find_great() functions
                                283                 :                :  * by searching for an equal key and iterating the lesser keys then the greater
                                284                 :                :  * keys.
                                285                 :                :  */
                                286                 :                : static void
  646 akorotkov@postgresql      287                 :              1 : testfindltgt(int size)
                                288                 :                : {
                                289                 :              1 :     RBTree     *tree = create_int_rbtree();
                                290                 :                : 
                                291                 :                :     /*
                                292                 :                :      * Using the size as the random key to search wouldn't allow us to get at
                                293                 :                :      * least one greater match, so we do size - 1
                                294                 :                :      */
                                295                 :              1 :     int         randomKey = pg_prng_uint64_range(&pg_global_prng_state, 0, size - 1);
                                296                 :                :     bool        keyDeleted;
                                297                 :              1 :     IntRBTreeNode searchNode = {.key = randomKey};
                                298                 :                :     IntRBTreeNode *lteNode;
                                299                 :                :     IntRBTreeNode *gteNode;
                                300                 :                :     IntRBTreeNode *node;
                                301                 :                : 
                                302                 :                :     /* Insert natural numbers */
                                303                 :              1 :     rbt_populate(tree, size, 1);
                                304                 :                : 
                                305                 :                :     /*
                                306                 :                :      * Since the search key is included in the naturals of the tree, we're
                                307                 :                :      * sure to find an equal match
                                308                 :                :      */
                                309                 :              1 :     lteNode = (IntRBTreeNode *) rbt_find_less(tree, (RBTNode *) &searchNode, true);
                                310                 :              1 :     gteNode = (IntRBTreeNode *) rbt_find_great(tree, (RBTNode *) &searchNode, true);
                                311                 :                : 
                                312   [ +  -  -  + ]:              1 :     if (lteNode == NULL || lteNode->key != searchNode.key)
  646 akorotkov@postgresql      313         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_find_less() didn't find the equal key");
                                314                 :                : 
  646 akorotkov@postgresql      315   [ +  -  -  + ]:CBC           1 :     if (gteNode == NULL || gteNode->key != searchNode.key)
  646 akorotkov@postgresql      316         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_find_great() didn't find the equal key");
                                317                 :                : 
  646 akorotkov@postgresql      318         [ -  + ]:CBC           1 :     if (lteNode != gteNode)
  646 akorotkov@postgresql      319         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_find_less() and rbt_find_great() found different equal keys");
                                320                 :                : 
                                321                 :                :     /* Find the rest of the naturals lesser than the search key */
  646 akorotkov@postgresql      322                 :CBC           1 :     keyDeleted = false;
                                323         [ +  + ]:          10000 :     for (; searchNode.key > 0; searchNode.key--)
                                324                 :                :     {
                                325                 :                :         /*
                                326                 :                :          * Find the next key.  If the current key is deleted, we can pass
                                327                 :                :          * equal_match == true and still find the next one.
                                328                 :                :          */
                                329                 :           9999 :         node = (IntRBTreeNode *) rbt_find_less(tree, (RBTNode *) &searchNode,
                                330                 :                :                                                keyDeleted);
                                331                 :                : 
                                332                 :                :         /* ensure we find a lesser match */
                                333   [ +  -  -  + ]:           9999 :         if (!node || !(node->key < searchNode.key))
  646 akorotkov@postgresql      334         [ #  # ]:UBC           0 :             elog(ERROR, "rbt_find_less() didn't find a lesser key");
                                335                 :                : 
                                336                 :                :         /* randomly delete the found key or leave it */
  646 akorotkov@postgresql      337                 :CBC        9999 :         keyDeleted = (pg_prng_uint64_range(&pg_global_prng_state, 0, 1) == 1);
                                338         [ +  + ]:           9999 :         if (keyDeleted)
                                339                 :           5016 :             rbt_delete(tree, (RBTNode *) node);
                                340                 :                :     }
                                341                 :                : 
                                342                 :                :     /* Find the rest of the naturals greater than the search key */
                                343                 :              1 :     keyDeleted = false;
                                344         [ -  + ]:              1 :     for (searchNode.key = randomKey; searchNode.key < size - 1; searchNode.key++)
                                345                 :                :     {
                                346                 :                :         /*
                                347                 :                :          * Find the next key.  If the current key is deleted, we can pass
                                348                 :                :          * equal_match == true and still find the next one.
                                349                 :                :          */
  646 akorotkov@postgresql      350                 :LBC      (4341) :         node = (IntRBTreeNode *) rbt_find_great(tree, (RBTNode *) &searchNode,
                                351                 :                :                                                 keyDeleted);
                                352                 :                : 
                                353                 :                :         /* ensure we find a greater match */
                                354   [ #  #  #  # ]:         (4341) :         if (!node || !(node->key > searchNode.key))
  646 akorotkov@postgresql      355         [ #  # ]:UBC           0 :             elog(ERROR, "rbt_find_great() didn't find a greater key");
                                356                 :                : 
                                357                 :                :         /* randomly delete the found key or leave it */
  646 akorotkov@postgresql      358                 :LBC      (4341) :         keyDeleted = (pg_prng_uint64_range(&pg_global_prng_state, 0, 1) == 1);
                                359         [ #  # ]:         (4341) :         if (keyDeleted)
                                360                 :         (2165) :             rbt_delete(tree, (RBTNode *) node);
                                361                 :                :     }
                                362                 :                : 
                                363                 :                :     /* Check out of bounds searches find nothing */
  646 akorotkov@postgresql      364                 :CBC           1 :     searchNode.key = -1;
                                365                 :              1 :     node = (IntRBTreeNode *) rbt_find_less(tree, (RBTNode *) &searchNode, true);
                                366         [ -  + ]:              1 :     if (node != NULL)
  646 akorotkov@postgresql      367         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_find_less() found non-inserted element");
  646 akorotkov@postgresql      368                 :CBC           1 :     searchNode.key = 0;
                                369                 :              1 :     node = (IntRBTreeNode *) rbt_find_less(tree, (RBTNode *) &searchNode, false);
                                370         [ -  + ]:              1 :     if (node != NULL)
  646 akorotkov@postgresql      371         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_find_less() found non-inserted element");
  646 akorotkov@postgresql      372                 :CBC           1 :     searchNode.key = size;
                                373                 :              1 :     node = (IntRBTreeNode *) rbt_find_great(tree, (RBTNode *) &searchNode, true);
                                374         [ -  + ]:              1 :     if (node != NULL)
  646 akorotkov@postgresql      375         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_find_great() found non-inserted element");
  646 akorotkov@postgresql      376                 :CBC           1 :     searchNode.key = size - 1;
                                377                 :              1 :     node = (IntRBTreeNode *) rbt_find_great(tree, (RBTNode *) &searchNode, false);
                                378         [ -  + ]:              1 :     if (node != NULL)
  646 akorotkov@postgresql      379         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_find_great() found non-inserted element");
  646 akorotkov@postgresql      380                 :CBC           1 : }
                                381                 :                : 
                                382                 :                : /*
                                383                 :                :  * Check the correctness of the rbt_leftmost operation.
                                384                 :                :  * This operation should always return the smallest element of the tree.
                                385                 :                :  */
                                386                 :                : static void
 2408 tgl@sss.pgh.pa.us         387                 :              1 : testleftmost(int size)
                                388                 :                : {
                                389                 :              1 :     RBTree     *tree = create_int_rbtree();
                                390                 :                :     IntRBTreeNode *result;
                                391                 :                : 
                                392                 :                :     /* Check that empty tree has no leftmost element */
 1986                           393         [ -  + ]:              1 :     if (rbt_leftmost(tree) != NULL)
 2408 tgl@sss.pgh.pa.us         394         [ #  # ]:UBC           0 :         elog(ERROR, "leftmost node of empty tree is not NULL");
                                395                 :                : 
                                396                 :                :     /* fill tree with consecutive natural numbers */
 1986 tgl@sss.pgh.pa.us         397                 :CBC           1 :     rbt_populate(tree, size, 1);
                                398                 :                : 
                                399                 :                :     /* Check that leftmost element is the smallest one */
                                400                 :              1 :     result = (IntRBTreeNode *) rbt_leftmost(tree);
 2408                           401   [ +  -  -  + ]:              1 :     if (result == NULL || result->key != 0)
 1986 tgl@sss.pgh.pa.us         402         [ #  # ]:UBC           0 :         elog(ERROR, "rbt_leftmost gave wrong result");
 2408 tgl@sss.pgh.pa.us         403                 :CBC           1 : }
                                404                 :                : 
                                405                 :                : /*
                                406                 :                :  * Check the correctness of the rbt_delete operation.
                                407                 :                :  */
                                408                 :                : static void
                                409                 :              1 : testdelete(int size, int delsize)
                                410                 :                : {
                                411                 :              1 :     RBTree     *tree = create_int_rbtree();
                                412                 :                :     int        *deleteIds;
                                413                 :                :     bool       *chosen;
                                414                 :                :     int         i;
                                415                 :                : 
                                416                 :                :     /* fill tree with consecutive natural numbers */
 1986                           417                 :              1 :     rbt_populate(tree, size, 1);
                                418                 :                : 
                                419                 :                :     /* Choose unique ids to delete */
 2408                           420                 :              1 :     deleteIds = (int *) palloc(delsize * sizeof(int));
                                421                 :              1 :     chosen = (bool *) palloc0(size * sizeof(bool));
                                422                 :                : 
                                423         [ +  + ]:           1001 :     for (i = 0; i < delsize; i++)
                                424                 :                :     {
  868                           425                 :           1000 :         int         k = pg_prng_uint64_range(&pg_global_prng_state, 0, size - 1);
                                426                 :                : 
 2408                           427         [ +  + ]:           1050 :         while (chosen[k])
                                428                 :             50 :             k = (k + 1) % size;
                                429                 :           1000 :         deleteIds[i] = k;
                                430                 :           1000 :         chosen[k] = true;
                                431                 :                :     }
                                432                 :                : 
                                433                 :                :     /* Delete elements */
                                434         [ +  + ]:           1001 :     for (i = 0; i < delsize; i++)
                                435                 :                :     {
                                436                 :                :         IntRBTreeNode find;
                                437                 :                :         IntRBTreeNode *node;
                                438                 :                : 
                                439                 :           1000 :         find.key = deleteIds[i];
                                440                 :                :         /* Locate the node to be deleted */
 1986                           441                 :           1000 :         node = (IntRBTreeNode *) rbt_find(tree, (RBTNode *) &find);
 2408                           442   [ +  -  -  + ]:           1000 :         if (node == NULL || node->key != deleteIds[i])
 2408 tgl@sss.pgh.pa.us         443         [ #  # ]:UBC           0 :             elog(ERROR, "expected element was not found during deleting");
                                444                 :                :         /* Delete it */
 1986 tgl@sss.pgh.pa.us         445                 :CBC        1000 :         rbt_delete(tree, (RBTNode *) node);
                                446                 :                :     }
                                447                 :                : 
                                448                 :                :     /* Check that deleted elements are deleted */
 2408                           449         [ +  + ]:          10001 :     for (i = 0; i < size; i++)
                                450                 :                :     {
                                451                 :                :         IntRBTreeNode node;
                                452                 :                :         IntRBTreeNode *result;
                                453                 :                : 
                                454                 :          10000 :         node.key = i;
 1986                           455                 :          10000 :         result = (IntRBTreeNode *) rbt_find(tree, (RBTNode *) &node);
 2408                           456         [ +  + ]:          10000 :         if (chosen[i])
                                457                 :                :         {
                                458                 :                :             /* Deleted element should be absent */
                                459         [ -  + ]:           1000 :             if (result != NULL)
 2408 tgl@sss.pgh.pa.us         460         [ #  # ]:UBC           0 :                 elog(ERROR, "deleted element still present in the rbtree");
                                461                 :                :         }
                                462                 :                :         else
                                463                 :                :         {
                                464                 :                :             /* Else it should be present */
 2408 tgl@sss.pgh.pa.us         465   [ +  -  -  + ]:CBC        9000 :             if (result == NULL || result->key != i)
 2408 tgl@sss.pgh.pa.us         466         [ #  # ]:UBC           0 :                 elog(ERROR, "delete operation removed wrong rbtree value");
                                467                 :                :         }
                                468                 :                :     }
                                469                 :                : 
                                470                 :                :     /* Delete remaining elements, so as to exercise reducing tree to empty */
 2408 tgl@sss.pgh.pa.us         471         [ +  + ]:CBC       10001 :     for (i = 0; i < size; i++)
                                472                 :                :     {
                                473                 :                :         IntRBTreeNode find;
                                474                 :                :         IntRBTreeNode *node;
                                475                 :                : 
                                476         [ +  + ]:          10000 :         if (chosen[i])
                                477                 :           1000 :             continue;
                                478                 :           9000 :         find.key = i;
                                479                 :                :         /* Locate the node to be deleted */
 1986                           480                 :           9000 :         node = (IntRBTreeNode *) rbt_find(tree, (RBTNode *) &find);
 2408                           481   [ +  -  -  + ]:           9000 :         if (node == NULL || node->key != i)
 2408 tgl@sss.pgh.pa.us         482         [ #  # ]:UBC           0 :             elog(ERROR, "expected element was not found during deleting");
                                483                 :                :         /* Delete it */
 1986 tgl@sss.pgh.pa.us         484                 :CBC        9000 :         rbt_delete(tree, (RBTNode *) node);
                                485                 :                :     }
                                486                 :                : 
                                487                 :                :     /* Tree should now be empty */
                                488         [ -  + ]:              1 :     if (rbt_leftmost(tree) != NULL)
 2408 tgl@sss.pgh.pa.us         489         [ #  # ]:UBC           0 :         elog(ERROR, "deleting all elements failed");
                                490                 :                : 
 2408 tgl@sss.pgh.pa.us         491                 :CBC           1 :     pfree(deleteIds);
                                492                 :              1 :     pfree(chosen);
                                493                 :              1 : }
                                494                 :                : 
                                495                 :                : /*
                                496                 :                :  * SQL-callable entry point to perform all tests
                                497                 :                :  *
                                498                 :                :  * Argument is the number of entries to put in the trees
                                499                 :                :  */
                                500                 :              2 : PG_FUNCTION_INFO_V1(test_rb_tree);
                                501                 :                : 
                                502                 :                : Datum
                                503                 :              1 : test_rb_tree(PG_FUNCTION_ARGS)
                                504                 :                : {
                                505                 :              1 :     int         size = PG_GETARG_INT32(0);
                                506                 :                : 
                                507   [ +  -  -  + ]:              1 :     if (size <= 0 || size > MaxAllocSize / sizeof(int))
 2408 tgl@sss.pgh.pa.us         508         [ #  # ]:UBC           0 :         elog(ERROR, "invalid size for test_rb_tree: %d", size);
 2408 tgl@sss.pgh.pa.us         509                 :CBC           1 :     testleftright(size);
                                510                 :              1 :     testrightleft(size);
                                511                 :              1 :     testfind(size);
  646 akorotkov@postgresql      512                 :              1 :     testfindltgt(size);
 2408 tgl@sss.pgh.pa.us         513                 :              1 :     testleftmost(size);
                                514         [ +  - ]:              1 :     testdelete(size, Max(size / 10, 1));
                                515                 :              1 :     PG_RETURN_VOID();
                                516                 :                : }
        

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