pop-swap
Version:
Range content change operator for arrays and array-like objects
106 lines (97 loc) • 3.53 kB
JavaScript
;
// 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;
}