'use strict'; const { Array, } = primordials; // The PriorityQueue is a basic implementation of a binary heap that accepts // a custom sorting function via its constructor. This function is passed // the two nodes to compare, similar to the native Array#sort. Crucially // this enables priority queues that are based on a comparison of more than // just a single criteria. module.exports = class PriorityQueue { #compare = (a, b) => a - b; #heap = new Array(64); #setPosition; #size = 0; constructor(comparator, setPosition) { if (comparator !== undefined) this.#compare = comparator; if (setPosition !== undefined) this.#setPosition = setPosition; } insert(value) { const heap = this.#heap; const pos = ++this.#size; heap[pos] = value; if (heap.length === pos) heap.length *= 2; this.percolateUp(pos); } peek() { return this.#heap[1]; } peekBottom() { return this.#heap[this.#size]; } percolateDown(pos) { const compare = this.#compare; const setPosition = this.#setPosition; const heap = this.#heap; const size = this.#size; const item = heap[pos]; while (pos * 2 <= size) { let childIndex = pos * 2 + 1; if (childIndex > size || compare(heap[pos * 2], heap[childIndex]) < 0) childIndex = pos * 2; const child = heap[childIndex]; if (compare(item, child) <= 0) break; if (setPosition !== undefined) setPosition(child, pos); heap[pos] = child; pos = childIndex; } heap[pos] = item; if (setPosition !== undefined) setPosition(item, pos); } percolateUp(pos) { const heap = this.#heap; const compare = this.#compare; const setPosition = this.#setPosition; const item = heap[pos]; while (pos > 1) { const parent = heap[pos / 2 | 0]; if (compare(parent, item) <= 0) break; heap[pos] = parent; if (setPosition !== undefined) setPosition(parent, pos); pos = pos / 2 | 0; } heap[pos] = item; if (setPosition !== undefined) setPosition(item, pos); } removeAt(pos) { const heap = this.#heap; const size = --this.#size; heap[pos] = heap[size + 1]; heap[size + 1] = undefined; if (size > 0 && pos <= size) { if (pos > 1 && this.#compare(heap[pos / 2 | 0], heap[pos]) > 0) this.percolateUp(pos); else this.percolateDown(pos); } } shift() { const heap = this.#heap; const value = heap[1]; if (value === undefined) return; this.removeAt(1); return value; } };