mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-09 02:17:50 +00:00
Refactor lazy evaluation.
This commit is contained in:
278
lodash.js
278
lodash.js
@@ -31,6 +31,10 @@
|
|||||||
var HOT_COUNT = 150,
|
var HOT_COUNT = 150,
|
||||||
HOT_SPAN = 16;
|
HOT_SPAN = 16;
|
||||||
|
|
||||||
|
var LAZY_FILTER_FLAG = 1,
|
||||||
|
LAZY_MAP_FLAG = 2,
|
||||||
|
LAZY_WHILE_FLAG = 3;
|
||||||
|
|
||||||
/** Used as the TypeError message for "Functions" methods */
|
/** Used as the TypeError message for "Functions" methods */
|
||||||
var FUNC_ERROR_TEXT = 'Expected a function';
|
var FUNC_ERROR_TEXT = 'Expected a function';
|
||||||
|
|
||||||
@@ -4640,8 +4644,8 @@
|
|||||||
*/
|
*/
|
||||||
function wrapperValueOf() {
|
function wrapperValueOf() {
|
||||||
var result = this.__wrapped__;
|
var result = this.__wrapped__;
|
||||||
if (result instanceof lazyWrapper) {
|
if (result instanceof LazyWrapper) {
|
||||||
return result.value();
|
result = result.value();
|
||||||
}
|
}
|
||||||
var index = -1,
|
var index = -1,
|
||||||
queue = this.__queue__,
|
queue = this.__queue__,
|
||||||
@@ -4650,148 +4654,118 @@
|
|||||||
while (++index < length) {
|
while (++index < length) {
|
||||||
var args = [result],
|
var args = [result],
|
||||||
data = queue[index],
|
data = queue[index],
|
||||||
object = data[1];
|
object = data.object;
|
||||||
|
|
||||||
push.apply(args, data[2]);
|
push.apply(args, data.args);
|
||||||
result = object[data[0]].apply(object, args);
|
result = object[data.name].apply(object, args);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
function limitSource(operators, source) {
|
|
||||||
var len = operators.length,
|
|
||||||
min = 0,
|
|
||||||
max = source.length - 1;
|
|
||||||
|
|
||||||
for(var i = 0; i < len; i++) {
|
|
||||||
var op = operators[i];
|
|
||||||
switch(op.name) {
|
|
||||||
case 'take': max = Math.min(max, min + (op.count - 1)); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
min: min,
|
|
||||||
max: max
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveLazyWrapper(wrapper, source, sourceRange) {
|
|
||||||
var resultIndex = 0,
|
|
||||||
dir = wrapper.dir,
|
|
||||||
loops = sourceRange.max - sourceRange.min + 1,
|
|
||||||
resultLimit = Math.min(wrapper.limit, loops),
|
|
||||||
sourceIndex = (dir == 1 ? sourceRange.min : sourceRange.max) - dir,
|
|
||||||
result = [],
|
|
||||||
type = wrapper.type,
|
|
||||||
iterators = wrapper.iterators,
|
|
||||||
num = type.length;
|
|
||||||
|
|
||||||
lazy:
|
|
||||||
while (loops-- && resultIndex < resultLimit) {
|
|
||||||
sourceIndex += dir;
|
|
||||||
val = source[sourceIndex];
|
|
||||||
|
|
||||||
for(i = 0; i < num; i++) {
|
|
||||||
iterator = iterators[i];
|
|
||||||
switch(type[i]) {
|
|
||||||
// LazyWrapper.MAP_FLAG
|
|
||||||
case 1: val = iterator(val, sourceIndex, source); break;
|
|
||||||
// LazyWrapper.FILTER_FLAG
|
|
||||||
case 2: if(!iterator(val, sourceIndex, source)) { continue lazy; }
|
|
||||||
// LazyWrapper.WHILE_FLAG
|
|
||||||
case 3: if(!iterator(val, sourceIndex, source)) { break lazy; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result[resultIndex++] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function LazyWrapper(value) {
|
function LazyWrapper(value) {
|
||||||
this.value = value;
|
if (value instanceof LazyWrapper) {
|
||||||
this.queue = [];
|
this.dir = value.dir;
|
||||||
|
this.iteratees = baseSlice(value.iteratees);
|
||||||
|
this.views = baseSlice(value.views);
|
||||||
|
this.wrapped = value.wrapped;
|
||||||
this.limit = POSITIVE_INFINITY;
|
} else {
|
||||||
this.filterApplied = false;
|
this.dir = 1;
|
||||||
this.dir = 1;
|
this.iteratees = [];
|
||||||
}
|
this.views = [];
|
||||||
|
this.wrapped = value;
|
||||||
LodashWrapper(value, chainAll, queue) {
|
}
|
||||||
this.__chain__ = !!chainAll;
|
|
||||||
this.__queue__ = queue || [];
|
|
||||||
this.__wrapped__ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
this.type = [];
|
|
||||||
this.iterators = [];
|
|
||||||
this.limitActions = [];
|
|
||||||
limitActions = [];
|
|
||||||
*/
|
|
||||||
|
|
||||||
function lazyClone() {
|
|
||||||
var clone = new LazyWrapper(this.source);
|
|
||||||
clone.type = this.type.concat();
|
|
||||||
clone.iterators = this.iterators.concat();
|
|
||||||
clone.limit = this.limit;
|
|
||||||
clone.limitActions = this.limitActions.concat();
|
|
||||||
clone.filterApplied = this.filterApplied;
|
|
||||||
clone.dir = this.dir;
|
|
||||||
return clone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyFilter(predicate, thisArg) {
|
function lazyFilter(predicate, thisArg) {
|
||||||
predicate = getCallback(predicate, thisArg, 3);
|
predicate = getCallback(predicate, thisArg, 3);
|
||||||
|
|
||||||
var fork = this.clone();
|
var result = new LazyWrapper(this);
|
||||||
fork.filterApplied = true;
|
result.iteratees.push({ 'type': LAZY_FILTER_FLAG, 'iteratee': predicate });
|
||||||
[methodName, object, arguments]
|
return result;
|
||||||
fork.type.push(LazyWrapper.FILTER_FLAG);
|
|
||||||
fork.iterators.push(predicate);
|
|
||||||
return fork;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyFirst() {
|
function lazyFirst() {
|
||||||
return this.take(1).value()[0];
|
return this.take(1).value()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyMap(iterator, thisArg) {
|
function lazyMap(iteratee, thisArg) {
|
||||||
iterator = getCallback(iterator, thisArg, 3);
|
iteratee = getCallback(iteratee, thisArg, 3);
|
||||||
|
|
||||||
var result = this.clone();
|
var result = new LazyWrapper(this);
|
||||||
result.queue.push([iterator);
|
result.iteratees.push({ 'type': LAZY_MAP_FLAG, 'iteratee': iteratee });
|
||||||
fork.type.push(LazyWrapper.MAP_FLAG);
|
return result;
|
||||||
return fork;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyTake(n) {
|
function lazyTake(n) {
|
||||||
var fork = this.clone();
|
n = n == null ? 1 : n;
|
||||||
n = (n == null) ? 1 : n;
|
|
||||||
if(fork.filterApplied) {
|
var result = new LazyWrapper(this);
|
||||||
fork.limit = n;
|
result.views.push({ 'type': 'take', 'size': n });
|
||||||
return new LazyWrapper(fork);
|
return result;
|
||||||
}
|
|
||||||
fork.limitActions.push(getLimitAction('take', n, this.dir));
|
|
||||||
return fork;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyValue() {
|
function lazyValue() {
|
||||||
var source = this.source,
|
var array = this.wrapped;
|
||||||
sourceLimit;
|
if (array instanceof LodashWrapper || array instanceof LazyWrapper) {
|
||||||
|
array = array.value();
|
||||||
if (source instanceof LazyWrapper) {
|
|
||||||
source = source.value();
|
|
||||||
}
|
}
|
||||||
sourceLimit = limitSource(this.limitActions, source);
|
var start = 0,
|
||||||
console.log('sourceLimit', sourceLimit)
|
end = array.length,
|
||||||
return resolveLazyWrapper(this, source, sourceLimit);
|
length = end,
|
||||||
|
views = this.views,
|
||||||
|
viewsLength = views.length;
|
||||||
|
|
||||||
|
while (viewsLength--) {
|
||||||
|
var view = views[viewsLength],
|
||||||
|
size = view.size;
|
||||||
|
|
||||||
|
switch (view.type) {
|
||||||
|
case 'take': end = nativeMin(end, start + size); break;
|
||||||
|
case 'takeRight': start = nativeMax(start, end - size); break;
|
||||||
|
case 'drop': start += size; break;
|
||||||
|
case 'dropRight': end -= size; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dir = this.dir,
|
||||||
|
index = (dir == 1 ? start : end) - dir,
|
||||||
|
iteratees = this.iteratees,
|
||||||
|
iterateesLength = iteratees.length,
|
||||||
|
resLimit = end - start,
|
||||||
|
result = [];
|
||||||
|
|
||||||
|
outer:
|
||||||
|
while (length-- && result.length < resLimit) {
|
||||||
|
index += dir;
|
||||||
|
|
||||||
|
var iterateesIndex = -1,
|
||||||
|
value = array[index];
|
||||||
|
|
||||||
|
while (++iterateesIndex < iterateesLength) {
|
||||||
|
var data = iteratees[iterateesIndex],
|
||||||
|
iteratee = data.iteratee;
|
||||||
|
|
||||||
|
switch (data.type) {
|
||||||
|
case LAZY_FILTER_FLAG:
|
||||||
|
if (!iteratee(value, index, array)) {
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LAZY_MAP_FLAG:
|
||||||
|
value = iteratee(value, index, array);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LAZY_WHILE_FLAG:
|
||||||
|
if (!iteratee(value, index, array)) {
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@@ -9259,8 +9233,8 @@
|
|||||||
return function() {
|
return function() {
|
||||||
if (chain || this.__chain__) {
|
if (chain || this.__chain__) {
|
||||||
var result = object(this.__wrapped__);
|
var result = object(this.__wrapped__);
|
||||||
result.__chain__ = this.__chain__;
|
result.__chain__ = true;
|
||||||
(result.__queue__ = baseSlice(this.__queue__)).push([methodName, object, arguments]);
|
(result.__queue__ = baseSlice(this.__queue__)).push({ 'name': methodName, 'object': object, 'args': arguments });
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
var args = [this.value()];
|
var args = [this.value()];
|
||||||
@@ -9849,24 +9823,47 @@
|
|||||||
lodash[methodName].placeholder = lodash;
|
lodash[methodName].placeholder = lodash;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ensure `new LodashWrapper` is an instance of `lodash`
|
||||||
|
LodashWrapper.prototype = lodash.prototype
|
||||||
|
|
||||||
|
// add functions to the memoize cache
|
||||||
|
MemCache.prototype.get = memGet;
|
||||||
|
MemCache.prototype.has = memHas;
|
||||||
|
MemCache.prototype.set = memSet;
|
||||||
|
memoize.Cache = MemCache;
|
||||||
|
|
||||||
|
// add functions to the lazy wrapper
|
||||||
|
LazyWrapper.prototype.filter = lazyFilter;
|
||||||
|
LazyWrapper.prototype.first = lazyFirst;
|
||||||
|
LazyWrapper.prototype.map = lazyMap;
|
||||||
|
LazyWrapper.prototype.take = lazyTake;
|
||||||
|
LazyWrapper.prototype.value = lazyValue;
|
||||||
|
|
||||||
// add `LazyWrapper` functions
|
// add `LazyWrapper` functions
|
||||||
arrayEach(['map', 'filter', 'first', 'take'], function(methodName) {
|
arrayEach(['map', 'filter', 'take'], function(methodName) {
|
||||||
var func = LazyWrapper.prototype[methodName];
|
var func = LazyWrapper.prototype[methodName];
|
||||||
var overriddenFunc = lodash.prototype[methodName];
|
|
||||||
lodash.prototype[methodName] = function() {
|
lodash.prototype[methodName] = function() {
|
||||||
var isLazy = wrapped instanceof LazyWrapper,
|
var value = this.__wrapped__,
|
||||||
value = this.__wrapped__;
|
isLazy = value instanceof LazyWrapper;
|
||||||
|
|
||||||
var result = isLazy
|
if (!isLazy && !isArray(value)) {
|
||||||
? overriddenFunc.apply(this, arguments)
|
var args = [this.value()];
|
||||||
: func.apply(inLazyChain ? wrapped : new LazyWrapper(wrapped), arguments);
|
push.apply(args, arguments);
|
||||||
|
value = lodash[methodName].apply(lodash, args);
|
||||||
return (wrapped instanceof LazyWrapper || this.__chain__)
|
} else {
|
||||||
? new LodashWrapper(wrapped, this.__chain__)
|
value = func.apply(isLazy ? value : new LazyWrapper(this), arguments);
|
||||||
: wrapped;
|
isLazy = true;
|
||||||
|
}
|
||||||
|
return (isLazy || this.__chain__) ? new LodashWrapper(value, true) : value;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// add "Chaining" functions to the lodash wrapper
|
||||||
|
lodash.prototype.chain = wrapperChain;
|
||||||
|
lodash.prototype.toString = wrapperToString;
|
||||||
|
lodash.prototype.toJSON = lodash.prototype.value = lodash.prototype.valueOf = wrapperValueOf;
|
||||||
|
|
||||||
// add `Array.prototype` functions
|
// add `Array.prototype` functions
|
||||||
arrayEach(['concat', 'join', 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
|
arrayEach(['concat', 'join', 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
|
||||||
var arrayFunc = arrayProto[methodName],
|
var arrayFunc = arrayProto[methodName],
|
||||||
@@ -9895,31 +9892,10 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// add functions to the lazy wrapper
|
|
||||||
LazyWrapper.prototype.clone = lazyClone;
|
|
||||||
LazyWrapper.prototype.first = lazyFirst;
|
|
||||||
LazyWrapper.prototype.map = lazyMap;
|
|
||||||
LazyWrapper.prototype.take = lazyTake;
|
|
||||||
LazyWrapper.prototype.value = lazyValue;
|
|
||||||
|
|
||||||
// ensure `new LodashWrapper` is an instance of `lodash`
|
|
||||||
LodashWrapper.prototype = lodash.prototype;
|
|
||||||
|
|
||||||
// add functions to the memoize cache
|
|
||||||
MemCache.prototype.get = memGet;
|
|
||||||
MemCache.prototype.has = memHas;
|
|
||||||
MemCache.prototype.set = memSet;
|
|
||||||
memoize.Cache = MemCache;
|
|
||||||
|
|
||||||
// add function aliases to the lodash wrapper
|
// add function aliases to the lodash wrapper
|
||||||
lodash.prototype.collect = lodash.prototype.map;
|
lodash.prototype.collect = lodash.prototype.map;
|
||||||
lodash.prototype.select = lodash.prototype.filter;
|
lodash.prototype.select = lodash.prototype.filter;
|
||||||
|
|
||||||
// add "Chaining" functions to the lodash wrapper
|
|
||||||
lodash.prototype.chain = wrapperChain;
|
|
||||||
lodash.prototype.toString = wrapperToString;
|
|
||||||
lodash.prototype.toJSON = lodash.prototype.value = lodash.prototype.valueOf = wrapperValueOf;
|
|
||||||
|
|
||||||
return lodash;
|
return lodash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user