UNPKG

pop-swap

Version:

Range content change operator for arrays and array-like objects

106 lines (97 loc) 3.53 kB
"use strict"; // Copyright (C) 2014 Montage Studio // https://github.com/montagejs/collections/blob/7c674d49c04955f01bbd2839f90936e15aceea2f/operators/swap.js var array_slice = Array.prototype.slice; module.exports = swap; function swap(array, start, minusLength, plus) { // Unrolled implementation into JavaScript for a couple reasons. // Calling splice can cause large stack sizes for large swaps. Also, // splice cannot handle array holes. if (plus) { if (!Array.isArray(plus)) { plus = array_slice.call(plus); } } else { plus = Array.empty; } if (start < 0) { start = array.length + start; } else if (start > array.length) { array.length = start; } if (start + minusLength > array.length) { // Truncate minus length if it extends beyond the length minusLength = array.length - start; } else if (minusLength < 0) { // It is the JavaScript way. minusLength = 0; } var diff = plus.length - minusLength; var oldLength = array.length; var newLength = array.length + diff; if (diff > 0) { // Head Tail Plus Minus // H H H H M M T T T T // H H H H P P P P T T T T // ^ start // ^-^ minus.length // ^ --> diff // ^-----^ plus.length // ^------^ tail before // ^------^ tail after // ^ start iteration // ^ start iteration offset // ^ end iteration // ^ end iteration offset // ^ start + minus.length // ^ length // ^ length - 1 for (var index = oldLength - 1; index >= start + minusLength; index--) { var offset = index + diff; if (index in array) { array[offset] = array[index]; } else { // Oddly, PhantomJS complains about deleting array // properties, unless you assign undefined first. array[offset] = void 0; delete array[offset]; } } } for (var index = 0; index < plus.length; index++) { if (index in plus) { array[start + index] = plus[index]; } else { array[start + index] = void 0; delete array[start + index]; } } if (diff < 0) { // Head Tail Plus Minus // H H H H M M M M T T T T // H H H H P P T T T T // ^ start // ^-----^ length // ^-^ plus.length // ^ start iteration // ^ offset start iteration // ^ end // ^ offset end // ^ start + minus.length - plus.length // ^ start - diff // ^------^ tail before // ^------^ tail after // ^ length - diff // ^ newLength for (var index = start + plus.length; index < oldLength - diff; index++) { var offset = index - diff; if (offset in array) { array[index] = array[offset]; } else { array[index] = void 0; delete array[index]; } } } array.length = newLength; }