LCOV - differential code coverage report
Current view: top level - src/common - binaryheap.c (source / functions) Coverage Total Hit UNC UBC GBC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 96.1 % 103 99 2 2 16 16 67 2 4
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 15 15 7 8 1 2
Baseline: 16@8cea358b128 Branches: 73.2 % 56 41 4 11 6 8 27
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 76.5 % 17 13 2 2 3 2 8
(180,240] days: 100.0 % 14 14 14
(240..) days: 100.0 % 72 72 13 59
Function coverage date bins:
[..60] days: 100.0 % 1 1 1
(180,240] days: 100.0 % 4 4 4
(240..) days: 100.0 % 10 10 2 8
Branch coverage date bins:
[..60] days: 0.0 % 4 0 4
(180,240] days: 66.7 % 12 8 4 8
(240..) days: 82.5 % 40 33 7 6 27

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * binaryheap.c
                                  4                 :                :  *    A simple binary heap implementation
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 2012-2024, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  * IDENTIFICATION
                                  9                 :                :  *    src/common/binaryheap.c
                                 10                 :                :  *
                                 11                 :                :  *-------------------------------------------------------------------------
                                 12                 :                :  */
                                 13                 :                : 
                                 14                 :                : #ifdef FRONTEND
                                 15                 :                : #include "postgres_fe.h"
                                 16                 :                : #else
                                 17                 :                : #include "postgres.h"
                                 18                 :                : #endif
                                 19                 :                : 
                                 20                 :                : #include <math.h>
                                 21                 :                : 
                                 22                 :                : #ifdef FRONTEND
                                 23                 :                : #include "common/logging.h"
                                 24                 :                : #endif
                                 25                 :                : #include "lib/binaryheap.h"
                                 26                 :                : 
                                 27                 :                : static void sift_down(binaryheap *heap, int node_off);
                                 28                 :                : static void sift_up(binaryheap *heap, int node_off);
                                 29                 :                : 
                                 30                 :                : /*
                                 31                 :                :  * binaryheap_allocate
                                 32                 :                :  *
                                 33                 :                :  * Returns a pointer to a newly-allocated heap that has the capacity to
                                 34                 :                :  * store the given number of nodes, with the heap property defined by
                                 35                 :                :  * the given comparator function, which will be invoked with the additional
                                 36                 :                :  * argument specified by 'arg'.
                                 37                 :                :  */
                                 38                 :                : binaryheap *
    3 msawada@postgresql.o       39                 :CBC        3599 : binaryheap_allocate(int capacity, binaryheap_comparator compare, void *arg)
                                 40                 :                : {
                                 41                 :                :     int         sz;
                                 42                 :                :     binaryheap *heap;
                                 43                 :                : 
    3 msawada@postgresql.o       44                 :GNC        3599 :     sz = offsetof(binaryheap, bh_nodes) + sizeof(bh_node_type) * capacity;
    3 msawada@postgresql.o       45                 :CBC        3599 :     heap = (binaryheap *) palloc(sz);
                                 46                 :           3599 :     heap->bh_space = capacity;
 4154 rhaas@postgresql.org       47                 :           3599 :     heap->bh_compare = compare;
                                 48                 :           3599 :     heap->bh_arg = arg;
                                 49                 :                : 
 3880 tgl@sss.pgh.pa.us          50                 :           3599 :     heap->bh_size = 0;
                                 51                 :           3599 :     heap->bh_has_heap_property = true;
                                 52                 :                : 
 4154 rhaas@postgresql.org       53                 :           3599 :     return heap;
                                 54                 :                : }
                                 55                 :                : 
                                 56                 :                : /*
                                 57                 :                :  * binaryheap_reset
                                 58                 :                :  *
                                 59                 :                :  * Resets the heap to an empty state, losing its data content but not the
                                 60                 :                :  * parameters passed at allocation.
                                 61                 :                :  */
                                 62                 :                : void
 3880 tgl@sss.pgh.pa.us          63                 :            350 : binaryheap_reset(binaryheap *heap)
                                 64                 :                : {
                                 65                 :            350 :     heap->bh_size = 0;
                                 66                 :            350 :     heap->bh_has_heap_property = true;
                                 67                 :            350 : }
                                 68                 :                : 
                                 69                 :                : /*
                                 70                 :                :  * binaryheap_free
                                 71                 :                :  *
                                 72                 :                :  * Releases memory used by the given binaryheap.
                                 73                 :                :  */
                                 74                 :                : void
 4154 rhaas@postgresql.org       75                 :           3142 : binaryheap_free(binaryheap *heap)
                                 76                 :                : {
                                 77                 :           3142 :     pfree(heap);
                                 78                 :           3142 : }
                                 79                 :                : 
                                 80                 :                : /*
                                 81                 :                :  * These utility functions return the offset of the left child, right
                                 82                 :                :  * child, and parent of the node at the given index, respectively.
                                 83                 :                :  *
                                 84                 :                :  * The heap is represented as an array of nodes, with the root node
                                 85                 :                :  * stored at index 0. The left child of node i is at index 2*i+1, and
                                 86                 :                :  * the right child at 2*i+2. The parent of node i is at index (i-1)/2.
                                 87                 :                :  */
                                 88                 :                : 
                                 89                 :                : static inline int
                                 90                 :       13012173 : left_offset(int i)
                                 91                 :                : {
                                 92                 :       13012173 :     return 2 * i + 1;
                                 93                 :                : }
                                 94                 :                : 
                                 95                 :                : static inline int
                                 96                 :       13012173 : right_offset(int i)
                                 97                 :                : {
                                 98                 :       13012173 :     return 2 * i + 2;
                                 99                 :                : }
                                100                 :                : 
                                101                 :                : static inline int
                                102                 :        2951014 : parent_offset(int i)
                                103                 :                : {
                                104                 :        2951014 :     return (i - 1) / 2;
                                105                 :                : }
                                106                 :                : 
                                107                 :                : /*
                                108                 :                :  * binaryheap_add_unordered
                                109                 :                :  *
                                110                 :                :  * Adds the given datum to the end of the heap's list of nodes in O(1) without
                                111                 :                :  * preserving the heap property. This is a convenience to add elements quickly
                                112                 :                :  * to a new heap. To obtain a valid heap, one must call binaryheap_build()
                                113                 :                :  * afterwards.
                                114                 :                :  */
                                115                 :                : void
  209 nathan@postgresql.or      116                 :GNC       27966 : binaryheap_add_unordered(binaryheap *heap, bh_node_type d)
                                117                 :                : {
 4154 rhaas@postgresql.org      118         [ -  + ]:CBC       27966 :     if (heap->bh_size >= heap->bh_space)
                                119                 :                :     {
                                120                 :                : #ifdef FRONTEND
    3 msawada@postgresql.o      121                 :UNC           0 :         pg_fatal("out of binary heap slots");
                                122                 :                : #else
    3 msawada@postgresql.o      123         [ #  # ]:UBC           0 :         elog(ERROR, "out of binary heap slots");
                                124                 :                : #endif
                                125                 :                :     }
 4154 rhaas@postgresql.org      126                 :CBC       27966 :     heap->bh_has_heap_property = false;
    3 msawada@postgresql.o      127                 :          27966 :     heap->bh_nodes[heap->bh_size] = d;
 4154 rhaas@postgresql.org      128                 :          27966 :     heap->bh_size++;
                                129                 :          27966 : }
                                130                 :                : 
                                131                 :                : /*
                                132                 :                :  * binaryheap_build
                                133                 :                :  *
                                134                 :                :  * Assembles a valid heap in O(n) from the nodes added by
                                135                 :                :  * binaryheap_add_unordered(). Not needed otherwise.
                                136                 :                :  */
                                137                 :                : void
                                138                 :           3447 : binaryheap_build(binaryheap *heap)
                                139                 :                : {
                                140                 :                :     int         i;
                                141                 :                : 
                                142         [ +  + ]:          18510 :     for (i = parent_offset(heap->bh_size - 1); i >= 0; i--)
                                143                 :          15063 :         sift_down(heap, i);
                                144                 :           3447 :     heap->bh_has_heap_property = true;
                                145                 :           3447 : }
                                146                 :                : 
                                147                 :                : /*
                                148                 :                :  * binaryheap_add
                                149                 :                :  *
                                150                 :                :  * Adds the given datum to the heap in O(log n) time, while preserving
                                151                 :                :  * the heap property.
                                152                 :                :  */
                                153                 :                : void
  209 nathan@postgresql.or      154                 :GNC     1233709 : binaryheap_add(binaryheap *heap, bh_node_type d)
                                155                 :                : {
 4154 rhaas@postgresql.org      156         [ -  + ]:GBC     1233709 :     if (heap->bh_size >= heap->bh_space)
                                157                 :                :     {
                                158                 :                : #ifdef FRONTEND
    3 msawada@postgresql.o      159                 :UNC           0 :         pg_fatal("out of binary heap slots");
                                160                 :                : #else
    3 msawada@postgresql.o      161         [ #  # ]:UBC           0 :         elog(ERROR, "out of binary heap slots");
                                162                 :                : #endif
                                163                 :                :     }
    3 msawada@postgresql.o      164                 :GBC     1233709 :     heap->bh_nodes[heap->bh_size] = d;
 4154 rhaas@postgresql.org      165                 :        1233709 :     heap->bh_size++;
                                166                 :        1233709 :     sift_up(heap, heap->bh_size - 1);
                                167                 :        1233709 : }
                                168                 :                : 
                                169                 :                : /*
                                170                 :                :  * binaryheap_first
                                171                 :                :  *
                                172                 :                :  * Returns a pointer to the first (root, topmost) node in the heap
                                173                 :                :  * without modifying the heap. The caller must ensure that this
                                174                 :                :  * routine is not used on an empty heap. Always O(1).
                                175                 :                :  */
                                176                 :                : bh_node_type
 4154 rhaas@postgresql.org      177                 :CBC     1025189 : binaryheap_first(binaryheap *heap)
                                178                 :                : {
                                179   [ +  -  -  + ]:        1025189 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                180                 :        1025189 :     return heap->bh_nodes[0];
                                181                 :                : }
                                182                 :                : 
                                183                 :                : /*
                                184                 :                :  * binaryheap_remove_first
                                185                 :                :  *
                                186                 :                :  * Removes the first (root, topmost) node in the heap and returns a
                                187                 :                :  * pointer to it after rebalancing the heap. The caller must ensure
                                188                 :                :  * that this routine is not used on an empty heap. O(log n) worst
                                189                 :                :  * case.
                                190                 :                :  */
                                191                 :                : bh_node_type
                                192                 :        1261502 : binaryheap_remove_first(binaryheap *heap)
                                193                 :                : {
                                194                 :                :     bh_node_type result;
                                195                 :                : 
                                196   [ +  -  +  + ]:        1261502 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                197                 :                : 
                                198                 :                :     /* extract the root node, which will be the result */
  852 tgl@sss.pgh.pa.us         199                 :        1261502 :     result = heap->bh_nodes[0];
                                200                 :                : 
                                201                 :                :     /* easy if heap contains one element */
 4154 rhaas@postgresql.org      202         [ +  + ]:        1261502 :     if (heap->bh_size == 1)
                                203                 :                :     {
                                204                 :           4511 :         heap->bh_size--;
  852 tgl@sss.pgh.pa.us         205                 :           4511 :         return result;
                                206                 :                :     }
                                207                 :                : 
                                208                 :                :     /*
                                209                 :                :      * Remove the last node, placing it in the vacated root entry, and sift
                                210                 :                :      * the new root node down to its correct position.
                                211                 :                :      */
    3 msawada@postgresql.o      212                 :        1256991 :     heap->bh_nodes[0] = heap->bh_nodes[--heap->bh_size];
 4154 rhaas@postgresql.org      213                 :        1256991 :     sift_down(heap, 0);
                                214                 :                : 
  852 tgl@sss.pgh.pa.us         215                 :        1256991 :     return result;
                                216                 :                : }
                                217                 :                : 
                                218                 :                : /*
                                219                 :                :  * binaryheap_remove_node
                                220                 :                :  *
                                221                 :                :  * Removes the nth (zero based) node from the heap.  The caller must ensure
                                222                 :                :  * that there are at least (n + 1) nodes in the heap.  O(log n) worst case.
                                223                 :                :  */
                                224                 :                : void
  209 nathan@postgresql.or      225                 :GNC          46 : binaryheap_remove_node(binaryheap *heap, int n)
                                226                 :                : {
                                227                 :                :     int         cmp;
                                228                 :                : 
                                229   [ +  -  +  - ]:             46 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                230   [ +  -  +  - ]:             46 :     Assert(n >= 0 && n < heap->bh_size);
                                231                 :                : 
                                232                 :                :     /* compare last node to the one that is being removed */
                                233                 :             46 :     cmp = heap->bh_compare(heap->bh_nodes[--heap->bh_size],
                                234                 :                :                            heap->bh_nodes[n],
                                235                 :                :                            heap->bh_arg);
                                236                 :                : 
                                237                 :                :     /* remove the last node, placing it in the vacated entry */
    3 msawada@postgresql.o      238                 :             46 :     heap->bh_nodes[n] = heap->bh_nodes[heap->bh_size];
                                239                 :                : 
                                240                 :                :     /* sift as needed to preserve the heap property */
  209 nathan@postgresql.or      241         [ +  + ]:             46 :     if (cmp > 0)
                                242                 :              1 :         sift_up(heap, n);
                                243         [ +  + ]:             45 :     else if (cmp < 0)
                                244                 :             30 :         sift_down(heap, n);
                                245                 :             46 : }
                                246                 :                : 
                                247                 :                : /*
                                248                 :                :  * binaryheap_replace_first
                                249                 :                :  *
                                250                 :                :  * Replace the topmost element of a non-empty heap, preserving the heap
                                251                 :                :  * property.  O(1) in the best case, or O(log n) if it must fall back to
                                252                 :                :  * sifting the new node down.
                                253                 :                :  */
                                254                 :                : void
                                255                 :         811597 : binaryheap_replace_first(binaryheap *heap, bh_node_type d)
                                256                 :                : {
 4154 rhaas@postgresql.org      257   [ +  -  -  + ]:CBC      811597 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                258                 :                : 
    3 msawada@postgresql.o      259                 :         811597 :     heap->bh_nodes[0] = d;
                                260                 :                : 
 4154 rhaas@postgresql.org      261         [ +  + ]:         811597 :     if (heap->bh_size > 1)
                                262                 :         443092 :         sift_down(heap, 0);
                                263                 :         811597 : }
                                264                 :                : 
                                265                 :                : /*
                                266                 :                :  * Sift a node up to the highest position it can hold according to the
                                267                 :                :  * comparator.
                                268                 :                :  */
                                269                 :                : static void
 4154 rhaas@postgresql.org      270                 :GBC     1233710 : sift_up(binaryheap *heap, int node_off)
                                271                 :                : {
  209 nathan@postgresql.or      272                 :GNC     1233710 :     bh_node_type node_val = heap->bh_nodes[node_off];
                                273                 :                : 
                                274                 :                :     /*
                                275                 :                :      * Within the loop, the node_off'th array entry is a "hole" that
                                276                 :                :      * notionally holds node_val, but we don't actually store node_val there
                                277                 :                :      * till the end, saving some unnecessary data copying steps.
                                278                 :                :      */
 4154 rhaas@postgresql.org      279         [ +  + ]:GBC     3047644 :     while (node_off != 0)
                                280                 :                :     {
                                281                 :                :         int         cmp;
                                282                 :                :         int         parent_off;
                                283                 :                :         bh_node_type parent_val;
                                284                 :                : 
                                285                 :                :         /*
                                286                 :                :          * If this node is smaller than its parent, the heap condition is
                                287                 :                :          * satisfied, and we're done.
                                288                 :                :          */
                                289                 :        2947567 :         parent_off = parent_offset(node_off);
  852 tgl@sss.pgh.pa.us         290                 :        2947567 :         parent_val = heap->bh_nodes[parent_off];
                                291                 :        2947567 :         cmp = heap->bh_compare(node_val,
                                292                 :                :                                parent_val,
                                293                 :                :                                heap->bh_arg);
 4154 rhaas@postgresql.org      294         [ +  + ]:        2947567 :         if (cmp <= 0)
                                295                 :        1133633 :             break;
                                296                 :                : 
                                297                 :                :         /*
                                298                 :                :          * Otherwise, swap the parent value with the hole, and go on to check
                                299                 :                :          * the node's new parent.
                                300                 :                :          */
    3 msawada@postgresql.o      301                 :        1813934 :         heap->bh_nodes[node_off] = parent_val;
 4154 rhaas@postgresql.org      302                 :        1813934 :         node_off = parent_off;
                                303                 :                :     }
                                304                 :                :     /* Re-fill the hole */
    3 msawada@postgresql.o      305                 :        1233710 :     heap->bh_nodes[node_off] = node_val;
 4154 rhaas@postgresql.org      306                 :        1233710 : }
                                307                 :                : 
                                308                 :                : /*
                                309                 :                :  * Sift a node down from its current position to satisfy the heap
                                310                 :                :  * property.
                                311                 :                :  */
                                312                 :                : static void
 4154 rhaas@postgresql.org      313                 :CBC     1715176 : sift_down(binaryheap *heap, int node_off)
                                314                 :                : {
  209 nathan@postgresql.or      315                 :GNC     1715176 :     bh_node_type node_val = heap->bh_nodes[node_off];
                                316                 :                : 
                                317                 :                :     /*
                                318                 :                :      * Within the loop, the node_off'th array entry is a "hole" that
                                319                 :                :      * notionally holds node_val, but we don't actually store node_val there
                                320                 :                :      * till the end, saving some unnecessary data copying steps.
                                321                 :                :      */
                                322                 :                :     while (true)
 4154 rhaas@postgresql.org      323                 :CBC    11296997 :     {
                                324                 :       13012173 :         int         left_off = left_offset(node_off);
                                325                 :       13012173 :         int         right_off = right_offset(node_off);
                                326                 :       13012173 :         int         swap_off = 0;
                                327                 :                : 
                                328                 :                :         /* Is the left child larger than the parent? */
                                329   [ +  +  +  + ]:       25093921 :         if (left_off < heap->bh_size &&
  852 tgl@sss.pgh.pa.us         330                 :       12081748 :             heap->bh_compare(node_val,
                                331                 :                :                              heap->bh_nodes[left_off],
                                332                 :                :                              heap->bh_arg) < 0)
 4154 rhaas@postgresql.org      333                 :       11023679 :             swap_off = left_off;
                                334                 :                : 
                                335                 :                :         /* Is the right child larger than the parent? */
                                336   [ +  +  +  + ]:       24708930 :         if (right_off < heap->bh_size &&
  852 tgl@sss.pgh.pa.us         337                 :       11696757 :             heap->bh_compare(node_val,
                                338                 :                :                              heap->bh_nodes[right_off],
                                339                 :                :                              heap->bh_arg) < 0)
                                340                 :                :         {
                                341                 :                :             /* swap with the larger child */
 4154 rhaas@postgresql.org      342   [ +  +  +  + ]:       21728676 :             if (!swap_off ||
                                343                 :       10727679 :                 heap->bh_compare(heap->bh_nodes[left_off],
                                344                 :                :                                  heap->bh_nodes[right_off],
                                345                 :                :                                  heap->bh_arg) < 0)
                                346                 :        5490734 :                 swap_off = right_off;
                                347                 :                :         }
                                348                 :                : 
                                349                 :                :         /*
                                350                 :                :          * If we didn't find anything to swap, the heap condition is
                                351                 :                :          * satisfied, and we're done.
                                352                 :                :          */
                                353         [ +  + ]:       13012173 :         if (!swap_off)
                                354                 :        1715176 :             break;
                                355                 :                : 
                                356                 :                :         /*
                                357                 :                :          * Otherwise, swap the hole with the child that violates the heap
                                358                 :                :          * property; then go on to check its children.
                                359                 :                :          */
    3 msawada@postgresql.o      360                 :       11296997 :         heap->bh_nodes[node_off] = heap->bh_nodes[swap_off];
 4154 rhaas@postgresql.org      361                 :       11296997 :         node_off = swap_off;
                                362                 :                :     }
                                363                 :                :     /* Re-fill the hole */
    3 msawada@postgresql.o      364                 :        1715176 :     heap->bh_nodes[node_off] = node_val;
 4154 rhaas@postgresql.org      365                 :        1715176 : }
        

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