LCOV - differential code coverage report
Current view: top level - src/backend/lib - binaryheap.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 78.0 % 91 71 20 71
Current Date: 2023-04-08 17:13:01 Functions: 85.7 % 14 12 2 12
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 78.0 % 91 71 20 71
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 85.7 % 14 12 2 12

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

Generated by: LCOV version v1.16-55-g56c0a2a