LCOV - code coverage report
Current view: top level - src/backend/lib - pairingheap.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 95.3 % 85 81
Test Date: 2026-07-07 06:15:36 Functions: 88.9 % 9 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 96.7 % 30 29

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pairingheap.c
       4                 :             :  *    A Pairing Heap implementation
       5                 :             :  *
       6                 :             :  * A pairing heap is a data structure that's useful for implementing
       7                 :             :  * priority queues. It is simple to implement, and provides amortized O(1)
       8                 :             :  * insert and find-min operations, and amortized O(log n) delete-min.
       9                 :             :  *
      10                 :             :  * The pairing heap was first described in this paper:
      11                 :             :  *
      12                 :             :  *  Michael L. Fredman, Robert Sedgewick, Daniel D. Sleator, and Robert E.
      13                 :             :  *   Tarjan. 1986.
      14                 :             :  *  The pairing heap: a new form of self-adjusting heap.
      15                 :             :  *  Algorithmica 1, 1 (January 1986), pages 111-129. DOI: 10.1007/BF01840439
      16                 :             :  *
      17                 :             :  * Portions Copyright (c) 2012-2026, PostgreSQL Global Development Group
      18                 :             :  *
      19                 :             :  * IDENTIFICATION
      20                 :             :  *    src/backend/lib/pairingheap.c
      21                 :             :  *
      22                 :             :  *-------------------------------------------------------------------------
      23                 :             :  */
      24                 :             : 
      25                 :             : #include "postgres.h"
      26                 :             : 
      27                 :             : #include "lib/pairingheap.h"
      28                 :             : 
      29                 :             : static pairingheap_node *merge(pairingheap *heap, pairingheap_node *a,
      30                 :             :                                pairingheap_node *b);
      31                 :             : static pairingheap_node *merge_children(pairingheap *heap,
      32                 :             :                                         pairingheap_node *children);
      33                 :             : 
      34                 :             : /*
      35                 :             :  * pairingheap_allocate
      36                 :             :  *
      37                 :             :  * Returns a pointer to a newly-allocated heap, with the heap property defined
      38                 :             :  * by the given comparator function, which will be invoked with the additional
      39                 :             :  * argument specified by 'arg'.
      40                 :             :  */
      41                 :             : pairingheap *
      42                 :        8221 : pairingheap_allocate(pairingheap_comparator compare, void *arg)
      43                 :             : {
      44                 :             :     pairingheap *heap;
      45                 :             : 
      46                 :        8221 :     heap = palloc_object(pairingheap);
      47                 :        8221 :     pairingheap_initialize(heap, compare, arg);
      48                 :             : 
      49                 :        8221 :     return heap;
      50                 :             : }
      51                 :             : 
      52                 :             : /*
      53                 :             :  * pairingheap_initialize
      54                 :             :  *
      55                 :             :  * Same as pairingheap_allocate(), but initializes the pairing heap in-place
      56                 :             :  * rather than allocating a new chunk of memory.  Useful to store the pairing
      57                 :             :  * heap in a shared memory.
      58                 :             :  */
      59                 :             : void
      60                 :       13205 : pairingheap_initialize(pairingheap *heap, pairingheap_comparator compare,
      61                 :             :                        void *arg)
      62                 :             : {
      63                 :       13205 :     heap->ph_compare = compare;
      64                 :       13205 :     heap->ph_arg = arg;
      65                 :             : 
      66                 :       13205 :     heap->ph_root = NULL;
      67                 :       13205 : }
      68                 :             : 
      69                 :             : /*
      70                 :             :  * pairingheap_free
      71                 :             :  *
      72                 :             :  * Releases memory used by the given pairingheap.
      73                 :             :  *
      74                 :             :  * Note: The nodes in the heap are not freed!
      75                 :             :  */
      76                 :             : void
      77                 :           0 : pairingheap_free(pairingheap *heap)
      78                 :             : {
      79                 :           0 :     pfree(heap);
      80                 :           0 : }
      81                 :             : 
      82                 :             : /*
      83                 :             :  * A helper function to merge two subheaps into one.
      84                 :             :  *
      85                 :             :  * The subheap with smaller value is put as a child of the other one (assuming
      86                 :             :  * a max-heap).
      87                 :             :  *
      88                 :             :  * The next_sibling and prev_or_parent pointers of the input nodes are
      89                 :             :  * ignored. On return, the returned node's next_sibling and prev_or_parent
      90                 :             :  * pointers are garbage.
      91                 :             :  */
      92                 :             : static pairingheap_node *
      93                 :    16400999 : merge(pairingheap *heap, pairingheap_node *a, pairingheap_node *b)
      94                 :             : {
      95         [ +  + ]:    16400999 :     if (a == NULL)
      96                 :     2932877 :         return b;
      97         [ -  + ]:    13468122 :     if (b == NULL)
      98                 :           0 :         return a;
      99                 :             : 
     100                 :             :     /* swap 'a' and 'b' so that 'a' is the one with larger value */
     101         [ +  + ]:    13468122 :     if (heap->ph_compare(a, b, heap->ph_arg) < 0)
     102                 :             :     {
     103                 :             :         pairingheap_node *tmp;
     104                 :             : 
     105                 :     1296624 :         tmp = a;
     106                 :     1296624 :         a = b;
     107                 :     1296624 :         b = tmp;
     108                 :             :     }
     109                 :             : 
     110                 :             :     /* and put 'b' as a child of 'a' */
     111         [ +  + ]:    13468122 :     if (a->first_child)
     112                 :     5202044 :         a->first_child->prev_or_parent = b;
     113                 :    13468122 :     b->prev_or_parent = a;
     114                 :    13468122 :     b->next_sibling = a->first_child;
     115                 :    13468122 :     a->first_child = b;
     116                 :             : 
     117                 :    13468122 :     return a;
     118                 :             : }
     119                 :             : 
     120                 :             : /*
     121                 :             :  * pairingheap_add
     122                 :             :  *
     123                 :             :  * Adds the given node to the heap in O(1) time.
     124                 :             :  */
     125                 :             : void
     126                 :    13619908 : pairingheap_add(pairingheap *heap, pairingheap_node *node)
     127                 :             : {
     128                 :    13619908 :     node->first_child = NULL;
     129                 :             : 
     130                 :             :     /* Link the new node as a new tree */
     131                 :    13619908 :     heap->ph_root = merge(heap, heap->ph_root, node);
     132                 :    13619908 :     heap->ph_root->prev_or_parent = NULL;
     133                 :    13619908 :     heap->ph_root->next_sibling = NULL;
     134                 :    13619908 : }
     135                 :             : 
     136                 :             : /*
     137                 :             :  * pairingheap_first
     138                 :             :  *
     139                 :             :  * Returns a pointer to the first (root, topmost) node in the heap without
     140                 :             :  * modifying the heap. The caller must ensure that this routine is not used on
     141                 :             :  * an empty heap. Always O(1).
     142                 :             :  */
     143                 :             : pairingheap_node *
     144                 :     2402620 : pairingheap_first(pairingheap *heap)
     145                 :             : {
     146                 :             :     Assert(!pairingheap_is_empty(heap));
     147                 :             : 
     148                 :     2402620 :     return heap->ph_root;
     149                 :             : }
     150                 :             : 
     151                 :             : /*
     152                 :             :  * pairingheap_remove_first
     153                 :             :  *
     154                 :             :  * Removes the first (root, topmost) node in the heap and returns a pointer to
     155                 :             :  * it after rebalancing the heap. The caller must ensure that this routine is
     156                 :             :  * not used on an empty heap. O(log n) amortized.
     157                 :             :  */
     158                 :             : pairingheap_node *
     159                 :     3742949 : pairingheap_remove_first(pairingheap *heap)
     160                 :             : {
     161                 :             :     pairingheap_node *result;
     162                 :             :     pairingheap_node *children;
     163                 :             : 
     164                 :             :     Assert(!pairingheap_is_empty(heap));
     165                 :             : 
     166                 :             :     /* Remove the root, and form a new heap of its children. */
     167                 :     3742949 :     result = heap->ph_root;
     168                 :     3742949 :     children = result->first_child;
     169                 :             : 
     170                 :     3742949 :     heap->ph_root = merge_children(heap, children);
     171         [ +  + ]:     3742949 :     if (heap->ph_root)
     172                 :             :     {
     173                 :      810250 :         heap->ph_root->prev_or_parent = NULL;
     174                 :      810250 :         heap->ph_root->next_sibling = NULL;
     175                 :             :     }
     176                 :             : 
     177                 :     3742949 :     return result;
     178                 :             : }
     179                 :             : 
     180                 :             : /*
     181                 :             :  * Remove 'node' from the heap. O(log n) amortized.
     182                 :             :  */
     183                 :             : void
     184                 :    13251224 : pairingheap_remove(pairingheap *heap, pairingheap_node *node)
     185                 :             : {
     186                 :             :     pairingheap_node *children;
     187                 :             :     pairingheap_node *replacement;
     188                 :             :     pairingheap_node *next_sibling;
     189                 :             :     pairingheap_node **prev_ptr;
     190                 :             : 
     191                 :             :     /*
     192                 :             :      * If the removed node happens to be the root node, do it with
     193                 :             :      * pairingheap_remove_first().
     194                 :             :      */
     195         [ +  + ]:    13251224 :     if (node == heap->ph_root)
     196                 :             :     {
     197                 :     3392953 :         (void) pairingheap_remove_first(heap);
     198                 :     3392953 :         return;
     199                 :             :     }
     200                 :             : 
     201                 :             :     /*
     202                 :             :      * Before we modify anything, remember the removed node's first_child and
     203                 :             :      * next_sibling pointers.
     204                 :             :      */
     205                 :     9858271 :     children = node->first_child;
     206                 :     9858271 :     next_sibling = node->next_sibling;
     207                 :             : 
     208                 :             :     /*
     209                 :             :      * Also find the pointer to the removed node in its previous sibling, or
     210                 :             :      * if this is the first child of its parent, in its parent.
     211                 :             :      */
     212         [ +  + ]:     9858271 :     if (node->prev_or_parent->first_child == node)
     213                 :     9840024 :         prev_ptr = &node->prev_or_parent->first_child;
     214                 :             :     else
     215                 :       18247 :         prev_ptr = &node->prev_or_parent->next_sibling;
     216                 :             :     Assert(*prev_ptr == node);
     217                 :             : 
     218                 :             :     /*
     219                 :             :      * If this node has children, make a new subheap of the children and link
     220                 :             :      * the subheap in place of the removed node. Otherwise just unlink this
     221                 :             :      * node.
     222                 :             :      */
     223         [ +  + ]:     9858271 :     if (children)
     224                 :             :     {
     225                 :        1080 :         replacement = merge_children(heap, children);
     226                 :             : 
     227                 :        1080 :         replacement->prev_or_parent = node->prev_or_parent;
     228                 :        1080 :         replacement->next_sibling = node->next_sibling;
     229                 :        1080 :         *prev_ptr = replacement;
     230         [ +  + ]:        1080 :         if (next_sibling)
     231                 :         944 :             next_sibling->prev_or_parent = replacement;
     232                 :             :     }
     233                 :             :     else
     234                 :             :     {
     235                 :     9857191 :         *prev_ptr = next_sibling;
     236         [ +  + ]:     9857191 :         if (next_sibling)
     237                 :     2397793 :             next_sibling->prev_or_parent = node->prev_or_parent;
     238                 :             :     }
     239                 :             : }
     240                 :             : 
     241                 :             : /*
     242                 :             :  * Merge a list of subheaps into a single heap.
     243                 :             :  *
     244                 :             :  * This implements the basic two-pass merging strategy, first forming pairs
     245                 :             :  * from left to right, and then merging the pairs.
     246                 :             :  */
     247                 :             : static pairingheap_node *
     248                 :     3744029 : merge_children(pairingheap *heap, pairingheap_node *children)
     249                 :             : {
     250                 :             :     pairingheap_node *curr,
     251                 :             :                *next;
     252                 :             :     pairingheap_node *pairs;
     253                 :             :     pairingheap_node *newroot;
     254                 :             : 
     255   [ +  +  +  + ]:     3744029 :     if (children == NULL || children->next_sibling == NULL)
     256                 :     3413299 :         return children;
     257                 :             : 
     258                 :             :     /* Walk the subheaps from left to right, merging in pairs */
     259                 :      330730 :     next = children;
     260                 :      330730 :     pairs = NULL;
     261                 :             :     for (;;)
     262                 :             :     {
     263                 :     1807214 :         curr = next;
     264                 :             : 
     265         [ +  + ]:     1807214 :         if (curr == NULL)
     266                 :      171877 :             break;
     267                 :             : 
     268         [ +  + ]:     1635337 :         if (curr->next_sibling == NULL)
     269                 :             :         {
     270                 :             :             /* last odd node at the end of list */
     271                 :      158853 :             curr->next_sibling = pairs;
     272                 :      158853 :             pairs = curr;
     273                 :      158853 :             break;
     274                 :             :         }
     275                 :             : 
     276                 :     1476484 :         next = curr->next_sibling->next_sibling;
     277                 :             : 
     278                 :             :         /* merge this and the next subheap, and add to 'pairs' list. */
     279                 :             : 
     280                 :     1476484 :         curr = merge(heap, curr, curr->next_sibling);
     281                 :     1476484 :         curr->next_sibling = pairs;
     282                 :     1476484 :         pairs = curr;
     283                 :             :     }
     284                 :             : 
     285                 :             :     /*
     286                 :             :      * Merge all the pairs together to form a single heap.
     287                 :             :      */
     288                 :      330730 :     newroot = pairs;
     289                 :      330730 :     next = pairs->next_sibling;
     290         [ +  + ]:     1635337 :     while (next)
     291                 :             :     {
     292                 :     1304607 :         curr = next;
     293                 :     1304607 :         next = curr->next_sibling;
     294                 :             : 
     295                 :     1304607 :         newroot = merge(heap, newroot, curr);
     296                 :             :     }
     297                 :             : 
     298                 :      330730 :     return newroot;
     299                 :             : }
     300                 :             : 
     301                 :             : /*
     302                 :             :  * A debug function to dump the contents of the heap as a string.
     303                 :             :  *
     304                 :             :  * The 'dumpfunc' callback appends a string representation of a single node
     305                 :             :  * to the StringInfo. 'opaque' can be used to pass more information to the
     306                 :             :  * callback.
     307                 :             :  */
     308                 :             : #ifdef PAIRINGHEAP_DEBUG
     309                 :             : static void
     310                 :             : pairingheap_dump_recurse(StringInfo buf,
     311                 :             :                          pairingheap_node *node,
     312                 :             :                          void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
     313                 :             :                          void *opaque,
     314                 :             :                          int depth,
     315                 :             :                          pairingheap_node *prev_or_parent)
     316                 :             : {
     317                 :             :     while (node)
     318                 :             :     {
     319                 :             :         Assert(node->prev_or_parent == prev_or_parent);
     320                 :             : 
     321                 :             :         appendStringInfoSpaces(buf, depth * 4);
     322                 :             :         dumpfunc(node, buf, opaque);
     323                 :             :         appendStringInfoChar(buf, '\n');
     324                 :             :         if (node->first_child)
     325                 :             :             pairingheap_dump_recurse(buf, node->first_child, dumpfunc, opaque, depth + 1, node);
     326                 :             :         prev_or_parent = node;
     327                 :             :         node = node->next_sibling;
     328                 :             :     }
     329                 :             : }
     330                 :             : 
     331                 :             : char *
     332                 :             : pairingheap_dump(pairingheap *heap,
     333                 :             :                  void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
     334                 :             :                  void *opaque)
     335                 :             : {
     336                 :             :     StringInfoData buf;
     337                 :             : 
     338                 :             :     if (!heap->ph_root)
     339                 :             :         return pstrdup("(empty)");
     340                 :             : 
     341                 :             :     initStringInfo(&buf);
     342                 :             : 
     343                 :             :     pairingheap_dump_recurse(&buf, heap->ph_root, dumpfunc, opaque, 0, NULL);
     344                 :             : 
     345                 :             :     return buf.data;
     346                 :             : }
     347                 :             : #endif
        

Generated by: LCOV version 2.0-1