mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-10 02:47:50 +00:00
Replace cachedContains with createCache and further optimize linear array searches.
Former-commit-id: bfe905985c9125cbadfcf111ffd97b6f8ecdd58d
This commit is contained in:
112
lodash.js
112
lodash.js
@@ -33,7 +33,7 @@
|
|||||||
var keyPrefix = +new Date + '';
|
var keyPrefix = +new Date + '';
|
||||||
|
|
||||||
/** Used as the size when optimizations are enabled for large arrays */
|
/** Used as the size when optimizations are enabled for large arrays */
|
||||||
var largeArraySize = 200;
|
var largeArraySize = 75;
|
||||||
|
|
||||||
/** Used to match empty string literals in compiled template source */
|
/** Used to match empty string literals in compiled template source */
|
||||||
var reEmptyStringLeading = /\b__p \+= '';/g,
|
var reEmptyStringLeading = /\b__p \+= '';/g,
|
||||||
@@ -662,26 +662,72 @@
|
|||||||
* @param {Mixed} value The value to search for.
|
* @param {Mixed} value The value to search for.
|
||||||
* @returns {Boolean} Returns `true`, if `value` is found, else `false`.
|
* @returns {Boolean} Returns `true`, if `value` is found, else `false`.
|
||||||
*/
|
*/
|
||||||
function cachedContains(array) {
|
function createCache(array) {
|
||||||
var length = array.length,
|
var bailout,
|
||||||
isLarge = length >= largeArraySize;
|
index = -1,
|
||||||
|
length = array.length,
|
||||||
|
isLarge = length >= largeArraySize,
|
||||||
|
objCache = {};
|
||||||
|
|
||||||
if (isLarge) {
|
var caches = {
|
||||||
var cache = {},
|
'false': false,
|
||||||
index = -1;
|
'function': false,
|
||||||
|
'null': false,
|
||||||
|
'number': {},
|
||||||
|
'object': objCache,
|
||||||
|
'string': {},
|
||||||
|
'true': false,
|
||||||
|
'undefined': false
|
||||||
|
};
|
||||||
|
|
||||||
while (++index < length) {
|
function cacheContains(value) {
|
||||||
var key = keyPrefix + array[index];
|
var type = typeof value;
|
||||||
(cache[key] || (cache[key] = [])).push(array[index]);
|
if (type == 'boolean' || value == null) {
|
||||||
|
return caches[value];
|
||||||
|
}
|
||||||
|
var cache = caches[type] || (type = 'object', objCache),
|
||||||
|
key = type == 'number' ? value : keyPrefix + value;
|
||||||
|
|
||||||
|
return type == 'object'
|
||||||
|
? (cache[key] ? indexOf(cache[key], value) > -1 : false)
|
||||||
|
: !!cache[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
function cachePush(value) {
|
||||||
|
var type = typeof value;
|
||||||
|
if (type == 'boolean' || value == null) {
|
||||||
|
caches[value] = true;
|
||||||
|
} else {
|
||||||
|
var cache = caches[type] || (type = 'object', objCache),
|
||||||
|
key = type == 'number' ? value : keyPrefix + value;
|
||||||
|
|
||||||
|
if (type == 'object') {
|
||||||
|
bailout = (cache[key] || (cache[key] = [])).push(value) == length;
|
||||||
|
} else {
|
||||||
|
cache[key] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return function(value) {
|
|
||||||
if (isLarge) {
|
function simpleContains(value) {
|
||||||
var key = keyPrefix + value;
|
|
||||||
return cache[key] && indexOf(cache[key], value) > -1;
|
|
||||||
}
|
|
||||||
return indexOf(array, value) > -1;
|
return indexOf(array, value) > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function simplePush(value) {
|
||||||
|
array.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLarge) {
|
||||||
|
while (++index < length) {
|
||||||
|
cachePush(array[index]);
|
||||||
|
}
|
||||||
|
if (bailout) {
|
||||||
|
isLarge = caches = objCache = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isLarge
|
||||||
|
? { 'contains': cacheContains, 'push': cachePush }
|
||||||
|
: { 'push': simplePush, 'contains' : simpleContains };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3441,7 +3487,7 @@
|
|||||||
var index = -1,
|
var index = -1,
|
||||||
length = array ? array.length : 0,
|
length = array ? array.length : 0,
|
||||||
flattened = concat.apply(arrayProto, nativeSlice.call(arguments, 1)),
|
flattened = concat.apply(arrayProto, nativeSlice.call(arguments, 1)),
|
||||||
contains = cachedContains(flattened),
|
contains = createCache(flattened).contains,
|
||||||
result = [];
|
result = [];
|
||||||
|
|
||||||
while (++index < length) {
|
while (++index < length) {
|
||||||
@@ -3769,29 +3815,21 @@
|
|||||||
function intersection(array) {
|
function intersection(array) {
|
||||||
var args = arguments,
|
var args = arguments,
|
||||||
argsLength = args.length,
|
argsLength = args.length,
|
||||||
cache = { '0': {} },
|
cache = createCache([]),
|
||||||
|
caches = {},
|
||||||
index = -1,
|
index = -1,
|
||||||
length = array ? array.length : 0,
|
length = array ? array.length : 0,
|
||||||
isLarge = length >= largeArraySize,
|
isLarge = length >= largeArraySize,
|
||||||
result = [],
|
result = [];
|
||||||
seen = result;
|
|
||||||
|
|
||||||
outer:
|
outer:
|
||||||
while (++index < length) {
|
while (++index < length) {
|
||||||
var value = array[index];
|
var value = array[index];
|
||||||
if (isLarge) {
|
if (!cache.contains(value)) {
|
||||||
var key = keyPrefix + value;
|
|
||||||
var inited = cache[0][key]
|
|
||||||
? !(seen = cache[0][key])
|
|
||||||
: (seen = cache[0][key] = []);
|
|
||||||
}
|
|
||||||
if (inited || indexOf(seen, value) < 0) {
|
|
||||||
if (isLarge) {
|
|
||||||
seen.push(value);
|
|
||||||
}
|
|
||||||
var argsIndex = argsLength;
|
var argsIndex = argsLength;
|
||||||
|
cache.push(value);
|
||||||
while (--argsIndex) {
|
while (--argsIndex) {
|
||||||
if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex])))(value)) {
|
if (!(caches[argsIndex] || (caches[argsIndex] = createCache(args[argsIndex]).contains))(value)) {
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4179,26 +4217,20 @@
|
|||||||
}
|
}
|
||||||
// init value cache for large arrays
|
// init value cache for large arrays
|
||||||
var isLarge = !isSorted && length >= largeArraySize;
|
var isLarge = !isSorted && length >= largeArraySize;
|
||||||
if (isLarge) {
|
|
||||||
var cache = {};
|
|
||||||
}
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
seen = [];
|
seen = [];
|
||||||
callback = lodash.createCallback(callback, thisArg);
|
callback = lodash.createCallback(callback, thisArg);
|
||||||
}
|
}
|
||||||
|
if (isLarge) {
|
||||||
|
seen = createCache([]);
|
||||||
|
}
|
||||||
while (++index < length) {
|
while (++index < length) {
|
||||||
var value = array[index],
|
var value = array[index],
|
||||||
computed = callback ? callback(value, index, array) : value;
|
computed = callback ? callback(value, index, array) : value;
|
||||||
|
|
||||||
if (isLarge) {
|
|
||||||
var key = keyPrefix + computed;
|
|
||||||
var inited = cache[key]
|
|
||||||
? !(seen = cache[key])
|
|
||||||
: (seen = cache[key] = []);
|
|
||||||
}
|
|
||||||
if (isSorted
|
if (isSorted
|
||||||
? !index || seen[seen.length - 1] !== computed
|
? !index || seen[seen.length - 1] !== computed
|
||||||
: inited || indexOf(seen, computed) < 0
|
: (isLarge ? !seen.contains(computed) : indexOf(seen, computed) < 0)
|
||||||
) {
|
) {
|
||||||
if (callback || isLarge) {
|
if (callback || isLarge) {
|
||||||
seen.push(computed);
|
seen.push(computed);
|
||||||
|
|||||||
52
perf/perf.js
52
perf/perf.js
@@ -775,6 +775,18 @@
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
suites.push(
|
||||||
|
Benchmark.Suite('`_.difference` iterating 75 elements')
|
||||||
|
.add(buildName, {
|
||||||
|
'fn': 'lodash.difference(seventyFiveValues, seventyFiveValues2)',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
.add(otherName, {
|
||||||
|
'fn': '_.difference(seventyFiveValues, seventyFiveValues2)',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
suites.push(
|
suites.push(
|
||||||
Benchmark.Suite('`_.difference` iterating 200 elements')
|
Benchmark.Suite('`_.difference` iterating 200 elements')
|
||||||
.add(buildName, {
|
.add(buildName, {
|
||||||
@@ -1076,6 +1088,18 @@
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
suites.push(
|
||||||
|
Benchmark.Suite('`_.intersection` iterating 75 elements')
|
||||||
|
.add(buildName, {
|
||||||
|
'fn': 'lodash.intersection(seventyFiveValues, seventyFiveValues2)',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
.add(otherName, {
|
||||||
|
'fn': '_.intersection(seventyFiveValues, seventyFiveValues2)',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
suites.push(
|
suites.push(
|
||||||
Benchmark.Suite('`_.intersection` iterating 200 elements')
|
Benchmark.Suite('`_.intersection` iterating 200 elements')
|
||||||
.add(buildName, {
|
.add(buildName, {
|
||||||
@@ -1731,11 +1755,23 @@
|
|||||||
suites.push(
|
suites.push(
|
||||||
Benchmark.Suite('`_.union` iterating an array of 75 elements')
|
Benchmark.Suite('`_.union` iterating an array of 75 elements')
|
||||||
.add(buildName, {
|
.add(buildName, {
|
||||||
'fn': 'lodash.union(fiftyValues, twentyFiveValues2)',
|
'fn': 'lodash.union(twentyFiveValues, fiftyValues2)',
|
||||||
'teardown': 'function multiArrays(){}'
|
'teardown': 'function multiArrays(){}'
|
||||||
})
|
})
|
||||||
.add(otherName, {
|
.add(otherName, {
|
||||||
'fn': '_.union(fiftyValues, twentyFiveValues2)',
|
'fn': '_.union(twentyFiveValues, fiftyValues2)',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
suites.push(
|
||||||
|
Benchmark.Suite('`_.union` iterating an array of 200 elements')
|
||||||
|
.add(buildName, {
|
||||||
|
'fn': 'lodash.union(oneHundredValues, oneHundredValues2)',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
.add(otherName, {
|
||||||
|
'fn': '_.union(oneHundredValues, oneHundredValues2)',
|
||||||
'teardown': 'function multiArrays(){}'
|
'teardown': 'function multiArrays(){}'
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -1766,6 +1802,18 @@
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
suites.push(
|
||||||
|
Benchmark.Suite('`_.uniq` iterating an array of 75 elements')
|
||||||
|
.add(buildName, {
|
||||||
|
'fn': 'lodash.uniq(twentyFiveValues.concat(fiftyValues2))',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
.add(otherName, {
|
||||||
|
'fn': '_.uniq(twentyFiveValues.concat(fiftyValues2))',
|
||||||
|
'teardown': 'function multiArrays(){}'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
suites.push(
|
suites.push(
|
||||||
Benchmark.Suite('`_.uniq` iterating an array of 200 elements')
|
Benchmark.Suite('`_.uniq` iterating an array of 200 elements')
|
||||||
.add(buildName, {
|
.add(buildName, {
|
||||||
|
|||||||
Reference in New Issue
Block a user