main
js 95 lines 2.36 KB
Raw
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 // $FlowFixMe[incompatible-type]
35 heap[0] = last;
36 // $FlowFixMe[incompatible-type]
37 siftDown(heap, last, 0);
38 }
39 return first;
40 }
41
42 function siftUp<T: Node>(heap: Heap<T>, node: T, i: number): void {
43 let index = i;
44 while (index > 0) {
45 const parentIndex = (index - 1) >>> 1;
46 const parent = heap[parentIndex];
47 if (compare(parent, node) > 0) {
48 // The parent is larger. Swap positions.
49 heap[parentIndex] = node;
50 heap[index] = parent;
51 index = parentIndex;
52 } else {
53 // The parent is smaller. Exit.
54 return;
55 }
56 }
57 }
58
59 function siftDown<T: Node>(heap: Heap<T>, node: T, i: number): void {
60 let index = i;
61 const length = heap.length;
62 const halfLength = length >>> 1;
63 while (index < halfLength) {
64 const leftIndex = (index + 1) * 2 - 1;
65 const left = heap[leftIndex];
66 const rightIndex = leftIndex + 1;
67 const right = heap[rightIndex];
68
69 // If the left or right node is smaller, swap with the smaller of those.
70 if (compare(left, node) < 0) {
71 if (rightIndex < length && compare(right, left) < 0) {
72 heap[index] = right;
73 heap[rightIndex] = node;
74 index = rightIndex;
75 } else {
76 heap[index] = left;
77 heap[leftIndex] = node;
78 index = leftIndex;
79 }
80 } else if (rightIndex < length && compare(right, node) < 0) {
81 heap[index] = right;
82 heap[rightIndex] = node;
83 index = rightIndex;
84 } else {
85 // Neither child is smaller. Exit.
86 return;
87 }
88 }
89 }
90
91 function compare(a: Node, b: Node) {
92 // Compare sort index first, then task id.
93 const diff = a.sortIndex - b.sortIndex;
94 return diff !== 0 ? diff : a.id - b.id;
95 }