'use strict'; const { Array, Symbol, } = primordials; const kCompare = Symbol('compare'); const kHeap = Symbol('heap'); const kSetPosition = Symbol('setPosition'); const kSize = Symbol('size'); // 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 { constructor(comparator, setPosition) { if (comparator !== undefined) this[kCompare] = comparator; if (setPosition !== undefined) this[kSetPosition] = setPosition; this[kHeap] = new Array(64); this[kSize] = 0; } [kCompare](a, b) { return a - b; } insert(value) { const heap = this[kHeap]; const pos = ++this[kSize]; heap[pos] = value; if (heap.length === pos) heap.length *= 2; this.percolateUp(pos); } peek() { return this[kHeap][1]; } percolateDown(pos) { const compare = this[kCompare]; const setPosition = this[kSetPosition]; const heap = this[kHeap]; const size = this[kSize]; 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[kHeap]; const compare = this[kCompare]; const setPosition = this[kSetPosition]; 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[kHeap]; const size = --this[kSize]; heap[pos] = heap[size + 1]; heap[size + 1] = undefined; if (size > 0 && pos <= size) { if (pos > 1 && this[kCompare](heap[pos / 2 | 0], heap[pos]) > 0) this.percolateUp(pos); else this.percolateDown(pos); } } remove(value) { const heap = this[kHeap]; const pos = heap.indexOf(value); if (pos < 1) return false; this.removeAt(pos); return true; } shift() { const heap = this[kHeap]; const value = heap[1]; if (value === undefined) return; this.removeAt(1); return value; } };