mirror of
https://github.com/BreizhHardware/memoizee.git
synced 2026-03-18 21:40:27 +01:00
Major reorganization and partial refactoring
- Move out main modules from `lib` folder - Introduce `normalizer` based configurations, and convert primitive and regular handlers into thos normalizers (can be found in lib/normalizers folder). Custom normalizers can be provided at run time via `normaizer` option - Provide `plain` module which does not load any extensions or normalizers. Any extensions that have to be used should be required upfront and normalizers should be provided directly - Remove `method` option, instead `methods` and `methods-plan` modules are provided which generate descriptors for lazy created memoized methods - `profile` is no longer extension. To be used it should be required directly - Improve logic for `async` handling - Take out `max` extensionLRU logic into external `lru-queue` package - Remove `context` option - Remove possibility to access original arguments when resolvers are used - Assure expected length of memoized functions
This commit is contained in:
57
lib/_base.js
57
lib/_base.js
@@ -1,57 +0,0 @@
|
||||
// To be used internally, memoize factory
|
||||
|
||||
'use strict';
|
||||
|
||||
var callable = require('es5-ext/object/valid-callable')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, ee = require('event-emitter')
|
||||
|
||||
, ext;
|
||||
|
||||
module.exports = exports = function (core) {
|
||||
return function self(fn/*, options */) {
|
||||
var options, length, get, clear, conf;
|
||||
|
||||
callable(fn);
|
||||
options = Object(arguments[1]);
|
||||
|
||||
// Do not memoize already memoized function
|
||||
if (fn.memoized && !options.force) return fn;
|
||||
|
||||
if (ext.method && (options.method != null)) {
|
||||
return ext.method(options.method, options, fn, self);
|
||||
}
|
||||
|
||||
conf = ee({ memoize: self, fn: fn });
|
||||
|
||||
// Normalize length
|
||||
if (isNaN(options.length)) {
|
||||
length = fn.length;
|
||||
// Special case
|
||||
if (options.async && ext.async) --length;
|
||||
} else {
|
||||
length = (options.length === false) ? false : (options.length >>> 0);
|
||||
}
|
||||
|
||||
core(conf, length, options);
|
||||
|
||||
forEach(ext, function (fn, name) {
|
||||
if (fn.force) fn(conf, options);
|
||||
else if (options[name]) fn(options[name], conf, options);
|
||||
});
|
||||
|
||||
fn = conf.fn;
|
||||
get = conf.get;
|
||||
clear = conf.clear;
|
||||
|
||||
conf.memoized.clear = function () { clear(get(arguments)); };
|
||||
conf.memoized.clearAll = function () {
|
||||
conf.emit('purgeall');
|
||||
conf.clearAll();
|
||||
};
|
||||
conf.memoized.memoized = true;
|
||||
conf.emit('ready');
|
||||
return conf.memoized;
|
||||
};
|
||||
};
|
||||
ext = exports.ext = {};
|
||||
144
lib/configure-map.js
Normal file
144
lib/configure-map.js
Normal file
@@ -0,0 +1,144 @@
|
||||
'use strict';
|
||||
|
||||
var toArray = require('es5-ext/array/to-array')
|
||||
, customError = require('es5-ext/error/custom')
|
||||
, defineLength = require('es5-ext/function/_define-length')
|
||||
, callable = require('es5-ext/object/valid-callable')
|
||||
, d = require('d')
|
||||
, ee = require('event-emitter').methods
|
||||
|
||||
, slice = Array.prototype.slice
|
||||
, apply = Function.prototype.apply, call = Function.prototype.call
|
||||
, create = Object.create, hasOwnProperty = Object.prototype.hasOwnProperty
|
||||
, defineProperties = Object.defineProperties
|
||||
, on = ee.on, emit = ee.emit, resolveArgs;
|
||||
|
||||
resolveArgs = function (args) {
|
||||
return this.map(function (r, i) {
|
||||
return r ? r(args[i]) : args[i];
|
||||
}).concat(slice.call(args, this.length));
|
||||
};
|
||||
|
||||
module.exports = function (original, length, options) {
|
||||
var cache = create(null), conf, memLength, get, set, del, clear
|
||||
, getListeners, setListeners, deleteListeners, memoized, resolve, resolvers;
|
||||
if (length !== false) memLength = length;
|
||||
else if (isNaN(original.length)) memLength = 1;
|
||||
else memLength = original.length;
|
||||
|
||||
if (options.normalizer) {
|
||||
get = callable(options.normalizer.get);
|
||||
if (options.normalizer.set !== undefined) {
|
||||
set = callable(options.normalizer.set);
|
||||
del = callable(options.normalizer.delete);
|
||||
clear = callable(options.normalizer.clear);
|
||||
} else {
|
||||
set = get;
|
||||
}
|
||||
} else if (options.serialize) {
|
||||
set = get = (function (serialize) {
|
||||
return function (args) { return serialize.apply(null, args); };
|
||||
}(callable(options.serialize)));
|
||||
}
|
||||
|
||||
if (options.resolvers != null) {
|
||||
resolvers = toArray(options.resolvers);
|
||||
resolvers.forEach(function (r) {
|
||||
if (r != null) callable(r);
|
||||
});
|
||||
resolve = resolveArgs.bind(resolvers);
|
||||
}
|
||||
|
||||
if (get) {
|
||||
memoized = defineLength(function (arg) {
|
||||
var id, result, args = arguments;
|
||||
if (resolve) args = resolve(args);
|
||||
id = get(args);
|
||||
if (id !== null) {
|
||||
if (hasOwnProperty.call(cache, id)) {
|
||||
if (getListeners) conf.emit('get', id, args, this);
|
||||
return cache[id];
|
||||
}
|
||||
}
|
||||
if (args.length === 1) result = call.call(original, this, arg);
|
||||
else result = apply.call(original, this, args);
|
||||
if (id === null) {
|
||||
id = get(args);
|
||||
if (id !== null) throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
||||
id = set(args);
|
||||
} else if (hasOwnProperty.call(cache, id)) {
|
||||
throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
cache[id] = result;
|
||||
if (setListeners) conf.emit('set', id);
|
||||
return result;
|
||||
}, memLength);
|
||||
} else {
|
||||
memoized = function (arg) {
|
||||
var result, args = arguments;
|
||||
if (resolve) {
|
||||
args = resolve(arguments);
|
||||
arg = args[0];
|
||||
}
|
||||
if (hasOwnProperty.call(cache, arg)) {
|
||||
if (getListeners) conf.emit('get', arg, args, this);
|
||||
return cache[arg];
|
||||
}
|
||||
if (args.length === 1) result = call.call(original, this, arg);
|
||||
else result = apply.call(original, this, args);
|
||||
if (hasOwnProperty.call(cache, arg)) {
|
||||
throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
cache[arg] = result;
|
||||
if (setListeners) conf.emit('set', arg);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
conf = {
|
||||
original: original,
|
||||
memoized: memoized,
|
||||
get: function (args) {
|
||||
if (resolve) args = resolve(args);
|
||||
if (get) return get(args);
|
||||
return args[0];
|
||||
},
|
||||
has: function (id) { return hasOwnProperty.call(cache, id); },
|
||||
delete: function (id) {
|
||||
var result;
|
||||
if (!hasOwnProperty.call(cache, id)) return;
|
||||
if (del) del(id);
|
||||
result = cache[id];
|
||||
delete cache[id];
|
||||
if (deleteListeners) conf.emit('delete', id, result);
|
||||
},
|
||||
clear: function () {
|
||||
var oldCache = cache;
|
||||
if (clear) clear();
|
||||
cache = create(null);
|
||||
conf.emit('clear', oldCache);
|
||||
},
|
||||
on: function (type, listener) {
|
||||
if (type === 'get') getListeners = true;
|
||||
else if (type === 'set') setListeners = true;
|
||||
else if (type === 'delete') deleteListeners = true;
|
||||
return on.call(this, type, listener);
|
||||
},
|
||||
emit: emit,
|
||||
updateEnv: function () { original = conf.original; }
|
||||
};
|
||||
defineProperties(memoized, {
|
||||
__memoized__: d(true),
|
||||
delete: d(get ? defineLength(function (arg) {
|
||||
var id, args = arguments;
|
||||
if (resolve) args = resolve(args);
|
||||
id = get(args);
|
||||
if (id === null) return;
|
||||
conf.delete(id);
|
||||
}, memLength) : function (arg) {
|
||||
if (resolve) arg = resolve(arguments)[0];
|
||||
return conf.delete(arg);
|
||||
}),
|
||||
clear: d(conf.clear)
|
||||
});
|
||||
return conf;
|
||||
};
|
||||
20
lib/d.js
20
lib/d.js
@@ -1,20 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var forEach = require('es5-ext/object/for-each')
|
||||
, callable = require('es5-ext/object/valid-callable')
|
||||
, lazy = require('d/lazy')
|
||||
|
||||
, a = [], b = [];
|
||||
|
||||
module.exports = function (fn) {
|
||||
var index = a.indexOf(callable(fn));
|
||||
if (index !== -1) return b[index];
|
||||
index = a.push(fn);
|
||||
return (b[index - 1] = function (props) {
|
||||
forEach(props, function (desc, name) {
|
||||
var value = callable(desc.value);
|
||||
desc.value = function (options) { return fn(value.bind(this), options); };
|
||||
});
|
||||
return lazy(props);
|
||||
});
|
||||
};
|
||||
111
lib/ext/async.js
111
lib/ext/async.js
@@ -1,111 +0,0 @@
|
||||
// Support for asynchronous functions
|
||||
|
||||
'use strict';
|
||||
|
||||
var aFrom = require('es5-ext/array/from')
|
||||
, last = require('es5-ext/array/#/last')
|
||||
, isArguments = require('es5-ext/function/is-arguments')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, isCallable = require('es5-ext/object/is-callable')
|
||||
, nextTick = require('next-tick')
|
||||
|
||||
, isArray = Array.isArray, slice = Array.prototype.slice
|
||||
, apply = Function.prototype.apply;
|
||||
|
||||
require('../_base').ext.async = function (ignore, conf) {
|
||||
var cache, purge;
|
||||
|
||||
cache = conf.async = {};
|
||||
|
||||
(function (org) {
|
||||
var value, cb, initContext, initArgs, fn, resolver;
|
||||
|
||||
conf.on('init', function (id) {
|
||||
value.id = id;
|
||||
cache[id] = cb ? [cb] : [];
|
||||
});
|
||||
|
||||
conf.on('hit', function (id, syncArgs, syncCtx) {
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isArray(cache[id])) {
|
||||
cache[id].push(cb);
|
||||
} else {
|
||||
nextTick(function (cb, id, ctx, args) {
|
||||
if (cache[id]) {
|
||||
conf.emit('hitasync', id, syncArgs, syncCtx);
|
||||
apply.call(cb, this.context, this);
|
||||
} else {
|
||||
// Purged in a meantime, we shouldn't rely on cached value, recall
|
||||
fn.apply(ctx, args);
|
||||
}
|
||||
}.bind(cache[id], cb, id, initContext, initArgs));
|
||||
initContext = initArgs = null;
|
||||
}
|
||||
});
|
||||
conf.fn = function () {
|
||||
var args, asyncArgs;
|
||||
args = arguments;
|
||||
asyncArgs = aFrom(args);
|
||||
asyncArgs.push(value = function self(err) {
|
||||
var i, cb, waiting, res;
|
||||
if (self.id == null) {
|
||||
// Shouldn't happen, means async callback was called sync way
|
||||
nextTick(apply.bind(self, this, arguments));
|
||||
return;
|
||||
}
|
||||
waiting = cache[self.id];
|
||||
if (conf.cache.hasOwnProperty(self.id)) {
|
||||
if (err) {
|
||||
delete cache[self.id];
|
||||
conf.clear(self.id);
|
||||
} else {
|
||||
arguments.context = this;
|
||||
cache[self.id] = arguments;
|
||||
conf.emit('initasync', self.id, waiting.length);
|
||||
}
|
||||
} else {
|
||||
delete cache[self.id];
|
||||
}
|
||||
for (i = 0; (cb = waiting[i]); ++i) {
|
||||
res = apply.call(cb, this, arguments);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
return apply.call(org, this, asyncArgs);
|
||||
};
|
||||
|
||||
fn = conf.memoized;
|
||||
resolver = function (args) {
|
||||
cb = last.call(args);
|
||||
if (isCallable(cb)) return slice.call(args, 0, -1);
|
||||
cb = null;
|
||||
return args;
|
||||
};
|
||||
conf.memoized = function () {
|
||||
return fn.apply(initContext = this, initArgs = resolver(arguments));
|
||||
};
|
||||
forEach(fn, function (value, name) {
|
||||
conf.memoized[name] = function () {
|
||||
return fn[name].apply(this, resolver(arguments));
|
||||
};
|
||||
});
|
||||
|
||||
}(conf.fn));
|
||||
|
||||
conf.on('purge', purge = function (id) {
|
||||
// If false, we don't have value yet, so we assume that intention is not
|
||||
// to memoize this call. After value is obtained we don't cache it but
|
||||
// gracefully pass to callback
|
||||
if (isArguments(cache[id])) {
|
||||
conf.emit('purgeasync', id);
|
||||
delete cache[id];
|
||||
}
|
||||
});
|
||||
|
||||
conf.on('purgeall', function () {
|
||||
forEach(conf.async, function (value, id) { purge(id); });
|
||||
});
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
// Call dispose callback on each cache purge
|
||||
|
||||
'use strict';
|
||||
|
||||
var callable = require('es5-ext/object/valid-callable')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, ext = require('../_base').ext
|
||||
|
||||
, slice = Array.prototype.slice;
|
||||
|
||||
ext.dispose = function (dispose, conf, options) {
|
||||
var clear, async, context;
|
||||
|
||||
callable(dispose);
|
||||
|
||||
async = (options.async && ext.async);
|
||||
context = options.context;
|
||||
conf.on('purge' + (async ? 'async' : ''), clear = async ? function (id) {
|
||||
var value = conf.async[id];
|
||||
delete conf.cache[id];
|
||||
dispose.apply(context, slice.call(value, 1));
|
||||
} : function (id) {
|
||||
var value = conf.cache[id];
|
||||
delete conf.cache[id];
|
||||
dispose.call(context, value);
|
||||
});
|
||||
|
||||
if (!async) {
|
||||
conf.on('purgeall', function () {
|
||||
forEach(conf.cache, function (value, id) { clear(id); });
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,76 +0,0 @@
|
||||
// Timeout cached values
|
||||
|
||||
'use strict';
|
||||
|
||||
var isNumber = require('es5-ext/number/is-number')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, nextTick = require('next-tick')
|
||||
, ext = require('../_base').ext
|
||||
|
||||
, max = Math.max, min = Math.min;
|
||||
|
||||
ext.maxAge = function (maxAge, conf, options) {
|
||||
var cache, async, preFetchAge, preFetchCache;
|
||||
|
||||
maxAge = maxAge >>> 0;
|
||||
if (!maxAge) {
|
||||
return;
|
||||
}
|
||||
|
||||
cache = {};
|
||||
async = options.async && ext.async;
|
||||
conf.on('init' + (async ? 'async' : ''), function (id) {
|
||||
cache[id] = setTimeout(function () { conf.clear(id); }, maxAge);
|
||||
if (preFetchCache) {
|
||||
preFetchCache[id] = setTimeout(function () { delete preFetchCache[id]; },
|
||||
preFetchAge);
|
||||
}
|
||||
});
|
||||
conf.on('purge' + (async ? 'async' : ''), function (id) {
|
||||
clearTimeout(cache[id]);
|
||||
if (preFetchCache && preFetchCache[id]) {
|
||||
clearTimeout(preFetchCache[id]);
|
||||
delete preFetchCache[id];
|
||||
}
|
||||
delete cache[id];
|
||||
});
|
||||
|
||||
if (options.preFetch) {
|
||||
if (isNumber(options.preFetch)) {
|
||||
preFetchAge = max(min(Number(options.preFetch), 1), 0);
|
||||
} else {
|
||||
preFetchAge = 0.333;
|
||||
}
|
||||
if (preFetchAge) {
|
||||
preFetchCache = {};
|
||||
preFetchAge = (1 - preFetchAge) * maxAge;
|
||||
conf.on('hit' + (async ? 'async' : ''), function (id, args, ctx) {
|
||||
if (!preFetchCache[id]) {
|
||||
preFetchCache[id] = true;
|
||||
nextTick(function () {
|
||||
if (preFetchCache[id] === true) {
|
||||
delete preFetchCache[id];
|
||||
conf.clear(id);
|
||||
conf.memoized.apply(ctx, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!async) {
|
||||
conf.on('purgeall', function () {
|
||||
forEach(cache, function (id) {
|
||||
clearTimeout(id);
|
||||
});
|
||||
cache = {};
|
||||
if (preFetchCache) {
|
||||
forEach(preFetchCache, function (id) {
|
||||
clearTimeout(id);
|
||||
});
|
||||
preFetchCache = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
// Limit cache size, LRU (least recently used) algorithm.
|
||||
|
||||
'use strict';
|
||||
|
||||
var ext = require('../_base').ext;
|
||||
|
||||
ext.max = function (max, conf, options) {
|
||||
var index, base, size, queue, map, async;
|
||||
|
||||
max = max >>> 0;
|
||||
if (!max) {
|
||||
return;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
base = size = 0;
|
||||
queue = {};
|
||||
map = {};
|
||||
async = options.async && ext.async;
|
||||
|
||||
conf.on('init' + (async ? 'async' : ''), function (id) {
|
||||
queue[++index] = id;
|
||||
map[id] = index;
|
||||
++size;
|
||||
if (size > max) {
|
||||
conf.clear(queue[base]);
|
||||
}
|
||||
});
|
||||
|
||||
conf.on('hit' + (async ? 'async' : ''), function (id) {
|
||||
var oldIndex = map[id];
|
||||
queue[++index] = id;
|
||||
map[id] = index;
|
||||
delete queue[oldIndex];
|
||||
if (base === oldIndex) {
|
||||
while (!queue.hasOwnProperty(++base)) continue; //jslint: skip
|
||||
}
|
||||
});
|
||||
|
||||
conf.on('purge' + (async ? 'async' : ''), function (id) {
|
||||
var oldIndex = map[id];
|
||||
delete queue[oldIndex];
|
||||
--size;
|
||||
if (base === oldIndex) {
|
||||
if (!size) {
|
||||
index = -1;
|
||||
base = 0;
|
||||
} else {
|
||||
while (!queue.hasOwnProperty(++base)) continue; //jslint: skip
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!async) {
|
||||
conf.on('purgeall', function () {
|
||||
index = -1;
|
||||
base = size = 0;
|
||||
queue = {};
|
||||
map = {};
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
// Memoized methods factory
|
||||
|
||||
'use strict';
|
||||
|
||||
var copy = require('es5-ext/object/copy')
|
||||
|
||||
, defineProperty = Object.defineProperty;
|
||||
|
||||
require('../_base').ext.method = function (method, options, fn, configure) {
|
||||
var name, descriptor, props, prop, selfName;
|
||||
name = selfName = String(method);
|
||||
descriptor = {
|
||||
enumerable: (options.enumerable == null) ? false :
|
||||
Boolean(options.enumerable),
|
||||
configurable: (options.configurable == null) ? true :
|
||||
Boolean(options.configurable),
|
||||
writable: (options.writable == null) ? true :
|
||||
Boolean(options.writable)
|
||||
};
|
||||
props = {};
|
||||
prop = props[selfName] = copy(descriptor);
|
||||
delete prop.writable;
|
||||
if (options.protoDeep != null) {
|
||||
if (typeof options.protoDeep === 'boolean') {
|
||||
if (options.protoDeep) name = '_' + name + '_';
|
||||
} else {
|
||||
name = String(options.protoDeep);
|
||||
}
|
||||
}
|
||||
options = copy(options);
|
||||
delete options.method;
|
||||
delete options.protoDeep;
|
||||
|
||||
prop.get = function () {
|
||||
if ((name !== selfName) && this.hasOwnProperty(name)) return this[name];
|
||||
options.context = this;
|
||||
descriptor.value = configure(fn.bind(this), options);
|
||||
defineProperty(this, name, descriptor);
|
||||
return this[name];
|
||||
};
|
||||
return props;
|
||||
};
|
||||
@@ -1,82 +0,0 @@
|
||||
// Gathers statistical data, and provides them in convinient form
|
||||
|
||||
'use strict';
|
||||
|
||||
var partial = require('es5-ext/function/#/partial')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, pad = require('es5-ext/string/#/pad')
|
||||
|
||||
, max = Math.max
|
||||
|
||||
, stats = exports.statistics = {}, ext;
|
||||
|
||||
require('../_base').ext.profile = ext = function (conf) {
|
||||
var id, stack, data;
|
||||
stack = (new Error()).stack;
|
||||
if (!stack.split('\n').slice(3).some(function (line) {
|
||||
if ((line.indexOf('/memoizee/') === -1) &&
|
||||
(line.indexOf('/es5-ext/') === -1) &&
|
||||
(line.indexOf('/next/lib/fs/_memoize-watcher') === -1) &&
|
||||
(line.indexOf(' (native)') === -1)) {
|
||||
id = line.replace(/\n/g, "\\n").trim();
|
||||
return true;
|
||||
}
|
||||
})) {
|
||||
id = 'unknown';
|
||||
}
|
||||
|
||||
if (!stats[id]) {
|
||||
stats[id] = { initial: 0, cached: 0 };
|
||||
}
|
||||
data = stats[id];
|
||||
|
||||
conf.on('init', function () { ++data.initial; });
|
||||
conf.on('hit', function () { ++data.cached; });
|
||||
};
|
||||
ext.force = true;
|
||||
|
||||
exports.log = function () {
|
||||
var initial, cached, ordered, ipad, cpad, ppad, toPrc, log;
|
||||
|
||||
initial = cached = 0;
|
||||
ordered = [];
|
||||
|
||||
toPrc = function (initial, cached) {
|
||||
if (!initial && !cached) {
|
||||
return '0.00';
|
||||
}
|
||||
return ((cached / (initial + cached)) * 100).toFixed(2);
|
||||
};
|
||||
|
||||
log = "------------------------------------------------------------\n";
|
||||
log += "Memoize statistics:\n\n";
|
||||
|
||||
forEach(stats, function (data, name) {
|
||||
initial += data.initial;
|
||||
cached += data.cached;
|
||||
ordered.push([name, data]);
|
||||
}, null, function (a, b) {
|
||||
return (this[b].initial + this[b].cached) -
|
||||
(this[a].initial + this[a].cached);
|
||||
});
|
||||
|
||||
ipad = partial.call(pad, " ",
|
||||
max(String(initial).length, "Init".length));
|
||||
cpad = partial.call(pad, " ", max(String(cached).length, "Cache".length));
|
||||
ppad = partial.call(pad, " ", "%Cache".length);
|
||||
log += ipad.call("Init") + " " +
|
||||
cpad.call("Cache") + " " +
|
||||
ppad.call("%Cache") + " Source location\n";
|
||||
log += ipad.call(initial) + " " +
|
||||
cpad.call(cached) + " " +
|
||||
ppad.call(toPrc(initial, cached)) + " (all)\n";
|
||||
ordered.forEach(function (data) {
|
||||
var name = data[0];
|
||||
data = data[1];
|
||||
log += ipad.call(data.initial) + " " +
|
||||
cpad.call(data.cached) + " " +
|
||||
ppad.call(toPrc(data.initial, data.cached)) + " " + name + "\n";
|
||||
});
|
||||
log += "------------------------------------------------------------\n";
|
||||
return log;
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
// Reference counter, useful for garbage collector like functionality
|
||||
|
||||
'use strict';
|
||||
|
||||
var ext = require('../_base').ext;
|
||||
|
||||
ext.refCounter = function (ignore, conf, options) {
|
||||
var cache, async;
|
||||
|
||||
cache = {};
|
||||
async = options.async && ext.async;
|
||||
|
||||
conf.on('init' + (async ? 'async' : ''), async ? function (id, length) {
|
||||
cache[id] = length;
|
||||
} : function (id) { cache[id] = 1; });
|
||||
conf.on('hit' + (async ? 'async' : ''), function (id) { ++cache[id]; });
|
||||
conf.on('purge' + (async ? 'async' : ''), function (id) {
|
||||
delete cache[id];
|
||||
});
|
||||
if (!async) {
|
||||
conf.on('purgeall', function () { cache = {}; });
|
||||
}
|
||||
|
||||
conf.memoized.clearRef = function () {
|
||||
var id = conf.get(arguments);
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
if (!--cache[id]) {
|
||||
conf.clear(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
conf.memoized.getRefCount = function () {
|
||||
var id = conf.get(arguments);
|
||||
if (!cache.hasOwnProperty(id)) return 0;
|
||||
return cache[id];
|
||||
};
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
// Normalize arguments before passing them to underlying function
|
||||
|
||||
'use strict';
|
||||
|
||||
var toArray = require('es5-ext/array/to-array')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, callable = require('es5-ext/object/valid-callable')
|
||||
|
||||
, slice = Array.prototype.slice
|
||||
|
||||
, resolve;
|
||||
|
||||
resolve = function (args) {
|
||||
return this.map(function (r, i) {
|
||||
return r ? r(args[i]) : args[i];
|
||||
}).concat(slice.call(args, this.length));
|
||||
};
|
||||
|
||||
require('../_base').ext.resolvers = function (resolvers, conf) {
|
||||
var resolver;
|
||||
|
||||
resolver = toArray(resolvers);
|
||||
resolver.forEach(function (r) {
|
||||
((r == null) || callable(r));
|
||||
});
|
||||
resolver = resolve.bind(resolver);
|
||||
|
||||
(function (fn) {
|
||||
conf.memoized = function () {
|
||||
var value;
|
||||
conf.memoized.args = arguments;
|
||||
value = fn.apply(this, resolver(arguments));
|
||||
delete conf.memoized.args;
|
||||
return value;
|
||||
};
|
||||
forEach(fn, function (value, name) {
|
||||
conf.memoized[name] = function () {
|
||||
return fn[name].apply(this, resolver(arguments));
|
||||
};
|
||||
});
|
||||
}(conf.memoized));
|
||||
};
|
||||
23
lib/index.js
23
lib/index.js
@@ -1,23 +0,0 @@
|
||||
// Provides memoize with all options
|
||||
|
||||
'use strict';
|
||||
|
||||
var regular = require('./regular')
|
||||
, primitive = require('./primitive')
|
||||
|
||||
, call = Function.prototype.call;
|
||||
|
||||
// Order is significant!
|
||||
require('./ext/dispose');
|
||||
require('./ext/resolvers');
|
||||
require('./ext/async');
|
||||
require('./ext/ref-counter');
|
||||
require('./ext/method');
|
||||
require('./ext/max-age');
|
||||
require('./ext/max');
|
||||
|
||||
module.exports = function (fn/* options */) {
|
||||
var options = Object(arguments[1]);
|
||||
return call.call((options.primitive || options.serialize) ?
|
||||
primitive : regular, this, fn, options);
|
||||
};
|
||||
15
lib/methods.js
Normal file
15
lib/methods.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var forEach = require('es5-ext/object/for-each')
|
||||
, callable = require('es5-ext/object/valid-callable')
|
||||
, lazy = require('d/lazy');
|
||||
|
||||
module.exports = function (memoize) {
|
||||
return function (props) {
|
||||
forEach(props, function (desc, name) {
|
||||
var fn = callable(desc.value);
|
||||
desc.value = function (options) { return memoize(fn.bind(this), options); };
|
||||
});
|
||||
return lazy(props);
|
||||
};
|
||||
};
|
||||
5
lib/normalizers/0.js
Normal file
5
lib/normalizers/0.js
Normal file
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var k = require('es5-ext/function/constant');
|
||||
|
||||
module.exports = { get: k('') };
|
||||
12
lib/normalizers/get-primitive-fixed.js
Normal file
12
lib/normalizers/get-primitive-fixed.js
Normal file
@@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (length) {
|
||||
if (!length) {
|
||||
return { get: function () { return ''; } };
|
||||
}
|
||||
return { get: function (args) {
|
||||
var id = String(args[0]), i = 0, l = length;
|
||||
while (--l) { id += '\u0001' + args[++i]; }
|
||||
return id;
|
||||
} };
|
||||
};
|
||||
30
lib/normalizers/get-regular-1.js
Normal file
30
lib/normalizers/get-regular-1.js
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
var indexOf = require('es5-ext/array/#/e-index-of');
|
||||
|
||||
module.exports = function () {
|
||||
var lastId = 0, argsMap = [], cache = [];
|
||||
return {
|
||||
get: function (args) {
|
||||
var index = indexOf.call(argsMap, args[0]);
|
||||
return (index === -1) ? null : cache[index];
|
||||
},
|
||||
set: function (args) {
|
||||
argsMap.push(args[0]);
|
||||
cache.push(++lastId);
|
||||
return lastId;
|
||||
},
|
||||
delete: function (id) {
|
||||
var index = indexOf.call(cache, id);
|
||||
if (index !== -1) {
|
||||
argsMap.splice(index, 1);
|
||||
cache.splice(index, 1);
|
||||
}
|
||||
},
|
||||
clear: function () {
|
||||
argsMap = [];
|
||||
cache = [];
|
||||
lastId = 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
72
lib/normalizers/get-regular-fixed.js
Normal file
72
lib/normalizers/get-regular-fixed.js
Normal file
@@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
var indexOf = require('es5-ext/array/#/e-index-of')
|
||||
, create = Object.create;
|
||||
|
||||
module.exports = function (length) {
|
||||
var lastId = 0, map = [[], []], cache = create(null);
|
||||
return {
|
||||
get: function (args) {
|
||||
var index = 0, set = map, i;
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
return set[1][i] || null;
|
||||
},
|
||||
set: function (args) {
|
||||
var index = 0, set = map, i;
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
set[1].push([[], []]);
|
||||
}
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
}
|
||||
set[1][i] = ++lastId;
|
||||
cache[lastId] = args;
|
||||
return lastId;
|
||||
},
|
||||
delete: function (id) {
|
||||
var index = 0, set = map, i, path = [], args = cache[id];
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
path.push(set, i);
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
id = set[1][i];
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
while (!set[0].length && path.length) {
|
||||
i = path.pop();
|
||||
set = path.pop();
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
}
|
||||
delete cache[id];
|
||||
},
|
||||
clear: function () {
|
||||
map = [[], []];
|
||||
cache = create(null);
|
||||
lastId = 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
89
lib/normalizers/get-regular.js
Normal file
89
lib/normalizers/get-regular.js
Normal file
@@ -0,0 +1,89 @@
|
||||
'use strict';
|
||||
|
||||
var indexOf = require('es5-ext/array/#/e-index-of')
|
||||
, create = Object.create;
|
||||
|
||||
module.exports = function () {
|
||||
var lastId = 0, map = [], cache = create(null);
|
||||
return {
|
||||
get: function (args) {
|
||||
var index = 0, set = map, i, length = args.length;
|
||||
if (length === 0) return set[length] || null;
|
||||
if ((set = set[length])) {
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
return set[1][i] || null;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
set: function (args) {
|
||||
var index = 0, set = map, i, length = args.length;
|
||||
if (length === 0) {
|
||||
set[length] = ++lastId;
|
||||
} else {
|
||||
if (!set[length]) {
|
||||
set[length] = [[], []];
|
||||
}
|
||||
set = set[length];
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
set[1].push([[], []]);
|
||||
}
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
}
|
||||
set[1][i] = ++lastId;
|
||||
}
|
||||
cache[lastId] = args;
|
||||
return lastId;
|
||||
},
|
||||
delete: function (id) {
|
||||
var index = 0, set = map, i, args = cache[id], length = args.length
|
||||
, path = [];
|
||||
if (length === 0) {
|
||||
delete set[length];
|
||||
} else if ((set = set[length])) {
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
path.push(set, i);
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
id = set[1][i];
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
while (!set[0].length && path.length) {
|
||||
i = path.pop();
|
||||
set = path.pop();
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
}
|
||||
}
|
||||
delete cache[id];
|
||||
},
|
||||
clear: function () {
|
||||
map = [];
|
||||
cache = create(null);
|
||||
lastId = 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
9
lib/normalizers/primitive.js
Normal file
9
lib/normalizers/primitive.js
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = { get: function (args) {
|
||||
var id, i, length = args.length;
|
||||
if (!length) return '\u0002';
|
||||
id = String(args[i = 0]);
|
||||
while (--length) id += '\u0001' + args[++i];
|
||||
return id;
|
||||
} };
|
||||
@@ -1,90 +0,0 @@
|
||||
// Memoize working in primitive mode
|
||||
|
||||
'use strict';
|
||||
|
||||
var customError = require('es5-ext/error/custom')
|
||||
, callable = require('es5-ext/object/valid-callable')
|
||||
, hasListeners = require('event-emitter/has-listeners')
|
||||
|
||||
, serialize0 = function () { return ''; }
|
||||
, serialize1 = function (args) { return args[0]; }
|
||||
|
||||
, apply = Function.prototype.apply, call = Function.prototype.call
|
||||
, serializeN;
|
||||
|
||||
serializeN = function (args) {
|
||||
var id = '', i, length = args.length;
|
||||
if (length) {
|
||||
id += args[i = 0];
|
||||
while (--length) id += '\u0001' + args[++i];
|
||||
} else {
|
||||
id = '\u0002';
|
||||
}
|
||||
return id;
|
||||
};
|
||||
|
||||
module.exports = require('./_base')(function (conf, length, options) {
|
||||
var get, cache = conf.cache = {}, fn
|
||||
, hitListeners, initListeners, purgeListeners, serialize;
|
||||
|
||||
if (options.serialize) {
|
||||
serialize = callable(options.serialize);
|
||||
get = conf.get = function (args) { return serialize.apply(this, args); };
|
||||
} else if (length === 1) {
|
||||
get = conf.get = serialize1;
|
||||
} else if (length === false) {
|
||||
get = conf.get = serializeN;
|
||||
} else if (length) {
|
||||
get = conf.get = function (args) {
|
||||
var id = String(args[0]), i = 0, l = length;
|
||||
while (--l) { id += '\u0001' + args[++i]; }
|
||||
return id;
|
||||
};
|
||||
} else {
|
||||
get = conf.get = serialize0;
|
||||
}
|
||||
|
||||
conf.memoized = (length === 1) ? function (id) {
|
||||
var value;
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
if (hitListeners) conf.emit('hit', id, arguments, this);
|
||||
return cache[id];
|
||||
}
|
||||
if (arguments.length === 1) value = call.call(fn, this, id);
|
||||
else value = apply.call(fn, this, arguments);
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
cache[id] = value;
|
||||
if (initListeners) conf.emit('init', id);
|
||||
return value;
|
||||
} : function () {
|
||||
var id = get(arguments), value;
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
if (hitListeners) conf.emit('hit', id, arguments, this);
|
||||
return cache[id];
|
||||
}
|
||||
value = apply.call(conf.fn, this, arguments);
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
cache[id] = value;
|
||||
if (initListeners) conf.emit('init', id);
|
||||
return value;
|
||||
};
|
||||
|
||||
conf.clear = function (id) {
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
if (purgeListeners) conf.emit('purge', id);
|
||||
delete cache[id];
|
||||
}
|
||||
};
|
||||
conf.clearAll = function () { cache = conf.cache = {}; };
|
||||
|
||||
conf.once('ready', function () {
|
||||
fn = conf.fn;
|
||||
hitListeners = hasListeners(conf, 'hit');
|
||||
initListeners = hasListeners(conf, 'init');
|
||||
purgeListeners = hasListeners(conf, 'purge');
|
||||
});
|
||||
});
|
||||
1
lib/registered-extensions.js
Normal file
1
lib/registered-extensions.js
Normal file
@@ -0,0 +1 @@
|
||||
'use strict';
|
||||
246
lib/regular.js
246
lib/regular.js
@@ -1,246 +0,0 @@
|
||||
// Memoize working in object mode (supports any type of arguments)
|
||||
|
||||
'use strict';
|
||||
|
||||
var customError = require('es5-ext/error/custom')
|
||||
, indexOf = require('es5-ext/array/#/e-index-of')
|
||||
, hasListeners = require('event-emitter/has-listeners')
|
||||
|
||||
, apply = Function.prototype.apply;
|
||||
|
||||
// Results are saved internally within array matrix:
|
||||
// [0] -> Result of calling function with no arguments
|
||||
// [1] -> Matrix that keeps results when function is called with one argument
|
||||
// [1][0] -> Array of arguments with which
|
||||
// function have been called
|
||||
// [1][1] -> Array of results that matches [1][0] array
|
||||
// [2] -> Matrix that keeps results when function is called with two arguments
|
||||
// [2][0] -> Array of first (of two) arguments with which
|
||||
// function have been called
|
||||
// [2][1] -> Matrixes that keeps results for two arguments function calls
|
||||
// Each matrix matches first argument found in [2][0]
|
||||
// [2][1][x][0] -> Array of second arguments with which
|
||||
// function have been called.
|
||||
// [2][1][x][1] -> Array of results that matches [2][1][x][0]
|
||||
// arguments array
|
||||
// ...and so on
|
||||
module.exports = require('./_base')(function (conf, length) {
|
||||
var map, map1, map2, get, set, clear, count, fn
|
||||
, hitListeners, initListeners, purgeListeners
|
||||
, cache = conf.cache = {}, argsCache;
|
||||
|
||||
if (length === 0) {
|
||||
map = null;
|
||||
get = conf.get = function () { return map; };
|
||||
set = function () { return ((map = 1)); };
|
||||
clear = function () { map = null; };
|
||||
conf.clearAll = function () {
|
||||
map = null;
|
||||
cache = conf.cache = {};
|
||||
};
|
||||
} else {
|
||||
count = 0;
|
||||
if (length === 1) {
|
||||
map1 = [];
|
||||
map2 = [];
|
||||
get = conf.get = function (args) {
|
||||
var index = indexOf.call(map1, args[0]);
|
||||
return (index === -1) ? null : map2[index];
|
||||
};
|
||||
set = function (args) {
|
||||
map1.push(args[0]);
|
||||
map2.push(++count);
|
||||
return count;
|
||||
};
|
||||
clear = function (id) {
|
||||
var index = indexOf.call(map2, id);
|
||||
if (index !== -1) {
|
||||
map1.splice(index, 1);
|
||||
map2.splice(index, 1);
|
||||
}
|
||||
};
|
||||
conf.clearAll = function () {
|
||||
map1 = [];
|
||||
map2 = [];
|
||||
cache = conf.cache = {};
|
||||
};
|
||||
} else if (length === false) {
|
||||
map = [];
|
||||
argsCache = {};
|
||||
get = conf.get = function (args) {
|
||||
var index = 0, set = map, i, length = args.length;
|
||||
if (length === 0) return set[length] || null;
|
||||
if ((set = set[length])) {
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
return set[1][i] || null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
set = function (args) {
|
||||
var index = 0, set = map, i, length = args.length;
|
||||
if (length === 0) {
|
||||
set[length] = ++count;
|
||||
} else {
|
||||
if (!set[length]) {
|
||||
set[length] = [[], []];
|
||||
}
|
||||
set = set[length];
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
set[1].push([[], []]);
|
||||
}
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
}
|
||||
set[1][i] = ++count;
|
||||
}
|
||||
argsCache[count] = args;
|
||||
return count;
|
||||
};
|
||||
clear = function (id) {
|
||||
var index = 0, set = map, i, args = argsCache[id], length = args.length
|
||||
, path = [];
|
||||
if (length === 0) {
|
||||
delete set[length];
|
||||
} else if ((set = set[length])) {
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
path.push(set, i);
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
id = set[1][i];
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
while (!set[0].length && path.length) {
|
||||
i = path.pop();
|
||||
set = path.pop();
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
}
|
||||
}
|
||||
delete argsCache[id];
|
||||
};
|
||||
conf.clearAll = function () {
|
||||
map = [];
|
||||
cache = conf.cache = {};
|
||||
argsCache = {};
|
||||
};
|
||||
} else {
|
||||
map = [[], []];
|
||||
argsCache = {};
|
||||
get = conf.get = function (args) {
|
||||
var index = 0, set = map, i;
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) return null;
|
||||
return set[1][i] || null;
|
||||
};
|
||||
set = function (args) {
|
||||
var index = 0, set = map, i;
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
set[1].push([[], []]);
|
||||
}
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = set[0].push(args[index]) - 1;
|
||||
}
|
||||
set[1][i] = ++count;
|
||||
argsCache[count] = args;
|
||||
return count;
|
||||
};
|
||||
clear = function (id) {
|
||||
var index = 0, set = map, i, path = [], args = argsCache[id];
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
path.push(set, i);
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
id = set[1][i];
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
while (!set[0].length && path.length) {
|
||||
i = path.pop();
|
||||
set = path.pop();
|
||||
set[0].splice(i, 1);
|
||||
set[1].splice(i, 1);
|
||||
}
|
||||
delete argsCache[id];
|
||||
};
|
||||
conf.clearAll = function () {
|
||||
map = [[], []];
|
||||
cache = conf.cache = {};
|
||||
argsCache = {};
|
||||
};
|
||||
}
|
||||
}
|
||||
conf.memoized = function () {
|
||||
var id = get(arguments), value;
|
||||
if (id != null) {
|
||||
if (hitListeners) conf.emit('hit', id, arguments, this);
|
||||
return cache[id];
|
||||
}
|
||||
value = apply.call(fn, this, arguments);
|
||||
id = get(arguments);
|
||||
if (id != null) {
|
||||
throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
id = set(arguments);
|
||||
cache[id] = value;
|
||||
if (initListeners) conf.emit('init', id);
|
||||
return value;
|
||||
};
|
||||
conf.clear = function (id) {
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
if (purgeListeners) conf.emit('purge', id);
|
||||
clear(id);
|
||||
delete cache[id];
|
||||
}
|
||||
};
|
||||
|
||||
conf.once('ready', function () {
|
||||
fn = conf.fn;
|
||||
hitListeners = hasListeners(conf, 'hit');
|
||||
initListeners = hasListeners(conf, 'init');
|
||||
purgeListeners = hasListeners(conf, 'purge');
|
||||
});
|
||||
});
|
||||
15
lib/resolve-length.js
Normal file
15
lib/resolve-length.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var toPosInt = require('es5-ext/number/to-pos-integer');
|
||||
|
||||
module.exports = function (optsLength, fnLength, isAsync) {
|
||||
var length;
|
||||
if (isNaN(optsLength)) {
|
||||
length = fnLength;
|
||||
if (!(length >= 0)) return 1;
|
||||
if (isAsync && length) return length - 1;
|
||||
return length;
|
||||
}
|
||||
if (optsLength === false) return false;
|
||||
return toPosInt(optsLength);
|
||||
};
|
||||
Reference in New Issue
Block a user