// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
/** This module is browser compatible. */ import { descend } from "./_comparators.ts";
export * from "./_comparators.ts";
/** Swaps the values at two indexes in an array. */ function swap(array, a, b) {
    const temp = array[a];
    array[a] = array[b];
    array[b] = temp;
}
/** Returns the parent index for a child index. */ function getParentIndex(index) {
    return Math.floor((index + 1) / 2) - 1;
}
/**
 * A priority queue implemented with a binary heap. The heap is in decending order by default,
 * using JavaScript's built in comparison operators to sort the values.
 */ export class BinaryHeap {
    #data;
    constructor(compare = descend){
        this.compare = compare;
        this.#data = [];
    }
    static from(collection, options) {
        let result;
        let unmappedValues = [];
        if (collection instanceof BinaryHeap) {
            result = new BinaryHeap(options?.compare ?? collection.compare);
            if (options?.compare || options?.map) {
                unmappedValues = collection.#data;
            } else {
                result.#data = Array.from(collection.#data);
            }
        } else {
            result = options?.compare ? new BinaryHeap(options.compare) : new BinaryHeap();
            unmappedValues = collection;
        }
        const values = options?.map ? Array.from(unmappedValues, options.map, options.thisArg) : unmappedValues;
        result.push(...values);
        return result;
    }
    /** The amount of values stored in the binary heap. */ get length() {
        return this.#data.length;
    }
    /** Returns the greatest value in the binary heap, or undefined if it is empty. */ peek() {
        return this.#data[0];
    }
    /** Removes the greatest value from the binary heap and returns it, or null if it is empty. */ pop() {
        const size = this.#data.length - 1;
        swap(this.#data, 0, size);
        let parent = 0;
        let right = 2 * (parent + 1);
        let left = right - 1;
        while(left < size){
            const greatestChild = right === size || this.compare(this.#data[left], this.#data[right]) <= 0 ? left : right;
            if (this.compare(this.#data[greatestChild], this.#data[parent]) < 0) {
                swap(this.#data, parent, greatestChild);
                parent = greatestChild;
            } else {
                break;
            }
            right = 2 * (parent + 1);
            left = right - 1;
        }
        return this.#data.pop();
    }
    /** Adds values to the binary heap. */ push(...values) {
        for (const value of values){
            let index = this.#data.length;
            let parent = getParentIndex(index);
            this.#data.push(value);
            while(index !== 0 && this.compare(this.#data[index], this.#data[parent]) < 0){
                swap(this.#data, parent, index);
                index = parent;
                parent = getParentIndex(index);
            }
        }
        return this.#data.length;
    }
    /** Removes all values from the binary heap. */ clear() {
        this.#data = [];
    }
    /** Checks if the binary heap is empty. */ isEmpty() {
        return this.#data.length === 0;
    }
    /** Returns an iterator for retrieving and removing values from the binary heap. */ *drain() {
        while(!this.isEmpty()){
            yield this.pop();
        }
    }
    *[Symbol.iterator]() {
        yield* this.drain();
    }
    compare;
}
//# sourceMappingURL=data:application/json;base64,[encoded data, 10732 characters]