function()

in MotionMark/resources/extensions.js [487:607]


    function(maxSize, compare)
    {
        this._maxSize = maxSize;
        this._compare = compare;
        this._size = 0;
        this._values = new Array(this._maxSize);
    }, {

    // This is a binary heap represented in an array. The root element is stored
    // in the first element in the array. The root is followed by its two children.
    // Then its four grandchildren and so on. So every level in the binary heap is
    // doubled in the following level. Here is an example of the node indices and
    // how they are related to their parents and children.
    // ===========================================================================
    //              0       1       2       3       4       5       6
    // PARENT       -1      0       0       1       1       2       2
    // LEFT         1       3       5       7       9       11      13
    // RIGHT        2       4       6       8       10      12      14
    // ===========================================================================
    _parentIndex: function(i)
    {
        return i > 0 ? Math.floor((i - 1) / 2) : -1;
    },

    _leftIndex: function(i)
    {
        var leftIndex = i * 2 + 1;
        return leftIndex < this._size ? leftIndex : -1;
    },

    _rightIndex: function(i)
    {
        var rightIndex = i * 2 + 2;
        return rightIndex < this._size ? rightIndex : -1;
    },

    // Return the child index that may violate the heap property at index i.
    _childIndex: function(i)
    {
        var left = this._leftIndex(i);
        var right = this._rightIndex(i);

        if (left != -1 && right != -1)
            return this._compare(this._values[left], this._values[right]) > 0 ? left : right;

        return left != -1 ? left : right;
    },

    init: function()
    {
        this._size = 0;
    },

    top: function()
    {
        return this._size ? this._values[0] : NaN;
    },

    push: function(value)
    {
        if (this._size == this._maxSize) {
            // If size is bounded and the new value can be a parent of the top()
            // if the size were unbounded, just ignore the new value.
            if (this._compare(value, this.top()) > 0)
                return;
            this.pop();
        }
        this._values[this._size++] = value;
        this._bubble(this._size - 1);
    },

    pop: function()
    {
        if (!this._size)
            return NaN;

        this._values[0] = this._values[--this._size];
        this._sink(0);
    },

    _bubble: function(i)
    {
        // Fix the heap property at index i given that parent is the only node that
        // may violate the heap property.
        for (var pi = this._parentIndex(i); pi != -1; i = pi, pi = this._parentIndex(pi)) {
            if (this._compare(this._values[pi], this._values[i]) > 0)
                break;

            this._values.swap(pi, i);
        }
    },

    _sink: function(i)
    {
        // Fix the heap property at index i given that each of the left and the right
        // sub-trees satisfies the heap property.
        for (var ci = this._childIndex(i); ci != -1; i = ci, ci = this._childIndex(ci)) {
            if (this._compare(this._values[i], this._values[ci]) > 0)
                break;

            this._values.swap(ci, i);
        }
    },

    str: function()
    {
        var out = "Heap[" + this._size + "] = [";
        for (var i = 0; i < this._size; ++i) {
            out += this._values[i];
            if (i < this._size - 1)
                out += ", ";
        }
        return out + "]";
    },

    values: function(size) {
        // Return the last "size" heap elements values.
        var values = this._values.slice(0, this._size);
        return values.sort(this._compare).slice(0, Math.min(size, this._size));
    }
});