/* * 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; } }