Source code

Revision control

Copy as Markdown

Other Tools

/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
"use strict";
class Insertion {
constructor(index, element)
{
this._index = index;
this._element = element;
}
get index() { return this._index; }
get element() { return this._element; }
lessThan(other)
{
return this._index < other._index;
}
}
class InsertionSet {
constructor()
{
this._insertions = []
}
appendInsertion(insertion)
{
this._insertions.push(insertion);
}
append(index, element)
{
this.appendInsertion(new Insertion(index, element));
}
execute(target)
{
// We bubble-sort because that's what the C++ code, and for the same reason as we do it:
// the stdlib doesn't have a stable sort and mergesort is slower in the common case of the
// array usually being sorted. This array is usually sorted.
bubbleSort(this._insertions, (a, b) => (a.lessThan(b)));
let numInsertions = this._insertions.length;
if (!numInsertions)
return 0;
let originalTargetSize = target.length;
target.length += numInsertions;
let lastIndex = target.length;
for (let indexInInsertions = numInsertions; indexInInsertions--;) {
let insertion = this._insertions[indexInInsertions];
if (indexInInsertions && insertion.index < this._insertions[indexInInsertions - 1].index)
throw new Error("Insertions out of order");
if (insertion.index > originalTargetSize)
throw new Error("Out-of-bounds insertion");
let firstIndex = insertion.index + indexInInsertions;
let indexOffset = indexInInsertions + 1;
for (let i = lastIndex; --i > firstIndex;)
target[i] = target[i - indexOffset];
target[firstIndex] = insertion.element;
lastIndex = firstIndex;
}
this._insertions = [];
return numInsertions;
}
}