LCOV - code coverage report
Current view: top level - src/backend/lib - pairingheap.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 96.3 % 108 104
Test Date: 2026-01-26 10:56:24 Functions: 88.9 % 9 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 86.8 % 38 33

             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                 :         944 : pairingheap_allocate(pairingheap_comparator compare, void *arg)
      43                 :             : {
      44                 :         944 :         pairingheap *heap;
      45                 :             : 
      46                 :         944 :         heap = palloc_object(pairingheap);
      47                 :         944 :         pairingheap_initialize(heap, compare, arg);
      48                 :             : 
      49                 :        1888 :         return heap;
      50                 :         944 : }
      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                 :         968 : pairingheap_initialize(pairingheap *heap, pairingheap_comparator compare,
      61                 :             :                                            void *arg)
      62                 :             : {
      63                 :         968 :         heap->ph_compare = compare;
      64                 :         968 :         heap->ph_arg = arg;
      65                 :             : 
      66                 :         968 :         heap->ph_root = NULL;
      67                 :         968 : }
      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                 :     2274527 : merge(pairingheap *heap, pairingheap_node *a, pairingheap_node *b)
      94                 :             : {
      95         [ +  + ]:     2274527 :         if (a == NULL)
      96                 :      193539 :                 return b;
      97         [ +  - ]:     2080988 :         if (b == NULL)
      98                 :           0 :                 return a;
      99                 :             : 
     100                 :             :         /* swap 'a' and 'b' so that 'a' is the one with larger value */
     101         [ +  + ]:     2080988 :         if (heap->ph_compare(a, b, heap->ph_arg) < 0)
     102                 :             :         {
     103                 :      264278 :                 pairingheap_node *tmp;
     104                 :             : 
     105                 :      264278 :                 tmp = a;
     106                 :      264278 :                 a = b;
     107                 :      264278 :                 b = tmp;
     108                 :      264278 :         }
     109                 :             : 
     110                 :             :         /* and put 'b' as a child of 'a' */
     111         [ +  + ]:     2080988 :         if (a->first_child)
     112                 :      859474 :                 a->first_child->prev_or_parent = b;
     113                 :     2080988 :         b->prev_or_parent = a;
     114                 :     2080988 :         b->next_sibling = a->first_child;
     115                 :     2080988 :         a->first_child = b;
     116                 :             : 
     117                 :     2080988 :         return a;
     118                 :     2274527 : }
     119                 :             : 
     120                 :             : /*
     121                 :             :  * pairingheap_add
     122                 :             :  *
     123                 :             :  * Adds the given node to the heap in O(1) time.
     124                 :             :  */
     125                 :             : void
     126                 :     1600533 : pairingheap_add(pairingheap *heap, pairingheap_node *node)
     127                 :             : {
     128                 :     1600533 :         node->first_child = NULL;
     129                 :             : 
     130                 :             :         /* Link the new node as a new tree */
     131                 :     1600533 :         heap->ph_root = merge(heap, heap->ph_root, node);
     132                 :     1600533 :         heap->ph_root->prev_or_parent = NULL;
     133                 :     1600533 :         heap->ph_root->next_sibling = NULL;
     134                 :     1600533 : }
     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                 :      104422 : pairingheap_first(pairingheap *heap)
     145                 :             : {
     146         [ +  - ]:      104422 :         Assert(!pairingheap_is_empty(heap));
     147                 :             : 
     148                 :      104422 :         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                 :      299361 : pairingheap_remove_first(pairingheap *heap)
     160                 :             : {
     161                 :      299361 :         pairingheap_node *result;
     162                 :      299361 :         pairingheap_node *children;
     163                 :             : 
     164         [ +  - ]:      299361 :         Assert(!pairingheap_is_empty(heap));
     165                 :             : 
     166                 :             :         /* Remove the root, and form a new heap of its children. */
     167                 :      299361 :         result = heap->ph_root;
     168                 :      299361 :         children = result->first_child;
     169                 :             : 
     170                 :      299361 :         heap->ph_root = merge_children(heap, children);
     171         [ +  + ]:      299361 :         if (heap->ph_root)
     172                 :             :         {
     173                 :      105848 :                 heap->ph_root->prev_or_parent = NULL;
     174                 :      105848 :                 heap->ph_root->next_sibling = NULL;
     175                 :      105848 :         }
     176                 :             : 
     177                 :      598722 :         return result;
     178                 :      299361 : }
     179                 :             : 
     180                 :             : /*
     181                 :             :  * Remove 'node' from the heap. O(log n) amortized.
     182                 :             :  */
     183                 :             : void
     184                 :     1516709 : pairingheap_remove(pairingheap *heap, pairingheap_node *node)
     185                 :             : {
     186                 :     1516709 :         pairingheap_node *children;
     187                 :     1516709 :         pairingheap_node *replacement;
     188                 :     1516709 :         pairingheap_node *next_sibling;
     189                 :     1516709 :         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         [ +  + ]:     1516709 :         if (node == heap->ph_root)
     196                 :             :         {
     197                 :      217712 :                 (void) pairingheap_remove_first(heap);
     198                 :      217712 :                 return;
     199                 :             :         }
     200                 :             : 
     201                 :             :         /*
     202                 :             :          * Before we modify anything, remember the removed node's first_child and
     203                 :             :          * next_sibling pointers.
     204                 :             :          */
     205                 :     1298997 :         children = node->first_child;
     206                 :     1298997 :         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         [ +  + ]:     1298997 :         if (node->prev_or_parent->first_child == node)
     213                 :     1294024 :                 prev_ptr = &node->prev_or_parent->first_child;
     214                 :             :         else
     215                 :        4973 :                 prev_ptr = &node->prev_or_parent->next_sibling;
     216         [ +  - ]:     1298997 :         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         [ +  + ]:     1298997 :         if (children)
     224                 :             :         {
     225                 :         528 :                 replacement = merge_children(heap, children);
     226                 :             : 
     227                 :         528 :                 replacement->prev_or_parent = node->prev_or_parent;
     228                 :         528 :                 replacement->next_sibling = node->next_sibling;
     229                 :         528 :                 *prev_ptr = replacement;
     230         [ +  + ]:         528 :                 if (next_sibling)
     231                 :         523 :                         next_sibling->prev_or_parent = replacement;
     232                 :         528 :         }
     233                 :             :         else
     234                 :             :         {
     235                 :     1298469 :                 *prev_ptr = next_sibling;
     236         [ +  + ]:     1298469 :                 if (next_sibling)
     237                 :      182392 :                         next_sibling->prev_or_parent = node->prev_or_parent;
     238                 :             :         }
     239         [ -  + ]:     1516709 : }
     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                 :      299889 : merge_children(pairingheap *heap, pairingheap_node *children)
     249                 :             : {
     250                 :      299889 :         pairingheap_node *curr,
     251                 :             :                            *next;
     252                 :      299889 :         pairingheap_node *pairs;
     253                 :      299889 :         pairingheap_node *newroot;
     254                 :             : 
     255   [ +  +  +  + ]:      299889 :         if (children == NULL || children->next_sibling == NULL)
     256                 :      222507 :                 return children;
     257                 :             : 
     258                 :             :         /* Walk the subheaps from left to right, merging in pairs */
     259                 :       77382 :         next = children;
     260                 :       77382 :         pairs = NULL;
     261                 :      434416 :         for (;;)
     262                 :             :         {
     263                 :      434416 :                 curr = next;
     264                 :             : 
     265         [ +  + ]:      434416 :                 if (curr == NULL)
     266                 :       40074 :                         break;
     267                 :             : 
     268         [ +  + ]:      394342 :                 if (curr->next_sibling == NULL)
     269                 :             :                 {
     270                 :             :                         /* last odd node at the end of list */
     271                 :       37308 :                         curr->next_sibling = pairs;
     272                 :       37308 :                         pairs = curr;
     273                 :       37308 :                         break;
     274                 :             :                 }
     275                 :             : 
     276                 :      357034 :                 next = curr->next_sibling->next_sibling;
     277                 :             : 
     278                 :             :                 /* merge this and the next subheap, and add to 'pairs' list. */
     279                 :             : 
     280                 :      357034 :                 curr = merge(heap, curr, curr->next_sibling);
     281                 :      357034 :                 curr->next_sibling = pairs;
     282                 :      357034 :                 pairs = curr;
     283                 :             :         }
     284                 :             : 
     285                 :             :         /*
     286                 :             :          * Merge all the pairs together to form a single heap.
     287                 :             :          */
     288                 :       77382 :         newroot = pairs;
     289                 :       77382 :         next = pairs->next_sibling;
     290         [ +  + ]:      394342 :         while (next)
     291                 :             :         {
     292                 :      316960 :                 curr = next;
     293                 :      316960 :                 next = curr->next_sibling;
     294                 :             : 
     295                 :      316960 :                 newroot = merge(heap, newroot, curr);
     296                 :             :         }
     297                 :             : 
     298                 :       77382 :         return newroot;
     299                 :      299889 : }
     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.3.2-1