LCOV - differential code coverage report
Current view: top level - src/common - binaryheap.c (source / functions) Coverage Total Hit UBC GBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 95.9 % 98 94 4 1 93
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 15 15 15
Baseline: lcov-20250906-005545-baseline Branches: 74.0 % 50 37 13 3 34
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 5 5 5
(360..) days: 95.7 % 93 89 4 1 88
Function coverage date bins:
(360..) days: 100.0 % 15 15 15
Branch coverage date bins:
(30,360] days: 100.0 % 4 4 4
(360..) days: 71.7 % 46 33 13 3 30

 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-2025, 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 *
  513 msawada@postgresql.o       39                 :CBC        4194 : binaryheap_allocate(int capacity, binaryheap_comparator compare, void *arg)
                                 40                 :                : {
                                 41                 :                :     int         sz;
                                 42                 :                :     binaryheap *heap;
                                 43                 :                : 
                                 44                 :           4194 :     sz = offsetof(binaryheap, bh_nodes) + sizeof(bh_node_type) * capacity;
                                 45                 :           4194 :     heap = (binaryheap *) palloc(sz);
                                 46                 :           4194 :     heap->bh_space = capacity;
 4664 rhaas@postgresql.org       47                 :           4194 :     heap->bh_compare = compare;
                                 48                 :           4194 :     heap->bh_arg = arg;
                                 49                 :                : 
 4390 tgl@sss.pgh.pa.us          50                 :           4194 :     heap->bh_size = 0;
                                 51                 :           4194 :     heap->bh_has_heap_property = true;
                                 52                 :                : 
 4664 rhaas@postgresql.org       53                 :           4194 :     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
 4390 tgl@sss.pgh.pa.us          63                 :            193 : binaryheap_reset(binaryheap *heap)
                                 64                 :                : {
                                 65                 :            193 :     heap->bh_size = 0;
                                 66                 :            193 :     heap->bh_has_heap_property = true;
                                 67                 :            193 : }
                                 68                 :                : 
                                 69                 :                : /*
                                 70                 :                :  * binaryheap_free
                                 71                 :                :  *
                                 72                 :                :  * Releases memory used by the given binaryheap.
                                 73                 :                :  */
                                 74                 :                : void
 4664 rhaas@postgresql.org       75                 :           3676 : binaryheap_free(binaryheap *heap)
                                 76                 :                : {
                                 77                 :           3676 :     pfree(heap);
                                 78                 :           3676 : }
                                 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                 :       16864657 : left_offset(int i)
                                 91                 :                : {
                                 92                 :       16864657 :     return 2 * i + 1;
                                 93                 :                : }
                                 94                 :                : 
                                 95                 :                : static inline int
                                 96                 :       16864657 : right_offset(int i)
                                 97                 :                : {
                                 98                 :       16864657 :     return 2 * i + 2;
                                 99                 :                : }
                                100                 :                : 
                                101                 :                : static inline int
                                102                 :        3920724 : parent_offset(int i)
                                103                 :                : {
                                104                 :        3920724 :     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
  719 nathan@postgresql.or      116                 :          38891 : binaryheap_add_unordered(binaryheap *heap, bh_node_type d)
                                117                 :                : {
 4664 rhaas@postgresql.org      118         [ -  + ]:          38891 :     if (heap->bh_size >= heap->bh_space)
                                119                 :                :     {
                                120                 :                : #ifdef FRONTEND
  513 msawada@postgresql.o      121                 :UBC           0 :         pg_fatal("out of binary heap slots");
                                122                 :                : #else
                                123         [ #  # ]:              0 :         elog(ERROR, "out of binary heap slots");
                                124                 :                : #endif
                                125                 :                :     }
 4664 rhaas@postgresql.org      126                 :CBC       38891 :     heap->bh_has_heap_property = false;
  513 msawada@postgresql.o      127                 :          38891 :     heap->bh_nodes[heap->bh_size] = d;
 4664 rhaas@postgresql.org      128                 :          38891 :     heap->bh_size++;
                                129                 :          38891 : }
                                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                 :           3938 : binaryheap_build(binaryheap *heap)
                                139                 :                : {
                                140                 :                :     int         i;
                                141                 :                : 
                                142         [ +  + ]:          24557 :     for (i = parent_offset(heap->bh_size - 1); i >= 0; i--)
                                143                 :          20619 :         sift_down(heap, i);
                                144                 :           3938 :     heap->bh_has_heap_property = true;
                                145                 :           3938 : }
                                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
  719 nathan@postgresql.or      154                 :        1610150 : binaryheap_add(binaryheap *heap, bh_node_type d)
                                155                 :                : {
 4664 rhaas@postgresql.org      156         [ -  + ]:        1610150 :     if (heap->bh_size >= heap->bh_space)
                                157                 :                :     {
                                158                 :                : #ifdef FRONTEND
  513 msawada@postgresql.o      159                 :UBC           0 :         pg_fatal("out of binary heap slots");
                                160                 :                : #else
                                161         [ #  # ]:              0 :         elog(ERROR, "out of binary heap slots");
                                162                 :                : #endif
                                163                 :                :     }
  513 msawada@postgresql.o      164                 :CBC     1610150 :     heap->bh_nodes[heap->bh_size] = d;
 4664 rhaas@postgresql.org      165                 :        1610150 :     heap->bh_size++;
                                166                 :        1610150 :     sift_up(heap, heap->bh_size - 1);
                                167                 :        1610150 : }
                                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
                                177                 :        1066355 : binaryheap_first(binaryheap *heap)
                                178                 :                : {
                                179   [ +  -  -  + ]:        1066355 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                180                 :        1066355 :     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                 :        1644408 : binaryheap_remove_first(binaryheap *heap)
                                193                 :                : {
                                194                 :                :     bh_node_type result;
                                195                 :                : 
                                196   [ +  -  +  + ]:        1644408 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                197                 :                : 
                                198                 :                :     /* extract the root node, which will be the result */
 1362 tgl@sss.pgh.pa.us         199                 :        1644408 :     result = heap->bh_nodes[0];
                                200                 :                : 
                                201                 :                :     /* easy if heap contains one element */
 4664 rhaas@postgresql.org      202         [ +  + ]:        1644408 :     if (heap->bh_size == 1)
                                203                 :                :     {
                                204                 :           5497 :         heap->bh_size--;
 1362 tgl@sss.pgh.pa.us         205                 :           5497 :         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                 :                :      */
  513 msawada@postgresql.o      212                 :        1638911 :     heap->bh_nodes[0] = heap->bh_nodes[--heap->bh_size];
 4664 rhaas@postgresql.org      213                 :        1638911 :     sift_down(heap, 0);
                                214                 :                : 
 1362 tgl@sss.pgh.pa.us         215                 :        1638911 :     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
  719 nathan@postgresql.or      225                 :            379 : binaryheap_remove_node(binaryheap *heap, int n)
                                226                 :                : {
                                227                 :                :     int         cmp;
                                228                 :                : 
                                229   [ +  -  +  + ]:            379 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                230   [ +  -  +  + ]:            379 :     Assert(n >= 0 && n < heap->bh_size);
                                231                 :                : 
                                232                 :                :     /* compare last node to the one that is being removed */
                                233                 :            379 :     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 */
  513 msawada@postgresql.o      238                 :            379 :     heap->bh_nodes[n] = heap->bh_nodes[heap->bh_size];
                                239                 :                : 
                                240                 :                :     /* sift as needed to preserve the heap property */
  719 nathan@postgresql.or      241         [ +  + ]:            379 :     if (cmp > 0)
  719 nathan@postgresql.or      242                 :GBC          69 :         sift_up(heap, n);
  719 nathan@postgresql.or      243         [ +  + ]:CBC         310 :     else if (cmp < 0)
                                244                 :            295 :         sift_down(heap, n);
                                245                 :            379 : }
                                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                 :         852150 : binaryheap_replace_first(binaryheap *heap, bh_node_type d)
                                256                 :                : {
 4664 rhaas@postgresql.org      257   [ +  -  -  + ]:         852150 :     Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
                                258                 :                : 
  513 msawada@postgresql.o      259                 :         852150 :     heap->bh_nodes[0] = d;
                                260                 :                : 
 4664 rhaas@postgresql.org      261         [ +  + ]:         852150 :     if (heap->bh_size > 1)
                                262                 :         433790 :         sift_down(heap, 0);
                                263                 :         852150 : }
                                264                 :                : 
                                265                 :                : /*
                                266                 :                :  * Sift a node up to the highest position it can hold according to the
                                267                 :                :  * comparator.
                                268                 :                :  */
                                269                 :                : static void
                                270                 :        1610219 : sift_up(binaryheap *heap, int node_off)
                                271                 :                : {
  719 nathan@postgresql.or      272                 :        1610219 :     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                 :                :      */
 4664 rhaas@postgresql.org      279         [ +  + ]:        4062456 :     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                 :        3916786 :         parent_off = parent_offset(node_off);
 1362 tgl@sss.pgh.pa.us         290                 :        3916786 :         parent_val = heap->bh_nodes[parent_off];
                                291                 :        3916786 :         cmp = heap->bh_compare(node_val,
                                292                 :                :                                parent_val,
                                293                 :                :                                heap->bh_arg);
 4664 rhaas@postgresql.org      294         [ +  + ]:        3916786 :         if (cmp <= 0)
                                295                 :        1464549 :             break;
                                296                 :                : 
                                297                 :                :         /*
                                298                 :                :          * Otherwise, swap the parent value with the hole, and go on to check
                                299                 :                :          * the node's new parent.
                                300                 :                :          */
  513 msawada@postgresql.o      301                 :        2452237 :         heap->bh_nodes[node_off] = parent_val;
 4664 rhaas@postgresql.org      302                 :        2452237 :         node_off = parent_off;
                                303                 :                :     }
                                304                 :                :     /* Re-fill the hole */
  513 msawada@postgresql.o      305                 :        1610219 :     heap->bh_nodes[node_off] = node_val;
 4664 rhaas@postgresql.org      306                 :        1610219 : }
                                307                 :                : 
                                308                 :                : /*
                                309                 :                :  * Sift a node down from its current position to satisfy the heap
                                310                 :                :  * property.
                                311                 :                :  */
                                312                 :                : static void
                                313                 :        2093615 : sift_down(binaryheap *heap, int node_off)
                                314                 :                : {
  719 nathan@postgresql.or      315                 :        2093615 :     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)
 4664 rhaas@postgresql.org      323                 :       14771042 :     {
                                324                 :       16864657 :         int         left_off = left_offset(node_off);
                                325                 :       16864657 :         int         right_off = right_offset(node_off);
  311 nathan@postgresql.or      326                 :       16864657 :         int         swap_off = left_off;
                                327                 :                : 
                                328                 :                :         /* Is the right child larger than the left child? */
 4664 rhaas@postgresql.org      329   [ +  +  +  + ]:       32094983 :         if (right_off < heap->bh_size &&
  311 nathan@postgresql.or      330                 :       15230326 :             heap->bh_compare(heap->bh_nodes[left_off],
                                331                 :                :                              heap->bh_nodes[right_off],
                                332                 :                :                              heap->bh_arg) < 0)
                                333                 :        7521333 :             swap_off = right_off;
                                334                 :                : 
                                335                 :                :         /*
                                336                 :                :          * If no children or parent is >= the larger child, heap condition is
                                337                 :                :          * satisfied, and we're done.
                                338                 :                :          */
                                339   [ +  +  +  + ]:       32518375 :         if (left_off >= heap->bh_size ||
                                340                 :       15653718 :             heap->bh_compare(node_val,
                                341                 :                :                              heap->bh_nodes[swap_off],
                                342                 :                :                              heap->bh_arg) >= 0)
                                343                 :                :             break;
                                344                 :                : 
                                345                 :                :         /*
                                346                 :                :          * Otherwise, swap the hole with the child that violates the heap
                                347                 :                :          * property; then go on to check its children.
                                348                 :                :          */
  513 msawada@postgresql.o      349                 :       14771042 :         heap->bh_nodes[node_off] = heap->bh_nodes[swap_off];
 4664 rhaas@postgresql.org      350                 :       14771042 :         node_off = swap_off;
                                351                 :                :     }
                                352                 :                :     /* Re-fill the hole */
  513 msawada@postgresql.o      353                 :        2093615 :     heap->bh_nodes[node_off] = node_val;
 4664 rhaas@postgresql.org      354                 :        2093615 : }
        

Generated by: LCOV version 2.4-beta