LCOV - differential code coverage report
Current view: top level - src/backend/lib - pairingheap.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 95.3 % 85 81 4 81
Current Date: 2023-04-08 15:15:32 Functions: 87.5 % 8 7 1 7
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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 CBC        1790 : pairingheap_allocate(pairingheap_comparator compare, void *arg)
      43                 : {
      44                 :     pairingheap *heap;
      45                 : 
      46            1790 :     heap = (pairingheap *) palloc(sizeof(pairingheap));
      47            1790 :     heap->ph_compare = compare;
      48            1790 :     heap->ph_arg = arg;
      49                 : 
      50            1790 :     heap->ph_root = NULL;
      51                 : 
      52            1790 :     return heap;
      53                 : }
      54                 : 
      55                 : /*
      56                 :  * pairingheap_free
      57                 :  *
      58                 :  * Releases memory used by the given pairingheap.
      59                 :  *
      60                 :  * Note: The nodes in the heap are not freed!
      61                 :  */
      62                 : void
      63 UBC           0 : pairingheap_free(pairingheap *heap)
      64                 : {
      65               0 :     pfree(heap);
      66               0 : }
      67                 : 
      68                 : /*
      69                 :  * A helper function to merge two subheaps into one.
      70                 :  *
      71                 :  * The subheap with smaller value is put as a child of the other one (assuming
      72                 :  * a max-heap).
      73                 :  *
      74                 :  * The next_sibling and prev_or_parent pointers of the input nodes are
      75                 :  * ignored. On return, the returned node's next_sibling and prev_or_parent
      76                 :  * pointers are garbage.
      77                 :  */
      78                 : static pairingheap_node *
      79 CBC    12455869 : merge(pairingheap *heap, pairingheap_node *a, pairingheap_node *b)
      80                 : {
      81        12455869 :     if (a == NULL)
      82         1220425 :         return b;
      83        11235444 :     if (b == NULL)
      84 UBC           0 :         return a;
      85                 : 
      86                 :     /* swap 'a' and 'b' so that 'a' is the one with larger value */
      87 CBC    11235444 :     if (heap->ph_compare(a, b, heap->ph_arg) < 0)
      88                 :     {
      89                 :         pairingheap_node *tmp;
      90                 : 
      91          805480 :         tmp = a;
      92          805480 :         a = b;
      93          805480 :         b = tmp;
      94                 :     }
      95                 : 
      96                 :     /* and put 'b' as a child of 'a' */
      97        11235444 :     if (a->first_child)
      98         4445148 :         a->first_child->prev_or_parent = b;
      99        11235444 :     b->prev_or_parent = a;
     100        11235444 :     b->next_sibling = a->first_child;
     101        11235444 :     a->first_child = b;
     102                 : 
     103        11235444 :     return a;
     104                 : }
     105                 : 
     106                 : /*
     107                 :  * pairingheap_add
     108                 :  *
     109                 :  * Adds the given node to the heap in O(1) time.
     110                 :  */
     111                 : void
     112        10344154 : pairingheap_add(pairingheap *heap, pairingheap_node *node)
     113                 : {
     114        10344154 :     node->first_child = NULL;
     115                 : 
     116                 :     /* Link the new node as a new tree */
     117        10344154 :     heap->ph_root = merge(heap, heap->ph_root, node);
     118        10344154 :     heap->ph_root->prev_or_parent = NULL;
     119        10344154 :     heap->ph_root->next_sibling = NULL;
     120        10344154 : }
     121                 : 
     122                 : /*
     123                 :  * pairingheap_first
     124                 :  *
     125                 :  * Returns a pointer to the first (root, topmost) node in the heap without
     126                 :  * modifying the heap. The caller must ensure that this routine is not used on
     127                 :  * an empty heap. Always O(1).
     128                 :  */
     129                 : pairingheap_node *
     130         1884481 : pairingheap_first(pairingheap *heap)
     131                 : {
     132         1884481 :     Assert(!pairingheap_is_empty(heap));
     133                 : 
     134         1884481 :     return heap->ph_root;
     135                 : }
     136                 : 
     137                 : /*
     138                 :  * pairingheap_remove_first
     139                 :  *
     140                 :  * Removes the first (root, topmost) node in the heap and returns a pointer to
     141                 :  * it after rebalancing the heap. The caller must ensure that this routine is
     142                 :  * not used on an empty heap. O(log n) amortized.
     143                 :  */
     144                 : pairingheap_node *
     145         1536918 : pairingheap_remove_first(pairingheap *heap)
     146                 : {
     147                 :     pairingheap_node *result;
     148                 :     pairingheap_node *children;
     149                 : 
     150         1536918 :     Assert(!pairingheap_is_empty(heap));
     151                 : 
     152                 :     /* Remove the root, and form a new heap of its children. */
     153         1536918 :     result = heap->ph_root;
     154         1536918 :     children = result->first_child;
     155                 : 
     156         1536918 :     heap->ph_root = merge_children(heap, children);
     157         1536918 :     if (heap->ph_root)
     158                 :     {
     159          316600 :         heap->ph_root->prev_or_parent = NULL;
     160          316600 :         heap->ph_root->next_sibling = NULL;
     161                 :     }
     162                 : 
     163         1536918 :     return result;
     164                 : }
     165                 : 
     166                 : /*
     167                 :  * Remove 'node' from the heap. O(log n) amortized.
     168                 :  */
     169                 : void
     170        10059970 : pairingheap_remove(pairingheap *heap, pairingheap_node *node)
     171                 : {
     172                 :     pairingheap_node *children;
     173                 :     pairingheap_node *replacement;
     174                 :     pairingheap_node *next_sibling;
     175                 :     pairingheap_node **prev_ptr;
     176                 : 
     177                 :     /*
     178                 :      * If the removed node happens to be the root node, do it with
     179                 :      * pairingheap_remove_first().
     180                 :      */
     181        10059970 :     if (node == heap->ph_root)
     182                 :     {
     183         1268543 :         (void) pairingheap_remove_first(heap);
     184         1268543 :         return;
     185                 :     }
     186                 : 
     187                 :     /*
     188                 :      * Before we modify anything, remember the removed node's first_child and
     189                 :      * next_sibling pointers.
     190                 :      */
     191         8791427 :     children = node->first_child;
     192         8791427 :     next_sibling = node->next_sibling;
     193                 : 
     194                 :     /*
     195                 :      * Also find the pointer to the removed node in its previous sibling, or
     196                 :      * if this is the first child of its parent, in its parent.
     197                 :      */
     198         8791427 :     if (node->prev_or_parent->first_child == node)
     199         8782052 :         prev_ptr = &node->prev_or_parent->first_child;
     200                 :     else
     201            9375 :         prev_ptr = &node->prev_or_parent->next_sibling;
     202         8791427 :     Assert(*prev_ptr == node);
     203                 : 
     204                 :     /*
     205                 :      * If this node has children, make a new subheap of the children and link
     206                 :      * the subheap in place of the removed node. Otherwise just unlink this
     207                 :      * node.
     208                 :      */
     209         8791427 :     if (children)
     210                 :     {
     211             793 :         replacement = merge_children(heap, children);
     212                 : 
     213             793 :         replacement->prev_or_parent = node->prev_or_parent;
     214             793 :         replacement->next_sibling = node->next_sibling;
     215             793 :         *prev_ptr = replacement;
     216             793 :         if (next_sibling)
     217             748 :             next_sibling->prev_or_parent = replacement;
     218                 :     }
     219                 :     else
     220                 :     {
     221         8790634 :         *prev_ptr = next_sibling;
     222         8790634 :         if (next_sibling)
     223         2319028 :             next_sibling->prev_or_parent = node->prev_or_parent;
     224                 :     }
     225                 : }
     226                 : 
     227                 : /*
     228                 :  * Merge a list of subheaps into a single heap.
     229                 :  *
     230                 :  * This implements the basic two-pass merging strategy, first forming pairs
     231                 :  * from left to right, and then merging the pairs.
     232                 :  */
     233                 : static pairingheap_node *
     234         1537711 : merge_children(pairingheap *heap, pairingheap_node *children)
     235                 : {
     236                 :     pairingheap_node *curr,
     237                 :                *next;
     238                 :     pairingheap_node *pairs;
     239                 :     pairingheap_node *newroot;
     240                 : 
     241         1537711 :     if (children == NULL || children->next_sibling == NULL)
     242         1284462 :         return children;
     243                 : 
     244                 :     /* Walk the subheaps from left to right, merging in pairs */
     245          253249 :     next = children;
     246          253249 :     pairs = NULL;
     247                 :     for (;;)
     248                 :     {
     249         1374806 :         curr = next;
     250                 : 
     251         1374806 :         if (curr == NULL)
     252          131399 :             break;
     253                 : 
     254         1243407 :         if (curr->next_sibling == NULL)
     255                 :         {
     256                 :             /* last odd node at the end of list */
     257          121850 :             curr->next_sibling = pairs;
     258          121850 :             pairs = curr;
     259          121850 :             break;
     260                 :         }
     261                 : 
     262         1121557 :         next = curr->next_sibling->next_sibling;
     263                 : 
     264                 :         /* merge this and the next subheap, and add to 'pairs' list. */
     265                 : 
     266         1121557 :         curr = merge(heap, curr, curr->next_sibling);
     267         1121557 :         curr->next_sibling = pairs;
     268         1121557 :         pairs = curr;
     269                 :     }
     270                 : 
     271                 :     /*
     272                 :      * Merge all the pairs together to form a single heap.
     273                 :      */
     274          253249 :     newroot = pairs;
     275          253249 :     next = pairs->next_sibling;
     276         1243407 :     while (next)
     277                 :     {
     278          990158 :         curr = next;
     279          990158 :         next = curr->next_sibling;
     280                 : 
     281          990158 :         newroot = merge(heap, newroot, curr);
     282                 :     }
     283                 : 
     284          253249 :     return newroot;
     285                 : }
     286                 : 
     287                 : /*
     288                 :  * A debug function to dump the contents of the heap as a string.
     289                 :  *
     290                 :  * The 'dumpfunc' callback appends a string representation of a single node
     291                 :  * to the StringInfo. 'opaque' can be used to pass more information to the
     292                 :  * callback.
     293                 :  */
     294                 : #ifdef PAIRINGHEAP_DEBUG
     295                 : static void
     296                 : pairingheap_dump_recurse(StringInfo buf,
     297                 :                          pairingheap_node *node,
     298                 :                          void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
     299                 :                          void *opaque,
     300                 :                          int depth,
     301                 :                          pairingheap_node *prev_or_parent)
     302                 : {
     303                 :     while (node)
     304                 :     {
     305                 :         Assert(node->prev_or_parent == prev_or_parent);
     306                 : 
     307                 :         appendStringInfoSpaces(buf, depth * 4);
     308                 :         dumpfunc(node, buf, opaque);
     309                 :         appendStringInfoChar(buf, '\n');
     310                 :         if (node->first_child)
     311                 :             pairingheap_dump_recurse(buf, node->first_child, dumpfunc, opaque, depth + 1, node);
     312                 :         prev_or_parent = node;
     313                 :         node = node->next_sibling;
     314                 :     }
     315                 : }
     316                 : 
     317                 : char *
     318                 : pairingheap_dump(pairingheap *heap,
     319                 :                  void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
     320                 :                  void *opaque)
     321                 : {
     322                 :     StringInfoData buf;
     323                 : 
     324                 :     if (!heap->ph_root)
     325                 :         return pstrdup("(empty)");
     326                 : 
     327                 :     initStringInfo(&buf);
     328                 : 
     329                 :     pairingheap_dump_recurse(&buf, heap->ph_root, dumpfunc, opaque, 0, NULL);
     330                 : 
     331                 :     return buf.data;
     332                 : }
     333                 : #endif
        

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