1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow strict
    
  8.  */
    
  9. 
    
  10. type Heap<T: Node> = Array<T>;
    
  11. type Node = {
    
  12.   id: number,
    
  13.   sortIndex: number,
    
  14.   ...
    
  15. };
    
  16. 
    
  17. export function push<T: Node>(heap: Heap<T>, node: T): void {
    
  18.   const index = heap.length;
    
  19.   heap.push(node);
    
  20.   siftUp(heap, node, index);
    
  21. }
    
  22. 
    
  23. export function peek<T: Node>(heap: Heap<T>): T | null {
    
  24.   return heap.length === 0 ? null : heap[0];
    
  25. }
    
  26. 
    
  27. export function pop<T: Node>(heap: Heap<T>): T | null {
    
  28.   if (heap.length === 0) {
    
  29.     return null;
    
  30.   }
    
  31.   const first = heap[0];
    
  32.   const last = heap.pop();
    
  33.   if (last !== first) {
    
  34.     heap[0] = last;
    
  35.     siftDown(heap, last, 0);
    
  36.   }
    
  37.   return first;
    
  38. }
    
  39. 
    
  40. function siftUp<T: Node>(heap: Heap<T>, node: T, i: number): void {
    
  41.   let index = i;
    
  42.   while (index > 0) {
    
  43.     const parentIndex = (index - 1) >>> 1;
    
  44.     const parent = heap[parentIndex];
    
  45.     if (compare(parent, node) > 0) {
    
  46.       // The parent is larger. Swap positions.
    
  47.       heap[parentIndex] = node;
    
  48.       heap[index] = parent;
    
  49.       index = parentIndex;
    
  50.     } else {
    
  51.       // The parent is smaller. Exit.
    
  52.       return;
    
  53.     }
    
  54.   }
    
  55. }
    
  56. 
    
  57. function siftDown<T: Node>(heap: Heap<T>, node: T, i: number): void {
    
  58.   let index = i;
    
  59.   const length = heap.length;
    
  60.   const halfLength = length >>> 1;
    
  61.   while (index < halfLength) {
    
  62.     const leftIndex = (index + 1) * 2 - 1;
    
  63.     const left = heap[leftIndex];
    
  64.     const rightIndex = leftIndex + 1;
    
  65.     const right = heap[rightIndex];
    
  66. 
    
  67.     // If the left or right node is smaller, swap with the smaller of those.
    
  68.     if (compare(left, node) < 0) {
    
  69.       if (rightIndex < length && compare(right, left) < 0) {
    
  70.         heap[index] = right;
    
  71.         heap[rightIndex] = node;
    
  72.         index = rightIndex;
    
  73.       } else {
    
  74.         heap[index] = left;
    
  75.         heap[leftIndex] = node;
    
  76.         index = leftIndex;
    
  77.       }
    
  78.     } else if (rightIndex < length && compare(right, node) < 0) {
    
  79.       heap[index] = right;
    
  80.       heap[rightIndex] = node;
    
  81.       index = rightIndex;
    
  82.     } else {
    
  83.       // Neither child is smaller. Exit.
    
  84.       return;
    
  85.     }
    
  86.   }
    
  87. }
    
  88. 
    
  89. function compare(a: Node, b: Node) {
    
  90.   // Compare sort index first, then task id.
    
  91.   const diff = a.sortIndex - b.sortIndex;
    
  92.   return diff !== 0 ? diff : a.id - b.id;
    
  93. }