UNPKG

deadem

Version:

JavaScript (Node.js & Browsers) parser for Deadlock (Valve Source 2 Engine) demo/replay files

188 lines (151 loc) 3.99 kB
import Assert from './Assert.js'; class BinaryHeap { /** * @public * @constructor * @param {Function=} extractor * @param {Function=} comparator */ constructor(extractor, comparator) { Assert.isTrue(!extractor || typeof extractor === 'function'); Assert.isTrue(!comparator || typeof comparator === 'function'); this._extractor = extractor || (i => i); this._comparator = comparator || BinaryHeap.MIN_HEAP_COMPARATOR; this._heap = [ ]; } /** * @public * @static * @returns {function(number, number): boolean} */ static get MAX_HEAP_COMPARATOR() { return (a, b) => a < b; } /** * @public * @static * @returns {function(number, number): boolean} */ static get MIN_HEAP_COMPARATOR() { return (a, b) => a > b; } /** * @public * @returns {number} */ get length() { return this._heap.length; } /** * @public * @returns {*} */ get root() { return this._heap[0]; } /** * @public * @returns {*} */ extract() { if (this._heap.length === 0) { return; } const element = this._heap[0]; const last = this._heap.pop(); if (this._heap.length !== 0) { this._heap[0] = last; this._siftDown(0); } return element; } /** * @public * @param {*} element */ insert(element) { const length = this._heap.push(element); this._siftUp(length - 1); } /** * @protected * @param {number} i * @returns {number} */ _getIChildLeft(i) { return i * 2 + 1; } /** * @protected * @param {number} i * @returns {number} */ _getIChildRight(i) { return i * 2 + 2; } /** * @protected * @param {number} i * @returns {number} */ _getIParent(i) { return Math.floor((i - 1) / 2); } /** * @protected * @param {number} i * @returns {*} */ _getValue(i) { Assert.isTrue(Number.isInteger(i) && i >= 0 && i < this._heap.length); return this._extractor(this._heap[i]); } /** * @protected * @param {number} i */ _siftUp(i) { Assert.isTrue(Number.isInteger(i) && i >= 0 && i < this._heap.length); let index = i; while (index > 0 && this._comparator(this._getValue(this._getIParent(index)), this._getValue(index))) { this._swap(this._getIParent(index), index); index = this._getIParent(index); } } /** * @protected * @param {number} i */ _siftDown(i) { Assert.isTrue(Number.isInteger(i) && i >= 0 && i < this._heap.length); let iTarget = i; while (this._getIChildLeft(iTarget) < this._heap.length) { const iChildLeft = this._getIChildLeft(iTarget); const iChildRight = this._getIChildRight(iTarget); let iCandidate; if (iChildRight < this._heap.length && this._comparator(this._getValue(iChildLeft), this._getValue(iChildRight))) { iCandidate = iChildRight; } else { iCandidate = iChildLeft; } if (!this._comparator(this._getValue(iTarget), this._getValue(iCandidate))) { break; } this._swap(iTarget, iCandidate); iTarget = iCandidate; } } /** * @protected * @param {number} i * @param {number} j */ _swap(i, j) { Assert.isTrue(Number.isInteger(i) && i >= 0 && i < this._heap.length); Assert.isTrue(Number.isInteger(j) && j >= 0 && j < this._heap.length); const reference = this._heap[i]; this._heap[i] = this._heap[j]; this._heap[j] = reference; } } export default BinaryHeap;