mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
620 lines
25 KiB
JavaScript
620 lines
25 KiB
JavaScript
|
/* global describe, it */
|
||
|
|
||
|
var _ = require('underscore');
|
||
|
var assert = require('chai').assert;
|
||
|
var gutil = require('app/common/gutil');
|
||
|
var utils = require('../utils');
|
||
|
|
||
|
/**
|
||
|
* Set env ENABLE_TIMING_TESTS=1 to run the timing tests.
|
||
|
* These tests rely on mocha's reported timings to allow you to compare the performance of
|
||
|
* different implementations.
|
||
|
*/
|
||
|
var ENABLE_TIMING_TESTS = Boolean(process.env.ENABLE_TIMING_TESTS);
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
// Following recommendations such as here:
|
||
|
// http://stackoverflow.com/questions/7032550/javascript-insert-an-array-inside-another-array
|
||
|
// However, this won't work for large arrToInsert because .apply has a limit on length of args.
|
||
|
function spliceApplyConcat(target, start, arrToInsert) {
|
||
|
target.splice.apply(target, [start, 0].concat(arrToInsert));
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
// Seems like could be faster, but disturbingly mutates the last argument.
|
||
|
// However, this won't work for large arrToInsert because .apply has a limit on length of args.
|
||
|
function spliceApplyUnshift(target, start, arrToInsert) {
|
||
|
var spliceArgs = arrToInsert;
|
||
|
spliceArgs.unshift(start, 0);
|
||
|
try {
|
||
|
target.splice.apply(target, spliceArgs);
|
||
|
} finally {
|
||
|
spliceArgs.splice(0, 2);
|
||
|
}
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
// This is from the same stackoverflow answer, but builds a new array instead of mutating target.
|
||
|
function nonSpliceUsingSlice(target, start, arrToInsert) {
|
||
|
return target.slice(0, start).concat(arrToInsert, target.slice(start));
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
// A simple manual implementation, that performs reasonably well in all environments.
|
||
|
function spliceManualWithTailCopy(target, start, arrToInsert) {
|
||
|
var insLen = arrToInsert.length;
|
||
|
if (insLen === 1) {
|
||
|
target.splice(start, 0, arrToInsert[0]);
|
||
|
} else if (insLen > 1) {
|
||
|
var i, len, tail = target.slice(start);
|
||
|
for (i = 0; i < insLen; i++, start++) {
|
||
|
target[start] = arrToInsert[i];
|
||
|
}
|
||
|
for (i = 0, len = tail.length; i < len; i++, start++) {
|
||
|
target[start] = tail[i];
|
||
|
}
|
||
|
}
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
function spliceCopyWithTail(helpers) {
|
||
|
var copyForward = helpers.copyForward;
|
||
|
return function(target, start, arrToInsert) {
|
||
|
var tail = target.slice(start), insLen = arrToInsert.length;
|
||
|
copyForward(target, start, arrToInsert, 0, insLen);
|
||
|
copyForward(target, start + insLen, tail, 0, tail.length);
|
||
|
return target;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
// This implementation avoids creating a copy of the tail, but fills in the array
|
||
|
// non-contiguously.
|
||
|
function spliceFwdBackCopy(helpers) {
|
||
|
var copyForward = helpers.copyForward,
|
||
|
copyBackward = helpers.copyBackward;
|
||
|
return function(target, start, arrayToInsert) {
|
||
|
var count = arrayToInsert.length;
|
||
|
copyBackward(target, start + count, target, start, target.length - start);
|
||
|
copyForward(target, start, arrayToInsert, 0, count);
|
||
|
return target;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
// This implementation tries to be smarter by avoiding allocations, appending to the array
|
||
|
// contiguously, then filling in the gap.
|
||
|
function spliceAppendCopy(helpers) {
|
||
|
var appendFunc = helpers.append,
|
||
|
copyForward = helpers.copyForward,
|
||
|
copyBackward = helpers.copyBackward;
|
||
|
return function(target, start, arrToInsert) {
|
||
|
var origLen = target.length;
|
||
|
var tailLen = origLen - start;
|
||
|
var insLen = arrToInsert.length;
|
||
|
if (insLen > tailLen) {
|
||
|
appendFunc(target, arrToInsert, tailLen, insLen - tailLen);
|
||
|
appendFunc(target, target, start, tailLen);
|
||
|
copyForward(target, start, arrToInsert, 0, tailLen);
|
||
|
} else {
|
||
|
appendFunc(target, target, origLen - insLen, insLen);
|
||
|
copyBackward(target, start + insLen, target, start, tailLen - insLen);
|
||
|
copyForward(target, start, arrToInsert, 0, insLen);
|
||
|
}
|
||
|
return target;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
// This implementation only appends, but requires splicing out the tail from the original.
|
||
|
// It is consistently slower on Node.
|
||
|
function spliceAppendOnly(helpers) {
|
||
|
var appendFunc = helpers.append;
|
||
|
return function(target, start, arrToInsert) {
|
||
|
var tail = target.splice(start, target.length);
|
||
|
appendFunc(target, arrToInsert, 0, arrToInsert.length);
|
||
|
appendFunc(target, tail, 0, tail.length);
|
||
|
return target;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// COPY-FORWARD FUNCTIONS
|
||
|
//----------------------------------------------------------------------
|
||
|
var copyForward = {
|
||
|
gutil: gutil.arrayCopyForward,
|
||
|
|
||
|
copyForward1: function(toArray, toStart, fromArray, fromStart, count) {
|
||
|
for (var end = toStart + count; toStart < end; ++toStart, ++fromStart) {
|
||
|
toArray[toStart] = fromArray[fromStart];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
copyForward8: function(toArray, toStart, fromArray, fromStart, count) {
|
||
|
var end = toStart + count;
|
||
|
for (var xend = end - 7; toStart < xend; fromStart += 8, toStart += 8) {
|
||
|
toArray[toStart] = fromArray[fromStart];
|
||
|
toArray[toStart+1] = fromArray[fromStart+1];
|
||
|
toArray[toStart+2] = fromArray[fromStart+2];
|
||
|
toArray[toStart+3] = fromArray[fromStart+3];
|
||
|
toArray[toStart+4] = fromArray[fromStart+4];
|
||
|
toArray[toStart+5] = fromArray[fromStart+5];
|
||
|
toArray[toStart+6] = fromArray[fromStart+6];
|
||
|
toArray[toStart+7] = fromArray[fromStart+7];
|
||
|
}
|
||
|
for (; toStart < end; ++fromStart, ++toStart) {
|
||
|
toArray[toStart] = fromArray[fromStart];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
copyForward64: function(toArray, toStart, fromArray, fromStart, count) {
|
||
|
var end = toStart + count;
|
||
|
for (var xend = end - 63; toStart < xend; fromStart += 64, toStart += 64) {
|
||
|
toArray[toStart]=fromArray[fromStart]; toArray[toStart+1]=fromArray[fromStart+1];
|
||
|
toArray[toStart+2]=fromArray[fromStart+2]; toArray[toStart+3]=fromArray[fromStart+3];
|
||
|
toArray[toStart+4]=fromArray[fromStart+4]; toArray[toStart+5]=fromArray[fromStart+5];
|
||
|
toArray[toStart+6]=fromArray[fromStart+6]; toArray[toStart+7]=fromArray[fromStart+7];
|
||
|
toArray[toStart+8]=fromArray[fromStart+8]; toArray[toStart+9]=fromArray[fromStart+9];
|
||
|
toArray[toStart+10]=fromArray[fromStart+10]; toArray[toStart+11]=fromArray[fromStart+11];
|
||
|
toArray[toStart+12]=fromArray[fromStart+12]; toArray[toStart+13]=fromArray[fromStart+13];
|
||
|
toArray[toStart+14]=fromArray[fromStart+14]; toArray[toStart+15]=fromArray[fromStart+15];
|
||
|
toArray[toStart+16]=fromArray[fromStart+16]; toArray[toStart+17]=fromArray[fromStart+17];
|
||
|
toArray[toStart+18]=fromArray[fromStart+18]; toArray[toStart+19]=fromArray[fromStart+19];
|
||
|
toArray[toStart+20]=fromArray[fromStart+20]; toArray[toStart+21]=fromArray[fromStart+21];
|
||
|
toArray[toStart+22]=fromArray[fromStart+22]; toArray[toStart+23]=fromArray[fromStart+23];
|
||
|
toArray[toStart+24]=fromArray[fromStart+24]; toArray[toStart+25]=fromArray[fromStart+25];
|
||
|
toArray[toStart+26]=fromArray[fromStart+26]; toArray[toStart+27]=fromArray[fromStart+27];
|
||
|
toArray[toStart+28]=fromArray[fromStart+28]; toArray[toStart+29]=fromArray[fromStart+29];
|
||
|
toArray[toStart+30]=fromArray[fromStart+30]; toArray[toStart+31]=fromArray[fromStart+31];
|
||
|
toArray[toStart+32]=fromArray[fromStart+32]; toArray[toStart+33]=fromArray[fromStart+33];
|
||
|
toArray[toStart+34]=fromArray[fromStart+34]; toArray[toStart+35]=fromArray[fromStart+35];
|
||
|
toArray[toStart+36]=fromArray[fromStart+36]; toArray[toStart+37]=fromArray[fromStart+37];
|
||
|
toArray[toStart+38]=fromArray[fromStart+38]; toArray[toStart+39]=fromArray[fromStart+39];
|
||
|
toArray[toStart+40]=fromArray[fromStart+40]; toArray[toStart+41]=fromArray[fromStart+41];
|
||
|
toArray[toStart+42]=fromArray[fromStart+42]; toArray[toStart+43]=fromArray[fromStart+43];
|
||
|
toArray[toStart+44]=fromArray[fromStart+44]; toArray[toStart+45]=fromArray[fromStart+45];
|
||
|
toArray[toStart+46]=fromArray[fromStart+46]; toArray[toStart+47]=fromArray[fromStart+47];
|
||
|
toArray[toStart+48]=fromArray[fromStart+48]; toArray[toStart+49]=fromArray[fromStart+49];
|
||
|
toArray[toStart+50]=fromArray[fromStart+50]; toArray[toStart+51]=fromArray[fromStart+51];
|
||
|
toArray[toStart+52]=fromArray[fromStart+52]; toArray[toStart+53]=fromArray[fromStart+53];
|
||
|
toArray[toStart+54]=fromArray[fromStart+54]; toArray[toStart+55]=fromArray[fromStart+55];
|
||
|
toArray[toStart+56]=fromArray[fromStart+56]; toArray[toStart+57]=fromArray[fromStart+57];
|
||
|
toArray[toStart+58]=fromArray[fromStart+58]; toArray[toStart+59]=fromArray[fromStart+59];
|
||
|
toArray[toStart+60]=fromArray[fromStart+60]; toArray[toStart+61]=fromArray[fromStart+61];
|
||
|
toArray[toStart+62]=fromArray[fromStart+62]; toArray[toStart+63]=fromArray[fromStart+63];
|
||
|
}
|
||
|
for (; toStart < end; ++fromStart, ++toStart) {
|
||
|
toArray[toStart] = fromArray[fromStart];
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// COPY-BACKWARD FUNCTIONS
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
var copyBackward = {
|
||
|
gutil: gutil.arrayCopyBackward,
|
||
|
|
||
|
copyBackward1: function(toArray, toStart, fromArray, fromStart, count) {
|
||
|
for (var i = toStart + count - 1, j = fromStart + count - 1; i >= toStart; --i, --j) {
|
||
|
toArray[i] = fromArray[j];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
copyBackward8: function(toArray, toStart, fromArray, fromStart, count) {
|
||
|
var i = toStart + count - 1, j = fromStart + count - 1;
|
||
|
for (var xStart = toStart + 7; i >= xStart; i -= 8, j -= 8) {
|
||
|
toArray[i] = fromArray[j];
|
||
|
toArray[i-1] = fromArray[j-1];
|
||
|
toArray[i-2] = fromArray[j-2];
|
||
|
toArray[i-3] = fromArray[j-3];
|
||
|
toArray[i-4] = fromArray[j-4];
|
||
|
toArray[i-5] = fromArray[j-5];
|
||
|
toArray[i-6] = fromArray[j-6];
|
||
|
toArray[i-7] = fromArray[j-7];
|
||
|
}
|
||
|
for ( ; i >= toStart; --i, --j) {
|
||
|
toArray[i] = fromArray[j];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
copyBackward64: function(toArray, toStart, fromArray, fromStart, count) {
|
||
|
var i = toStart + count - 1, j = fromStart + count - 1;
|
||
|
for (var xStart = toStart + 63; i >= xStart; i -= 64, j -= 64) {
|
||
|
toArray[i]=fromArray[j]; toArray[i-1]=fromArray[j-1];
|
||
|
toArray[i-2]=fromArray[j-2]; toArray[i-3]=fromArray[j-3];
|
||
|
toArray[i-4]=fromArray[j-4]; toArray[i-5]=fromArray[j-5];
|
||
|
toArray[i-6]=fromArray[j-6]; toArray[i-7]=fromArray[j-7];
|
||
|
toArray[i-8]=fromArray[j-8]; toArray[i-9]=fromArray[j-9];
|
||
|
toArray[i-10]=fromArray[j-10]; toArray[i-11]=fromArray[j-11];
|
||
|
toArray[i-12]=fromArray[j-12]; toArray[i-13]=fromArray[j-13];
|
||
|
toArray[i-14]=fromArray[j-14]; toArray[i-15]=fromArray[j-15];
|
||
|
toArray[i-16]=fromArray[j-16]; toArray[i-17]=fromArray[j-17];
|
||
|
toArray[i-18]=fromArray[j-18]; toArray[i-19]=fromArray[j-19];
|
||
|
toArray[i-20]=fromArray[j-20]; toArray[i-21]=fromArray[j-21];
|
||
|
toArray[i-22]=fromArray[j-22]; toArray[i-23]=fromArray[j-23];
|
||
|
toArray[i-24]=fromArray[j-24]; toArray[i-25]=fromArray[j-25];
|
||
|
toArray[i-26]=fromArray[j-26]; toArray[i-27]=fromArray[j-27];
|
||
|
toArray[i-28]=fromArray[j-28]; toArray[i-29]=fromArray[j-29];
|
||
|
toArray[i-30]=fromArray[j-30]; toArray[i-31]=fromArray[j-31];
|
||
|
toArray[i-32]=fromArray[j-32]; toArray[i-33]=fromArray[j-33];
|
||
|
toArray[i-34]=fromArray[j-34]; toArray[i-35]=fromArray[j-35];
|
||
|
toArray[i-36]=fromArray[j-36]; toArray[i-37]=fromArray[j-37];
|
||
|
toArray[i-38]=fromArray[j-38]; toArray[i-39]=fromArray[j-39];
|
||
|
toArray[i-40]=fromArray[j-40]; toArray[i-41]=fromArray[j-41];
|
||
|
toArray[i-42]=fromArray[j-42]; toArray[i-43]=fromArray[j-43];
|
||
|
toArray[i-44]=fromArray[j-44]; toArray[i-45]=fromArray[j-45];
|
||
|
toArray[i-46]=fromArray[j-46]; toArray[i-47]=fromArray[j-47];
|
||
|
toArray[i-48]=fromArray[j-48]; toArray[i-49]=fromArray[j-49];
|
||
|
toArray[i-50]=fromArray[j-50]; toArray[i-51]=fromArray[j-51];
|
||
|
toArray[i-52]=fromArray[j-52]; toArray[i-53]=fromArray[j-53];
|
||
|
toArray[i-54]=fromArray[j-54]; toArray[i-55]=fromArray[j-55];
|
||
|
toArray[i-56]=fromArray[j-56]; toArray[i-57]=fromArray[j-57];
|
||
|
toArray[i-58]=fromArray[j-58]; toArray[i-59]=fromArray[j-59];
|
||
|
toArray[i-60]=fromArray[j-60]; toArray[i-61]=fromArray[j-61];
|
||
|
toArray[i-62]=fromArray[j-62]; toArray[i-63]=fromArray[j-63];
|
||
|
}
|
||
|
for ( ; i >= toStart; --i, --j) {
|
||
|
toArray[i] = fromArray[j];
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// APPEND FUNCTIONS.
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
var append = {
|
||
|
gutil: gutil.arrayAppend,
|
||
|
|
||
|
append1: function(toArray, fromArray, fromStart, count) {
|
||
|
var end = fromStart + count;
|
||
|
for (var i = fromStart; i < end; i++) {
|
||
|
toArray.push(fromArray[i]);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
appendCopy1: function(toArray, fromArray, fromStart, count) {
|
||
|
if (count === 1) {
|
||
|
toArray.push(fromArray[fromStart]);
|
||
|
} else if (count > 1) {
|
||
|
var len = toArray.length;
|
||
|
toArray.length = len + count;
|
||
|
copyForward.copyForward1(toArray, len, fromArray, fromStart, count);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
append8: function(toArray, fromArray, fromStart, count) {
|
||
|
var end = fromStart + count;
|
||
|
for (var xend = end - 7; fromStart < xend; fromStart += 8) {
|
||
|
toArray.push(
|
||
|
fromArray[fromStart],
|
||
|
fromArray[fromStart + 1],
|
||
|
fromArray[fromStart + 2],
|
||
|
fromArray[fromStart + 3],
|
||
|
fromArray[fromStart + 4],
|
||
|
fromArray[fromStart + 5],
|
||
|
fromArray[fromStart + 6],
|
||
|
fromArray[fromStart + 7]);
|
||
|
}
|
||
|
for ( ; fromStart < end; ++fromStart) {
|
||
|
toArray.push(fromArray[fromStart]);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
append64: function(toArray, fromArray, fromStart, count) {
|
||
|
var end = fromStart + count;
|
||
|
for (var xend = end - 63; fromStart < xend; fromStart += 64) {
|
||
|
toArray.push(
|
||
|
fromArray[fromStart], fromArray[fromStart + 1],
|
||
|
fromArray[fromStart + 2], fromArray[fromStart + 3],
|
||
|
fromArray[fromStart + 4], fromArray[fromStart + 5],
|
||
|
fromArray[fromStart + 6], fromArray[fromStart + 7],
|
||
|
fromArray[fromStart + 8], fromArray[fromStart + 9],
|
||
|
fromArray[fromStart + 10], fromArray[fromStart + 11],
|
||
|
fromArray[fromStart + 12], fromArray[fromStart + 13],
|
||
|
fromArray[fromStart + 14], fromArray[fromStart + 15],
|
||
|
fromArray[fromStart + 16], fromArray[fromStart + 17],
|
||
|
fromArray[fromStart + 18], fromArray[fromStart + 19],
|
||
|
fromArray[fromStart + 20], fromArray[fromStart + 21],
|
||
|
fromArray[fromStart + 22], fromArray[fromStart + 23],
|
||
|
fromArray[fromStart + 24], fromArray[fromStart + 25],
|
||
|
fromArray[fromStart + 26], fromArray[fromStart + 27],
|
||
|
fromArray[fromStart + 28], fromArray[fromStart + 29],
|
||
|
fromArray[fromStart + 30], fromArray[fromStart + 31],
|
||
|
fromArray[fromStart + 32], fromArray[fromStart + 33],
|
||
|
fromArray[fromStart + 34], fromArray[fromStart + 35],
|
||
|
fromArray[fromStart + 36], fromArray[fromStart + 37],
|
||
|
fromArray[fromStart + 38], fromArray[fromStart + 39],
|
||
|
fromArray[fromStart + 40], fromArray[fromStart + 41],
|
||
|
fromArray[fromStart + 42], fromArray[fromStart + 43],
|
||
|
fromArray[fromStart + 44], fromArray[fromStart + 45],
|
||
|
fromArray[fromStart + 46], fromArray[fromStart + 47],
|
||
|
fromArray[fromStart + 48], fromArray[fromStart + 49],
|
||
|
fromArray[fromStart + 50], fromArray[fromStart + 51],
|
||
|
fromArray[fromStart + 52], fromArray[fromStart + 53],
|
||
|
fromArray[fromStart + 54], fromArray[fromStart + 55],
|
||
|
fromArray[fromStart + 56], fromArray[fromStart + 57],
|
||
|
fromArray[fromStart + 58], fromArray[fromStart + 59],
|
||
|
fromArray[fromStart + 60], fromArray[fromStart + 61],
|
||
|
fromArray[fromStart + 62], fromArray[fromStart + 63]
|
||
|
);
|
||
|
}
|
||
|
for ( ; fromStart < end; ++fromStart) {
|
||
|
toArray.push(fromArray[fromStart]);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
appendSlice64: function(toArray, fromArray, fromStart, count) {
|
||
|
var end = fromStart + count;
|
||
|
for ( ; fromStart < end; fromStart += 64) {
|
||
|
Array.prototype.push.apply(toArray, fromArray.slice(fromStart, Math.min(fromStart + 64, end)));
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
var helpers1 = {
|
||
|
copyForward: copyForward.copyForward1,
|
||
|
copyBackward: copyBackward.copyBackward1,
|
||
|
append: append.append1,
|
||
|
};
|
||
|
|
||
|
var helpers8 = {
|
||
|
copyForward: copyForward.copyForward8,
|
||
|
copyBackward: copyBackward.copyBackward8,
|
||
|
append: append.append8,
|
||
|
};
|
||
|
|
||
|
var helpers64 = {
|
||
|
copyForward: copyForward.copyForward64,
|
||
|
copyBackward: copyBackward.copyBackward64,
|
||
|
append: append.append64,
|
||
|
};
|
||
|
|
||
|
var allArraySpliceFuncs = {
|
||
|
spliceApplyConcat: spliceApplyConcat,
|
||
|
spliceApplyUnshift: spliceApplyUnshift,
|
||
|
nonSpliceUsingSlice: nonSpliceUsingSlice,
|
||
|
|
||
|
spliceGutil: gutil.arraySplice,
|
||
|
spliceManualWithTailCopy: spliceManualWithTailCopy,
|
||
|
|
||
|
spliceCopyWithTail1: spliceCopyWithTail(helpers1),
|
||
|
spliceCopyWithTail8: spliceCopyWithTail(helpers8),
|
||
|
spliceCopyWithTail64: spliceCopyWithTail(helpers64),
|
||
|
|
||
|
spliceFwdBackCopy1: spliceFwdBackCopy(helpers1),
|
||
|
spliceFwdBackCopy8: spliceFwdBackCopy(helpers8),
|
||
|
spliceFwdBackCopy64: spliceFwdBackCopy(helpers64),
|
||
|
|
||
|
spliceAppendCopy1: spliceAppendCopy(helpers1),
|
||
|
spliceAppendCopy8: spliceAppendCopy(helpers8),
|
||
|
spliceAppendCopy64: spliceAppendCopy(helpers64),
|
||
|
|
||
|
spliceAppendOnly1: spliceAppendOnly(helpers1),
|
||
|
spliceAppendOnly8: spliceAppendOnly(helpers8),
|
||
|
spliceAppendOnly64: spliceAppendOnly(helpers64),
|
||
|
};
|
||
|
|
||
|
var timedArraySpliceFuncs = {
|
||
|
// The following two naive implementations cannot cope with large arrays, and raise
|
||
|
// "RangeError: Maximum call stack size exceeded".
|
||
|
|
||
|
//spliceApplyConcat: spliceApplyConcat,
|
||
|
//spliceApplyUnshift: spliceApplyUnshift,
|
||
|
|
||
|
// This isn't a real splice, it doesn't modify the array.
|
||
|
//nonSpliceUsingSlice: nonSpliceUsingSlice,
|
||
|
|
||
|
// The implementations commented out below are the slower ones.
|
||
|
spliceGutil: gutil.arraySplice,
|
||
|
spliceManualWithTailCopy: spliceManualWithTailCopy,
|
||
|
|
||
|
spliceCopyWithTail1: spliceCopyWithTail(helpers1),
|
||
|
//spliceCopyWithTail8: spliceCopyWithTail(helpers8),
|
||
|
//spliceCopyWithTail64: spliceCopyWithTail(helpers64),
|
||
|
|
||
|
//spliceFwdBackCopy1: spliceFwdBackCopy(helpers1),
|
||
|
//spliceFwdBackCopy8: spliceFwdBackCopy(helpers8),
|
||
|
//spliceFwdBackCopy64: spliceFwdBackCopy(helpers64),
|
||
|
|
||
|
spliceAppendCopy1: spliceAppendCopy(helpers1),
|
||
|
spliceAppendCopy8: spliceAppendCopy(helpers8),
|
||
|
spliceAppendCopy64: spliceAppendCopy(helpers64),
|
||
|
|
||
|
//spliceAppendOnly1: spliceAppendOnly(helpers1),
|
||
|
//spliceAppendOnly8: spliceAppendOnly(helpers8),
|
||
|
//spliceAppendOnly64: spliceAppendOnly(helpers64),
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
describe("array copy functions", function() {
|
||
|
it("copyForward should copy correctly", function() {
|
||
|
_.each(copyForward, function(copyFunc, name) {
|
||
|
var data = _.range(10000);
|
||
|
copyFunc(data, 0, data, 1, 9999);
|
||
|
copyFunc(data, 0, data, 1, 9999);
|
||
|
assert.equal(data[0], 2);
|
||
|
assert.equal(data[1], 3);
|
||
|
assert.equal(data[9996], 9998);
|
||
|
assert.equal(data[9997], 9999);
|
||
|
assert.equal(data[9998], 9999);
|
||
|
assert.equal(data[9999], 9999);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it("copyBackward should copy correctly", function() {
|
||
|
_.each(copyBackward, function(copyFunc, name) {
|
||
|
var data = _.range(10000);
|
||
|
copyFunc(data, 1, data, 0, 9999);
|
||
|
copyFunc(data, 1, data, 0, 9999);
|
||
|
assert.equal(data[0], 0);
|
||
|
assert.equal(data[1], 0);
|
||
|
assert.equal(data[2], 0);
|
||
|
assert.equal(data[3], 1);
|
||
|
assert.equal(data[9998], 9996);
|
||
|
assert.equal(data[9999], 9997);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it("arrayAppend should append correctly", function() {
|
||
|
_.each(append, function(appendFunc, name) {
|
||
|
var out = [];
|
||
|
var data = _.range(20000);
|
||
|
appendFunc(out, data, 100, 1);
|
||
|
appendFunc(out, data, 100, 1000);
|
||
|
appendFunc(out, data, 100, 10000);
|
||
|
assert.deepEqual(out.slice(0, 4), [100, 100, 101, 102]);
|
||
|
assert.deepEqual(out.slice(1000, 1004), [1099, 100, 101, 102]);
|
||
|
assert.deepEqual(out.slice(11000), [10099]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// See ENABLE_TIMING_TESTS flag on top of this file.
|
||
|
if (ENABLE_TIMING_TESTS) {
|
||
|
describe("timing", function() {
|
||
|
var a1m = _.range(1000000);
|
||
|
describe("copyForward", function() {
|
||
|
var reps = 40;
|
||
|
_.each(copyForward, function(copyFunc, name) {
|
||
|
var b1m = a1m.slice(0);
|
||
|
it(name, function() {
|
||
|
utils.repeat(reps, copyFunc, b1m, 0, b1m, 1, 999999);
|
||
|
|
||
|
// Make sure it actually worked. These checks shouldn't affect timings much.
|
||
|
assert.deepEqual(b1m.slice(0, 10), _.range(reps, reps + 10));
|
||
|
assert.equal(b1m[999999-reps-1], 999998);
|
||
|
assert.equal(b1m[999999-reps], 999999);
|
||
|
assert.deepEqual(b1m.slice(1000000-reps), _.times(reps, _.constant(999999)));
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("copyBackward", function() {
|
||
|
var reps = 40;
|
||
|
_.each(copyBackward, function(copyFunc, name) {
|
||
|
var b1m = a1m.slice(0);
|
||
|
it(name, function() {
|
||
|
utils.repeat(reps, copyFunc, b1m, 1, b1m, 0, 999999);
|
||
|
|
||
|
// Make sure it actually worked. These checks shouldn't affect timings much.
|
||
|
assert.deepEqual(b1m.slice(0, reps), _.times(reps, _.constant(0)));
|
||
|
assert.equal(b1m[reps], 0);
|
||
|
assert.equal(b1m[reps + 1], 1);
|
||
|
assert.deepEqual(b1m.slice(999990), _.range(999990-reps, 1000000-reps));
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("append", function() {
|
||
|
var data = _.range(1000000);
|
||
|
function chunkedAppend(appendFunc, data, chunk) {
|
||
|
var out = [];
|
||
|
var count = data.length / chunk;
|
||
|
for (var i = 0; i < count; i++) {
|
||
|
appendFunc(out, data, i * chunk, chunk);
|
||
|
}
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
_.each(append, function(appendFunc, name) {
|
||
|
it(name, function() {
|
||
|
var out1 = chunkedAppend(appendFunc, data, 1);
|
||
|
var out2 = chunkedAppend(appendFunc, data, 1000);
|
||
|
var out3 = chunkedAppend(appendFunc, data, 1000000);
|
||
|
|
||
|
// Make sure it actually worked. Keep the checks short to avoid affecting timings.
|
||
|
assert.deepEqual(out1.slice(0, 10), data.slice(0, 10));
|
||
|
assert.deepEqual(out1.slice(data.length - 10), data.slice(data.length - 10));
|
||
|
assert.deepEqual(out2.slice(0, 10), data.slice(0, 10));
|
||
|
assert.deepEqual(out2.slice(data.length - 10), data.slice(data.length - 10));
|
||
|
assert.deepEqual(out3.slice(0, 10), data.slice(0, 10));
|
||
|
assert.deepEqual(out3.slice(data.length - 10), data.slice(data.length - 10));
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('arraySplice', function() {
|
||
|
|
||
|
// Make sure all our functions produce the same results as spliceApplyConcat for simple cases.
|
||
|
var refSpliceFunc = spliceApplyConcat;
|
||
|
|
||
|
it("all candidate functions should be correct for simpler cases", function() {
|
||
|
_.each(allArraySpliceFuncs, function(spliceFunc, name) {
|
||
|
var a10 = _.range(10), a100 = _.range(100);
|
||
|
function checkSpliceFunc(target, start, arrToInsert) {
|
||
|
assert.deepEqual(spliceFunc(target.slice(0), start, arrToInsert),
|
||
|
refSpliceFunc(target.slice(0), start, arrToInsert),
|
||
|
"splice function incorrect for " + name);
|
||
|
}
|
||
|
|
||
|
checkSpliceFunc(a10, 5, a100);
|
||
|
checkSpliceFunc(a100, 50, a10);
|
||
|
checkSpliceFunc(a100, 90, a10);
|
||
|
checkSpliceFunc(a100, 0, a10);
|
||
|
checkSpliceFunc(a100, 100, a10);
|
||
|
checkSpliceFunc(a10, 0, a100);
|
||
|
checkSpliceFunc(a10, 10, a100);
|
||
|
checkSpliceFunc(a10, 1, a10);
|
||
|
checkSpliceFunc(a10, 5, a10);
|
||
|
checkSpliceFunc(a10, 5, []);
|
||
|
assert.deepEqual(spliceFunc(a10.slice(0), 5, a10),
|
||
|
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 5, 6, 7, 8, 9]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// See ENABLE_TIMING_TESTS flag on top of this file.
|
||
|
if (ENABLE_TIMING_TESTS) {
|
||
|
describe("timing", function() {
|
||
|
var a1 = _.range(1);
|
||
|
var a1k = _.range(1000);
|
||
|
var a1m = _.range(1000000);
|
||
|
|
||
|
describe("insert-one", function() {
|
||
|
_.each(timedArraySpliceFuncs, function(spliceFunc, name) {
|
||
|
var b1m = a1m.slice(0);
|
||
|
it(name, function() {
|
||
|
utils.repeat(40, spliceFunc, b1m, 500000, a1);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("insert-1k", function() {
|
||
|
_.each(timedArraySpliceFuncs, function(spliceFunc, name) {
|
||
|
var b1m = a1m.slice(0);
|
||
|
it(name, function() {
|
||
|
utils.repeat(40, spliceFunc, b1m, 500000, a1k);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("insert-1m", function() {
|
||
|
_.each(timedArraySpliceFuncs, function(spliceFunc, name) {
|
||
|
var b1m = a1m.slice(0);
|
||
|
it(name, function() {
|
||
|
utils.repeat(4, spliceFunc, b1m, 500000, a1m);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
});
|