mirror of
https://github.com/BreizhHardware/memoizee.git
synced 2026-01-18 16:37:21 +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:
8
.lint
8
.lint
@@ -1,10 +1,9 @@
|
||||
@root
|
||||
|
||||
module
|
||||
es5
|
||||
|
||||
indent 2
|
||||
maxlen 80
|
||||
maxlen 100
|
||||
tabs
|
||||
|
||||
ass
|
||||
@@ -14,8 +13,7 @@ nomen
|
||||
./lib/_base.js
|
||||
bitwise
|
||||
|
||||
./lib/ext/max-age.js
|
||||
bitwise
|
||||
./ext/max-age.js
|
||||
predef+ setTimeout, clearTimeout
|
||||
|
||||
./lib/ext/max.js
|
||||
@@ -25,8 +23,6 @@ predef+ setTimeout, clearTimeout
|
||||
|
||||
|
||||
./test/index.js
|
||||
predef+ setTimeout
|
||||
|
||||
./test/ext/max-age.js
|
||||
predef+ setTimeout
|
||||
|
||||
|
||||
1
.testignore
Normal file
1
.testignore
Normal file
@@ -0,0 +1 @@
|
||||
/benchmark
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
var forEach = require('es5-ext/object/for-each')
|
||||
, pad = require('es5-ext/string/#/pad')
|
||||
, memoizee = require('../lib')
|
||||
, memoizee = require('..')
|
||||
, underscore = require('underscore').memoize
|
||||
, lodash = require('lodash').memoize
|
||||
, lruCache = require('lru-cache')
|
||||
|
||||
140
ext/async.js
Normal file
140
ext/async.js
Normal file
@@ -0,0 +1,140 @@
|
||||
// Support for asynchronous functions
|
||||
|
||||
'use strict';
|
||||
|
||||
var aFrom = require('es5-ext/array/from')
|
||||
, mixin = require('es5-ext/object/mixin')
|
||||
, defineLength = require('es5-ext/function/_define-length')
|
||||
, nextTick = require('next-tick')
|
||||
|
||||
, slice = Array.prototype.slice
|
||||
, apply = Function.prototype.apply, create = Object.create
|
||||
, hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
require('../lib/registered-extensions').async = function (tbi, conf) {
|
||||
var waiting = create(null), cache = create(null)
|
||||
, base = conf.memoized, original = conf.original
|
||||
, currentCallback, currentContext, currentArgs;
|
||||
|
||||
// Initial
|
||||
conf.memoized = defineLength(function (arg) {
|
||||
var args = arguments, last = args[args.length - 1];
|
||||
if (typeof last === 'function') {
|
||||
currentCallback = last;
|
||||
args = slice.call(args, 0, -1);
|
||||
}
|
||||
return base.apply(currentContext = this, currentArgs = args);
|
||||
}, base);
|
||||
try { mixin(conf.memoized, base); } catch (ignore) {}
|
||||
|
||||
// From cache (sync)
|
||||
conf.on('get', function (id) {
|
||||
var cb, context, args;
|
||||
if (!currentCallback) return;
|
||||
|
||||
// Unresolved
|
||||
if (waiting[id]) {
|
||||
if (typeof waiting[id] === 'function') {
|
||||
waiting[id] = [waiting[id], currentCallback];
|
||||
} else {
|
||||
waiting[id].push(currentCallback);
|
||||
}
|
||||
currentCallback = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolved, assure next tick invocation
|
||||
cb = currentCallback;
|
||||
context = currentContext;
|
||||
args = currentArgs;
|
||||
currentCallback = currentContext = currentArgs = null;
|
||||
nextTick(function () {
|
||||
var data;
|
||||
if (hasOwnProperty.call(cache, id)) {
|
||||
data = cache[id];
|
||||
conf.emit('getasync', id);
|
||||
apply.call(cb, data.context, data.args);
|
||||
} else {
|
||||
// Purged in a meantime, we shouldn't rely on cached value, recall
|
||||
currentCallback = cb;
|
||||
currentContext = context;
|
||||
currentArgs = args;
|
||||
base.apply(context, args);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Not from cache
|
||||
conf.original = function () {
|
||||
var args, cb, origCb, result;
|
||||
if (!currentCallback) return apply.call(original, this, arguments);
|
||||
args = aFrom(arguments);
|
||||
cb = function self(err) {
|
||||
var cb, args, id = self.id;
|
||||
if (id == null) {
|
||||
// Shouldn't happen, means async callback was called sync way
|
||||
nextTick(apply.bind(self, this, arguments));
|
||||
return;
|
||||
}
|
||||
delete self.id;
|
||||
cb = waiting[id];
|
||||
delete waiting[id];
|
||||
args = aFrom(arguments);
|
||||
if (conf.has(id)) {
|
||||
if (err) {
|
||||
conf.delete(id);
|
||||
} else {
|
||||
cache[id] = { context: this, args: args };
|
||||
conf.emit('setasync', id, (typeof cb === 'function') ? 1 : cb.length);
|
||||
}
|
||||
}
|
||||
if (typeof cb === 'function') {
|
||||
result = apply.call(cb, this, args);
|
||||
} else {
|
||||
cb.forEach(function (cb) {
|
||||
result = apply.call(cb, this, args);
|
||||
}, this);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
origCb = currentCallback;
|
||||
currentCallback = currentContext = currentArgs = null;
|
||||
args.push(cb);
|
||||
result = apply.call(original, this, args);
|
||||
cb.cb = origCb;
|
||||
currentCallback = cb;
|
||||
return result;
|
||||
};
|
||||
|
||||
// After not from cache call
|
||||
conf.on('set', function (id) {
|
||||
if (!currentCallback) {
|
||||
conf.delete(id);
|
||||
return;
|
||||
}
|
||||
waiting[id] = currentCallback.cb;
|
||||
delete currentCallback.cb;
|
||||
currentCallback.id = id;
|
||||
currentCallback = null;
|
||||
});
|
||||
|
||||
// On delete
|
||||
conf.on('delete', function (id) {
|
||||
var result;
|
||||
// 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 (hasOwnProperty.call(waiting, id)) return;
|
||||
if (!cache[id]) return;
|
||||
result = cache[id];
|
||||
delete cache[id];
|
||||
conf.emit('deleteasync', id, result);
|
||||
});
|
||||
|
||||
// On clear
|
||||
conf.on('clear', function () {
|
||||
var oldCache = cache;
|
||||
cache = create(null);
|
||||
conf.emit('clearasync', oldCache);
|
||||
});
|
||||
};
|
||||
27
ext/dispose.js
Normal file
27
ext/dispose.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// Call dispose callback on each cache purge
|
||||
|
||||
'use strict';
|
||||
|
||||
var callable = require('es5-ext/object/valid-callable')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, extensions = require('../lib/registered-extensions')
|
||||
|
||||
, slice = Array.prototype.slice, apply = Function.prototype.apply;
|
||||
|
||||
extensions.dispose = function (dispose, conf, options) {
|
||||
var del;
|
||||
callable(dispose);
|
||||
if (options.async && extensions.async) {
|
||||
conf.on('deleteasync', del = function (id, result) {
|
||||
apply.call(dispose, null, slice.call(result.args, 1));
|
||||
});
|
||||
conf.on('clearasync', function (cache) {
|
||||
forEach(cache, function (result, id) { del(id, result); });
|
||||
});
|
||||
return;
|
||||
}
|
||||
conf.on('delete', del = function (id, result) { dispose(result); });
|
||||
conf.on('clear', function (cache) {
|
||||
forEach(cache, function (result, id) { del(id, result); });
|
||||
});
|
||||
};
|
||||
64
ext/max-age.js
Normal file
64
ext/max-age.js
Normal file
@@ -0,0 +1,64 @@
|
||||
// Timeout cached values
|
||||
|
||||
'use strict';
|
||||
|
||||
var forEach = require('es5-ext/object/for-each')
|
||||
, timeout = require('timers-ext/valid-timeout')
|
||||
, extensions = require('../lib/registered-extensions')
|
||||
|
||||
, max = Math.max, min = Math.min, create = Object.create;
|
||||
|
||||
extensions.maxAge = function (maxAge, conf, options) {
|
||||
var timeouts, postfix, preFetchAge, preFetchTimeouts;
|
||||
|
||||
maxAge = timeout(maxAge);
|
||||
if (!maxAge) return;
|
||||
|
||||
timeouts = create(null);
|
||||
postfix = (options.async && extensions.async) ? 'async' : '';
|
||||
conf.on('set' + postfix, function (id) {
|
||||
timeouts[id] = setTimeout(function () { conf.clear(id); }, maxAge);
|
||||
if (!preFetchTimeouts) return;
|
||||
if (preFetchTimeouts[id]) clearTimeout(preFetchTimeouts[id]);
|
||||
preFetchTimeouts[id] = setTimeout(function () {
|
||||
delete preFetchTimeouts[id];
|
||||
}, preFetchAge);
|
||||
});
|
||||
conf.on('delete' + postfix, function (id) {
|
||||
clearTimeout(timeouts[id]);
|
||||
delete timeouts[id];
|
||||
if (!preFetchTimeouts) return;
|
||||
clearTimeout(preFetchTimeouts[id]);
|
||||
delete preFetchTimeouts[id];
|
||||
});
|
||||
|
||||
if (options.preFetch) {
|
||||
if ((options.preFetch === true) || isNaN(options.preFetch)) {
|
||||
preFetchAge = 0.333;
|
||||
} else {
|
||||
preFetchAge = max(min(Number(options.preFetch), 1), 0);
|
||||
}
|
||||
if (preFetchAge) {
|
||||
preFetchTimeouts = {};
|
||||
preFetchAge = (1 - preFetchAge) * maxAge;
|
||||
conf.on('get' + postfix, function (id, args, context) {
|
||||
if (!preFetchTimeouts[id]) {
|
||||
preFetchTimeouts[id] = setTimeout(function () {
|
||||
delete preFetchTimeouts[id];
|
||||
conf.delete(id);
|
||||
conf.memoized.apply(context, args);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
conf.on('clear' + postfix, function () {
|
||||
forEach(timeouts, function (id) { clearTimeout(id); });
|
||||
timeouts = {};
|
||||
if (preFetchTimeouts) {
|
||||
forEach(preFetchTimeouts, function (id) { clearTimeout(id); });
|
||||
preFetchTimeouts = {};
|
||||
}
|
||||
});
|
||||
};
|
||||
26
ext/max.js
Normal file
26
ext/max.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// Limit cache size, LRU (least recently used) algorithm.
|
||||
|
||||
'use strict';
|
||||
|
||||
var toPosInteger = require('es5-ext/number/to-pos-integer')
|
||||
, lruQueue = require('lru-queue')
|
||||
, extensions = require('../lib/registered-extensions');
|
||||
|
||||
extensions.max = function (max, conf, options) {
|
||||
var postfix, queue, hit;
|
||||
|
||||
max = toPosInteger(max);
|
||||
if (!max) return;
|
||||
|
||||
queue = lruQueue(max);
|
||||
postfix = (options.async && extensions.async) ? 'async' : '';
|
||||
|
||||
conf.on('set' + postfix, hit = function (id) {
|
||||
id = queue.hit(id);
|
||||
if (id === undefined) return;
|
||||
conf.delete(id);
|
||||
});
|
||||
conf.on('get' + postfix, hit);
|
||||
conf.on('delete' + postfix, queue.delete);
|
||||
conf.on('clear' + postfix, queue.clear);
|
||||
};
|
||||
39
ext/ref-counter.js
Normal file
39
ext/ref-counter.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// Reference counter, useful for garbage collector like functionality
|
||||
|
||||
'use strict';
|
||||
|
||||
var d = require('d')
|
||||
, extensions = require('../lib/registered-extensions')
|
||||
|
||||
, create = Object.create, defineProperties = Object.defineProperties;
|
||||
|
||||
extensions.refCounter = function (ignore, conf, options) {
|
||||
var cache, postfix;
|
||||
|
||||
cache = create(null);
|
||||
postfix = (options.async && extensions.async) ? 'async' : '';
|
||||
|
||||
conf.on('set' + postfix, function (id, length) { cache[id] = length || 1; });
|
||||
conf.on('get' + postfix, function (id) { ++cache[id]; });
|
||||
conf.on('delete' + postfix, function (id) { delete cache[id]; });
|
||||
conf.on('clear' + postfix, function () { cache = {}; });
|
||||
|
||||
defineProperties(conf.memoized, {
|
||||
deleteRef: d(function () {
|
||||
var id = conf.get(arguments);
|
||||
if (id === null) return null;
|
||||
if (!cache[id]) return null;
|
||||
if (!--cache[id]) {
|
||||
conf.delete(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
getRefCount: d(function () {
|
||||
var id = conf.get(arguments);
|
||||
if (id === null) return 0;
|
||||
if (!cache[id]) return 0;
|
||||
return cache[id];
|
||||
})
|
||||
});
|
||||
};
|
||||
35
index.js
Normal file
35
index.js
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
var normalizeOpts = require('es5-ext/object/normalize-options')
|
||||
, resolveLength = require('./lib/resolve-length')
|
||||
, plain = require('./plain');
|
||||
|
||||
module.exports = function (fn/*, options*/) {
|
||||
var options = normalizeOpts(arguments[1]), length;
|
||||
|
||||
if (!options.normalizer && !options.serialize) {
|
||||
length = options.length = resolveLength(options.length, fn.length, options.async);
|
||||
if (length === 0) {
|
||||
options.normalizer = require('./lib/normalizers/0');
|
||||
} else if (options.primitive) {
|
||||
if (length === false) {
|
||||
options.normalizer = require('./lib/normalizers/primitive');
|
||||
} else if (length > 1) {
|
||||
options.normalizer = require('./lib/normalizers/get-primitive-fixed')(length);
|
||||
}
|
||||
} else {
|
||||
if (length === false) options.normalizer = require('./lib/normalizers/get-regular')();
|
||||
else if (length === 1) options.normalizer = require('./lib/normalizers/get-regular-1')();
|
||||
else options.normalizer = require('./lib/normalizers/get-regular-fixed')(length);
|
||||
}
|
||||
}
|
||||
|
||||
// Assure extensions
|
||||
if (options.async) require('./ext/async');
|
||||
if (options.dispose) require('./ext/dispose');
|
||||
if (options.maxAge) require('./ext/max-age');
|
||||
if (options.max) require('./ext/max');
|
||||
if (options.refCounter) require('./ext/ref-counter');
|
||||
|
||||
return plain(fn, options);
|
||||
};
|
||||
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,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);
|
||||
};
|
||||
3
methods-plain.js
Normal file
3
methods-plain.js
Normal file
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./lib/methods')(require('./plain'));
|
||||
3
methods.js
Normal file
3
methods.js
Normal file
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./lib/methods')(require('./'));
|
||||
30
package.json
30
package.json
@@ -1,15 +1,8 @@
|
||||
{
|
||||
"name": "memoizee",
|
||||
"version": "0.3.0",
|
||||
"description": "Complete memoize/cache solution. Works with any type and length of function arguments",
|
||||
"main": "lib",
|
||||
"scripts": {
|
||||
"test": "node node_modules/tad/bin/tad lib"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/medikoo/memoize.git"
|
||||
},
|
||||
"description": "Memoize/cache",
|
||||
"author": "Mariusz Nowak <medikoo@medikoo.com> (http://www.medikoo.com/)",
|
||||
"keywords": [
|
||||
"memoize",
|
||||
"memoizer",
|
||||
@@ -26,22 +19,23 @@
|
||||
"garbage",
|
||||
"collector"
|
||||
],
|
||||
"bugs": {
|
||||
"email": "medikoo+memoize@medikoo.com",
|
||||
"url": "https://github.com/medikoo/memoize/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/medikoo/memoize.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"d": "~0.1.1",
|
||||
"es5-ext": "~0.10.2",
|
||||
"event-emitter": "0.3.x",
|
||||
"next-tick": "~0.2.2"
|
||||
"event-emitter": "~0.3.1",
|
||||
"lru-queue": "0.1.x",
|
||||
"next-tick": "~0.2.2",
|
||||
"timers-ext": "0.1.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tad": "~0.1.21"
|
||||
},
|
||||
"author": "Mariusz Nowak <medikoo+memoize@medikoo.com> (http://www.medikoo.com/)",
|
||||
"scripts": {
|
||||
"test": "node node_modules/tad/bin/tad"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
37
plain.js
Normal file
37
plain.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// To be used internally, memoize factory
|
||||
|
||||
'use strict';
|
||||
|
||||
var callable = require('es5-ext/object/valid-callable')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, extensions = require('./lib/registered-extensions')
|
||||
, configure = require('./lib/configure-map')
|
||||
, resolveLength = require('./lib/resolve-length')
|
||||
|
||||
, hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
module.exports = function self(fn/*, options */) {
|
||||
var options, length, conf;
|
||||
|
||||
callable(fn);
|
||||
options = Object(arguments[1]);
|
||||
|
||||
// Do not memoize already memoized function
|
||||
if (hasOwnProperty.call(fn, '__memoized__') && !options.force) return fn;
|
||||
|
||||
// Resolve length;
|
||||
length = resolveLength(options.length, fn.length, options.async && extensions.async);
|
||||
|
||||
// Configure cache map
|
||||
conf = configure(fn, length, options);
|
||||
|
||||
// Bind eventual extensions
|
||||
forEach(extensions, function (fn, name) {
|
||||
if (options[name]) fn(options[name], conf, options);
|
||||
});
|
||||
|
||||
if (self.__profiler__) self.__profiler__(conf);
|
||||
|
||||
conf.updateEnv();
|
||||
return conf.memoized;
|
||||
};
|
||||
@@ -5,18 +5,16 @@
|
||||
var partial = require('es5-ext/function/#/partial')
|
||||
, forEach = require('es5-ext/object/for-each')
|
||||
, pad = require('es5-ext/string/#/pad')
|
||||
, memoize = require('./plain')
|
||||
|
||||
, max = Math.max
|
||||
, stats = exports.statistics = {};
|
||||
|
||||
, stats = exports.statistics = {}, ext;
|
||||
|
||||
require('../_base').ext.profile = ext = function (conf) {
|
||||
Object.defineProperty(memoize, '__profiler__', function (conf) {
|
||||
var id, stack, data;
|
||||
stack = (new Error()).stack;
|
||||
if (!stack.split('\n').slice(3).some(function (line) {
|
||||
if (!stack || !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;
|
||||
@@ -25,15 +23,12 @@ require('../_base').ext.profile = ext = function (conf) {
|
||||
id = 'unknown';
|
||||
}
|
||||
|
||||
if (!stats[id]) {
|
||||
stats[id] = { initial: 0, cached: 0 };
|
||||
}
|
||||
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;
|
||||
conf.on('set', function () { ++data.initial; });
|
||||
conf.on('get', function () { ++data.cached; });
|
||||
});
|
||||
|
||||
exports.log = function () {
|
||||
var initial, cached, ordered, ipad, cpad, ppad, toPrc, log;
|
||||
@@ -1,18 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (t, a) {
|
||||
var mfn, m = t(function (conf) {
|
||||
conf.get = function () { return 'test'; };
|
||||
conf.memoized = function (x, y, z) { return conf.fn(z, y, x); };
|
||||
conf.clear = function () {};
|
||||
conf.clearAll = function () {};
|
||||
});
|
||||
|
||||
a(typeof m, 'function', "Returns");
|
||||
mfn = m(function (x, y, z) { return [x, y, z]; });
|
||||
a(typeof mfn, 'function', "Generates");
|
||||
a.deep(mfn(3, 7, 11), [11, 7, 3], "Works");
|
||||
|
||||
a(mfn.memoized, true, "Marked as memoized");
|
||||
a(m(mfn), mfn, "Do not memoize memoized");
|
||||
};
|
||||
@@ -1,10 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
var memoize = require('../..')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
require('../../lib/ext/dispose');
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
"Regular": {
|
||||
@@ -58,7 +56,7 @@ module.exports = function () {
|
||||
a(i, 2, "Init Called #2");
|
||||
a(invoked, 7, "Cb Called #2");
|
||||
|
||||
mfn.clear(3, 7);
|
||||
mfn.delete(3, 7);
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
@@ -70,8 +68,8 @@ module.exports = function () {
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Init After clear");
|
||||
a(invoked, 9, "Cb After clear");
|
||||
a(i, 3, "Init After delete");
|
||||
a(invoked, 9, "Cb After delete");
|
||||
d();
|
||||
});
|
||||
});
|
||||
@@ -164,7 +162,7 @@ module.exports = function () {
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
mfn.clear(3, 7);
|
||||
mfn.delete(3, 7);
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
@@ -174,7 +172,7 @@ module.exports = function () {
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Call After clear");
|
||||
a(i, 3, "Call After delete");
|
||||
d();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
var memoize = require('../..')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
module.exports = function () {
|
||||
@@ -15,15 +15,15 @@ module.exports = function () {
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
|
||||
x = {};
|
||||
@@ -31,35 +31,12 @@ module.exports = function () {
|
||||
mfn = memoize(function () { return x; },
|
||||
{ dispose: function (val) { invoked = val; } });
|
||||
|
||||
mfn.clear();
|
||||
a(invoked, false, "No args: Post invalid clear");
|
||||
mfn.delete();
|
||||
a(invoked, false, "No args: Post invalid delete");
|
||||
mfn();
|
||||
a(invoked, false, "No args: Post cache");
|
||||
mfn.clear();
|
||||
a(invoked, x, "No args: Pre clear");
|
||||
},
|
||||
"Method": function (a) {
|
||||
var fn, value = [];
|
||||
fn = function (x, y) { return x + y; };
|
||||
Object.defineProperties(value, memoize(fn, {
|
||||
method: 'mfn',
|
||||
dispose: function (val) { this.push(val); }
|
||||
}));
|
||||
|
||||
value.mfn(3, 7);
|
||||
value.mfn(5, 8);
|
||||
value.mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
value.mfn.clear(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value.length = 0;
|
||||
value.mfn.clear(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value.length = 0;
|
||||
value.mfn(77, 11);
|
||||
value.mfn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
mfn.delete();
|
||||
a(invoked, x, "No args: Pre delete");
|
||||
},
|
||||
"Ref counter": function (a) {
|
||||
var mfn, fn, value = [];
|
||||
@@ -72,17 +49,17 @@ module.exports = function () {
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn(5, 8);
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clearRef(12, 4);
|
||||
mfn.deleteRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
@@ -99,15 +76,15 @@ module.exports = function () {
|
||||
mfn(5, 8, function () {
|
||||
mfn(12, 4, function () {
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11, function () {
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
d();
|
||||
});
|
||||
@@ -126,15 +103,15 @@ module.exports = function () {
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Ref counter": function (a) {
|
||||
@@ -148,17 +125,17 @@ module.exports = function () {
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn(5, 8);
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clearRef(12, 4);
|
||||
mfn.deleteRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
@@ -175,15 +152,15 @@ module.exports = function () {
|
||||
mfn(5, 8, function () {
|
||||
mfn(12, 4, function () {
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11, function () {
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
d();
|
||||
});
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
var memoize = require('../..')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
require('../../ext/async');
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
"Regular": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
var memoize = require('../..')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
module.exports = function () {
|
||||
@@ -31,31 +31,31 @@ module.exports = function () {
|
||||
a(mfn(5, 8), 13, "Result B #3");
|
||||
a(i, 3, "Called B #3");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #1"); // Clear 12, 4
|
||||
a(mfn(77, 11), 88, "Result D #1"); // Delete 12, 4
|
||||
a(i, 4, "Called D #1");
|
||||
a(mfn(5, 8), 13, "Result B #4");
|
||||
a(i, 4, "Called B #4");
|
||||
a(mfn(12, 4), 16, "Result C #2"); // Clear 3, 7
|
||||
a(mfn(12, 4), 16, "Result C #2"); // Delete 3, 7
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7), 10, "Result #5"); // Clear 77, 11
|
||||
a(mfn(3, 7), 10, "Result #5"); // Delete 77, 11
|
||||
a(i, 6, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Clear 5, 8
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Delete 5, 8
|
||||
a(i, 7, "Called D #2");
|
||||
a(mfn(12, 4), 16, "Result C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8), 13, "Result B #5"); // Clear 3, 7
|
||||
a(mfn(5, 8), 13, "Result B #5"); // Delete 3, 7
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
@@ -141,13 +141,13 @@ module.exports = function () {
|
||||
"Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
@@ -207,31 +207,31 @@ module.exports = function () {
|
||||
a(mfn(5, 8), 13, "Result B #3");
|
||||
a(i, 3, "Called B #3");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #1"); // Clear 12, 4
|
||||
a(mfn(77, 11), 88, "Result D #1"); // Delete 12, 4
|
||||
a(i, 4, "Called D #1");
|
||||
a(mfn(5, 8), 13, "Result B #4");
|
||||
a(i, 4, "Called B #4");
|
||||
a(mfn(12, 4), 16, "Result C #2"); // Clear 3, 7
|
||||
a(mfn(12, 4), 16, "Result C #2"); // Delete 3, 7
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7), 10, "Result #5"); // Clear 77, 11
|
||||
a(mfn(3, 7), 10, "Result #5"); // Delete 77, 11
|
||||
a(i, 6, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Clear 5, 8
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Delete 5, 8
|
||||
a(i, 7, "Called D #2");
|
||||
a(mfn(12, 4), 16, "Result C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8), 13, "Result B #5"); // Clear 3, 7
|
||||
a(mfn(5, 8), 13, "Result B #5"); // Delete 3, 7
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
@@ -317,13 +317,13 @@ module.exports = function () {
|
||||
"Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib');
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
"No descriptor": function (a) {
|
||||
var x = {}, i = 0, fn = function () {
|
||||
++i;
|
||||
return this;
|
||||
};
|
||||
|
||||
Object.defineProperties(x, memoize(fn, { method: 'foo' }));
|
||||
a(x.foo(), x, "Context");
|
||||
a(x.foo(), x, "Method");
|
||||
a(i, 1, "Cached");
|
||||
},
|
||||
"Descriptor": function (a) {
|
||||
var x = {}, i = 0, fn = function () {
|
||||
++i;
|
||||
return this;
|
||||
};
|
||||
|
||||
Object.defineProperties(x, memoize(fn,
|
||||
{ method: 'foo', writable: false }));
|
||||
a(x.foo(), x, "Context");
|
||||
a.deep(Object.getOwnPropertyDescriptor(x, 'foo'),
|
||||
{ enumerable: false, configurable: true, writable: false,
|
||||
value: x.foo });
|
||||
a(x.foo(), x, "Method");
|
||||
a(i, 1, "Cached");
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
var memoize = require('../..')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
module.exports = function () {
|
||||
@@ -8,18 +8,18 @@ module.exports = function () {
|
||||
"Regular": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn;
|
||||
mfn = memoize(fn, { refCounter: true });
|
||||
a(mfn.clearRef(3, 5, 7), null, "Clear before");
|
||||
a(mfn.deleteRef(3, 5, 7), null, "Delete before");
|
||||
a(mfn(3, 5, 7), 15, "Initial");
|
||||
a(mfn(3, 5, 7), 15, "Cache");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #1");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #1");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #2");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #2");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #3");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #3");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 1, "Not cleared");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #4");
|
||||
a(mfn.clearRef(3, 5, 7), true, "Clear final");
|
||||
a(i, 1, "Not deleteed");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #4");
|
||||
a(mfn.deleteRef(3, 5, 7), true, "Delete final");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Restarted");
|
||||
mfn(3, 5, 7);
|
||||
@@ -37,7 +37,7 @@ module.exports = function () {
|
||||
|
||||
mfn = memoize(fn, { async: true, refCounter: true });
|
||||
|
||||
a(mfn.clearRef(3, 7), null, "Clear ref before");
|
||||
a(mfn.deleteRef(3, 7), null, "Delete ref before");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
@@ -68,10 +68,10 @@ module.exports = function () {
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #1");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #2");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #3");
|
||||
a(mfn.clearRef(3, 7), true, "Clear ref Final");
|
||||
a(mfn.deleteRef(3, 7), false, "Delete ref #1");
|
||||
a(mfn.deleteRef(3, 7), false, "Delete ref #2");
|
||||
a(mfn.deleteRef(3, 7), false, "Delete ref #3");
|
||||
a(mfn.deleteRef(3, 7), true, "Delete ref Final");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
@@ -81,7 +81,7 @@ module.exports = function () {
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Call After clear");
|
||||
a(i, 3, "Call After delete");
|
||||
d();
|
||||
});
|
||||
});
|
||||
@@ -90,18 +90,18 @@ module.exports = function () {
|
||||
"Primitive": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn;
|
||||
mfn = memoize(fn, { primitive: true, refCounter: true });
|
||||
a(mfn.clearRef(3, 5, 7), null, "Clear before");
|
||||
a(mfn.deleteRef(3, 5, 7), null, "Delete before");
|
||||
a(mfn(3, 5, 7), 15, "Initial");
|
||||
a(mfn(3, 5, 7), 15, "Cache");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #1");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #1");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #2");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #2");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #3");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #3");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 1, "Not cleared");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #4");
|
||||
a(mfn.clearRef(3, 5, 7), true, "Clear final");
|
||||
a(i, 1, "Not deleteed");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Delete #4");
|
||||
a(mfn.deleteRef(3, 5, 7), true, "Delete final");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Restarted");
|
||||
mfn(3, 5, 7);
|
||||
@@ -119,7 +119,7 @@ module.exports = function () {
|
||||
|
||||
mfn = memoize(fn, { async: true, primitive: true, refCounter: true });
|
||||
|
||||
a(mfn.clearRef(3, 7), null, "Clear ref before");
|
||||
a(mfn.deleteRef(3, 7), null, "Delete ref before");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
@@ -150,10 +150,10 @@ module.exports = function () {
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #1");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #2");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #3");
|
||||
a(mfn.clearRef(3, 7), true, "Clear ref Final");
|
||||
a(mfn.deleteRef(3, 7), false, "Delete ref #1");
|
||||
a(mfn.deleteRef(3, 7), false, "Delete ref #2");
|
||||
a(mfn.deleteRef(3, 7), false, "Delete ref #3");
|
||||
a(mfn.deleteRef(3, 7), true, "Delete ref Final");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
@@ -163,7 +163,7 @@ module.exports = function () {
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Call After clear");
|
||||
a(i, 3, "Call After delete");
|
||||
d();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var aFrom = require('es5-ext/array/from')
|
||||
, memoize = require('../../lib');
|
||||
|
||||
module.exports = function (a) {
|
||||
return {
|
||||
"Original arguments": function (a) {
|
||||
var fn, mfn, x = {};
|
||||
fn = function (x, y) { x = y; return aFrom(mfn.args); };
|
||||
mfn = memoize(fn, { resolvers: [] });
|
||||
|
||||
a.deep(mfn(23, 'raz', x), [23, 'raz', x]);
|
||||
},
|
||||
"Resolvers": function () {
|
||||
var i = 0, fn, r;
|
||||
fn = memoize(function () { ++i; return arguments; },
|
||||
{ length: 3, resolvers: [Boolean, String] });
|
||||
return {
|
||||
"No args": function () {
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn()), [false, 'undefined'], "First");
|
||||
a(fn(), r, "Second");
|
||||
a(fn(), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Some Args": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn(0, 34, x, 45)), [false, '34', x, 45],
|
||||
"First");
|
||||
a(fn(0, 34, x, 22), r, "Second");
|
||||
a(fn(0, 34, x, false), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
return {
|
||||
"Other": function () {
|
||||
a.deep(aFrom(r = fn(1, 34, x, 34)),
|
||||
[true, '34', x, 34], "Second");
|
||||
a(fn(1, 34, x, 89), r, "Third");
|
||||
a(i, 2, "Called once");
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
156
test/index.js
156
test/index.js
@@ -91,8 +91,7 @@ module.exports = function (t, a) {
|
||||
};
|
||||
},
|
||||
"Serialize": function () {
|
||||
var i = 0, fn = function () { ++i; return join.call(arguments, '|'); }
|
||||
, mfn;
|
||||
var i = 0, fn = function () { ++i; return join.call(arguments, '|'); }, mfn;
|
||||
mfn = t(fn, { serialize: Boolean });
|
||||
a(mfn(false, 'raz'), 'false|raz', "#1");
|
||||
a(mfn(0, 'dwa'), 'false|raz', "#2");
|
||||
@@ -132,13 +131,6 @@ module.exports = function (t, a) {
|
||||
}
|
||||
};
|
||||
},
|
||||
"Original arguments": function (a) {
|
||||
var fn, mfn, x = {};
|
||||
fn = function (x, y) { x = y; return aFrom(mfn.args); };
|
||||
mfn = t(fn, { resolvers: [] });
|
||||
|
||||
a.deep(mfn(23, 'raz', x), [23, 'raz', x]);
|
||||
},
|
||||
"Resolvers": function () {
|
||||
var i = 0, fn, r;
|
||||
fn = t(function () { ++i; return arguments; },
|
||||
@@ -184,11 +176,11 @@ module.exports = function (t, a) {
|
||||
mfn = t(fn);
|
||||
mfn(1, x, 3);
|
||||
mfn(1, x, 4);
|
||||
mfn.clear(1, x, 4);
|
||||
mfn.delete(1, x, 4);
|
||||
mfn(1, x, 3);
|
||||
mfn(1, x, 3);
|
||||
a(i, 1, "Pre clear");
|
||||
mfn.clear(1, x, 3);
|
||||
mfn.delete(1, x, 3);
|
||||
mfn(1, x, 3);
|
||||
a(i, 2, "After clear");
|
||||
|
||||
@@ -198,7 +190,7 @@ module.exports = function (t, a) {
|
||||
mfn(1, x, 3);
|
||||
mfn();
|
||||
mfn();
|
||||
mfn.clear();
|
||||
mfn.delete();
|
||||
mfn(1, x, 3);
|
||||
a(i, 1, "Proper no arguments clear");
|
||||
},
|
||||
@@ -216,7 +208,7 @@ module.exports = function (t, a) {
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
a(i, 2, "Pre clear");
|
||||
fn.clearAll();
|
||||
fn.clear();
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
fn(1, x, 3);
|
||||
@@ -224,34 +216,6 @@ module.exports = function (t, a) {
|
||||
a(i, 4, "After clear");
|
||||
}
|
||||
},
|
||||
"Method": {
|
||||
"No descriptor": function (a) {
|
||||
var x = {}, i = 0, fn = function () {
|
||||
++i;
|
||||
return this;
|
||||
};
|
||||
|
||||
Object.defineProperties(x, t(fn, { method: 'foo' }));
|
||||
a(x.foo(), x, "Context");
|
||||
a(x.foo(), x, "Method");
|
||||
a(i, 1, "Cached");
|
||||
},
|
||||
"Descriptor": function (a) {
|
||||
var x = {}, i = 0, fn = function () {
|
||||
++i;
|
||||
return this;
|
||||
};
|
||||
|
||||
Object.defineProperties(x, t(fn,
|
||||
{ method: 'foo', writable: false }));
|
||||
a(x.foo(), x, "Context");
|
||||
a.deep(Object.getOwnPropertyDescriptor(x, 'foo'),
|
||||
{ enumerable: false, configurable: true, writable: false,
|
||||
value: x.foo });
|
||||
a(x.foo(), x, "Method");
|
||||
a(i, 1, "Cached");
|
||||
}
|
||||
},
|
||||
"Primitive": {
|
||||
"No args": function (a) {
|
||||
var i = 0, fn = function () { ++i; return arguments[0]; }, mfn;
|
||||
@@ -283,7 +247,7 @@ module.exports = function (t, a) {
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foobarzeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
mfn.clear('foo', { toString: function () { return 'bar'; } },
|
||||
mfn.delete('foo', { toString: function () { return 'bar'; } },
|
||||
'zeta');
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#3");
|
||||
a(i, 2, "Called twice");
|
||||
@@ -293,18 +257,18 @@ module.exports = function (t, a) {
|
||||
"Regular": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn;
|
||||
mfn = t(fn, { refCounter: true });
|
||||
a(mfn.clearRef(3, 5, 7), null, "Clear before");
|
||||
a(mfn.deleteRef(3, 5, 7), null, "Clear before");
|
||||
a(mfn(3, 5, 7), 15, "Initial");
|
||||
a(mfn(3, 5, 7), 15, "Cache");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #1");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #1");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #2");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #2");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #3");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #3");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 1, "Not cleared");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #4");
|
||||
a(mfn.clearRef(3, 5, 7), true, "Clear final");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #4");
|
||||
a(mfn.deleteRef(3, 5, 7), true, "Clear final");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Restarted");
|
||||
mfn(3, 5, 7);
|
||||
@@ -313,18 +277,18 @@ module.exports = function (t, a) {
|
||||
"Primitive": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn;
|
||||
mfn = t(fn, { primitive: true, refCounter: true });
|
||||
a(mfn.clearRef(3, 5, 7), null, "Clear before");
|
||||
a(mfn.deleteRef(3, 5, 7), null, "Clear before");
|
||||
a(mfn(3, 5, 7), 15, "Initial");
|
||||
a(mfn(3, 5, 7), 15, "Cache");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #1");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #1");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #2");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #2");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #3");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #3");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 1, "Not cleared");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #4");
|
||||
a(mfn.clearRef(3, 5, 7), true, "Clear final");
|
||||
a(mfn.deleteRef(3, 5, 7), false, "Clear #4");
|
||||
a(mfn.deleteRef(3, 5, 7), true, "Clear final");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Restarted");
|
||||
mfn(3, 5, 7);
|
||||
@@ -383,7 +347,7 @@ module.exports = function (t, a) {
|
||||
a(i, 2, "Init Called #2");
|
||||
a(invoked, 7, "Cb Called #2");
|
||||
|
||||
mfn.clear(3, 7);
|
||||
mfn.delete(3, 7);
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
@@ -414,7 +378,7 @@ module.exports = function (t, a) {
|
||||
|
||||
mfn = t(fn, { async: true, refCounter: true });
|
||||
|
||||
a(mfn.clearRef(3, 7), null, "Clear ref before");
|
||||
a(mfn.deleteRef(3, 7), null, "Clear ref before");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
@@ -445,10 +409,10 @@ module.exports = function (t, a) {
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #1");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #2");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #3");
|
||||
a(mfn.clearRef(3, 7), true, "Clear ref Final");
|
||||
a(mfn.deleteRef(3, 7), false, "Clear ref #1");
|
||||
a(mfn.deleteRef(3, 7), false, "Clear ref #2");
|
||||
a(mfn.deleteRef(3, 7), false, "Clear ref #3");
|
||||
a(mfn.deleteRef(3, 7), true, "Clear ref Final");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
@@ -551,7 +515,7 @@ module.exports = function (t, a) {
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
mfn.clear(3, 7);
|
||||
mfn.delete(3, 7);
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
@@ -579,7 +543,7 @@ module.exports = function (t, a) {
|
||||
|
||||
mfn = t(fn, { async: true, primitive: true, refCounter: true });
|
||||
|
||||
a(mfn.clearRef(3, 7), null, "Clear ref before");
|
||||
a(mfn.deleteRef(3, 7), null, "Clear ref before");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
@@ -610,10 +574,10 @@ module.exports = function (t, a) {
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #1");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #2");
|
||||
a(mfn.clearRef(3, 7), false, "Clear ref #3");
|
||||
a(mfn.clearRef(3, 7), true, "Clear ref Final");
|
||||
a(mfn.deleteRef(3, 7), false, "Clear ref #1");
|
||||
a(mfn.deleteRef(3, 7), false, "Clear ref #2");
|
||||
a(mfn.deleteRef(3, 7), false, "Clear ref #3");
|
||||
a(mfn.deleteRef(3, 7), true, "Clear ref Final");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
@@ -916,11 +880,11 @@ module.exports = function (t, a) {
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
@@ -1006,13 +970,13 @@ module.exports = function (t, a) {
|
||||
"Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
@@ -1092,11 +1056,11 @@ module.exports = function (t, a) {
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
@@ -1182,13 +1146,13 @@ module.exports = function (t, a) {
|
||||
"Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
mfn.delete(77, 11);
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
@@ -1234,15 +1198,15 @@ module.exports = function (t, a) {
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
|
||||
x = {};
|
||||
@@ -1250,11 +1214,11 @@ module.exports = function (t, a) {
|
||||
mfn = t(function () { return x; },
|
||||
{ dispose: function (val) { invoked = val; } });
|
||||
|
||||
mfn.clear();
|
||||
mfn.delete();
|
||||
a(invoked, false, "No args: Post invalid clear");
|
||||
mfn();
|
||||
a(invoked, false, "No args: Post cache");
|
||||
mfn.clear();
|
||||
mfn.delete();
|
||||
a(invoked, x, "No args: Pre clear");
|
||||
},
|
||||
"Ref counter": function (a) {
|
||||
@@ -1268,17 +1232,17 @@ module.exports = function (t, a) {
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn(5, 8);
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clearRef(12, 4);
|
||||
mfn.deleteRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
@@ -1295,15 +1259,15 @@ module.exports = function (t, a) {
|
||||
mfn(5, 8, function () {
|
||||
mfn(12, 4, function () {
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11, function () {
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
d();
|
||||
});
|
||||
@@ -1322,15 +1286,15 @@ module.exports = function (t, a) {
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Ref counter": function (a) {
|
||||
@@ -1344,17 +1308,17 @@ module.exports = function (t, a) {
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn(5, 8);
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clearRef(5, 8);
|
||||
mfn.deleteRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clearRef(12, 4);
|
||||
mfn.deleteRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
@@ -1371,15 +1335,15 @@ module.exports = function (t, a) {
|
||||
mfn(5, 8, function () {
|
||||
mfn(12, 4, function () {
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
mfn.delete(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
mfn.delete(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11, function () {
|
||||
mfn.clearAll();
|
||||
mfn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
d();
|
||||
});
|
||||
|
||||
77
test/lib/configure-map.js
Normal file
77
test/lib/configure-map.js
Normal file
@@ -0,0 +1,77 @@
|
||||
'use strict';
|
||||
|
||||
var aFrom = require('es5-ext/array/from')
|
||||
, memoize = require('../..');
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
"One arg": function (a) {
|
||||
var i = 0, fn = function (x) { ++i; return x; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = memoize(fn, { primitive: true });
|
||||
a(mfn(y), y, "#1");
|
||||
a(mfn('foo'), y, "#2");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Clear cache": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = memoize(fn, { primitive: true });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foobarzeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
mfn.delete('foo', { toString: function () { return 'bar'; } },
|
||||
'zeta');
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#3");
|
||||
a(i, 2, "Called twice");
|
||||
},
|
||||
"Circular": function (a) {
|
||||
var i = 0, fn;
|
||||
fn = memoize(function (x) {
|
||||
if (++i < 2) fn(x);
|
||||
});
|
||||
a.throws(function () {
|
||||
fn('foo');
|
||||
}, 'CIRCULAR_INVOCATION');
|
||||
|
||||
i = 0;
|
||||
fn = memoize(function (x, y) {
|
||||
if (++i < 2) fn(x, y);
|
||||
});
|
||||
a.throws(function () {
|
||||
fn('foo', 'bar');
|
||||
}, 'CIRCULAR_INVOCATION');
|
||||
},
|
||||
"Resolvers": function () {
|
||||
var i = 0, fn, r;
|
||||
fn = memoize(function () { ++i; return arguments; },
|
||||
{ length: 3, resolvers: [Boolean, String] });
|
||||
return {
|
||||
"No args": function (a) {
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn()), [false, 'undefined'], "First");
|
||||
a(fn(), r, "Second");
|
||||
a(fn(), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Some Args": function (a) {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn(0, 34, x, 45)), [false, '34', x, 45], "First");
|
||||
a(fn(0, 34, x, 22), r, "Second");
|
||||
a(fn(0, 34, x, false), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
return {
|
||||
"Other": function (a) {
|
||||
a.deep(aFrom(r = fn(1, 34, x, 34)),
|
||||
[true, '34', x, 34], "Second");
|
||||
a(fn(1, 34, x, 89), r, "Third");
|
||||
a(i, 2, "Called once");
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
var d = require('d')
|
||||
, memoize = require('../lib/regular');
|
||||
, memoize = require('../..');
|
||||
|
||||
require('../lib/ext/dispose');
|
||||
require('../lib/ext/ref-counter');
|
||||
require('../ext/dispose');
|
||||
require('../ext/ref-counter');
|
||||
|
||||
module.exports = function (t, a) {
|
||||
var value = [], obj = {};
|
||||
@@ -21,16 +21,16 @@ module.exports = function (t, a) {
|
||||
obj.someFn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
obj.someFn(5, 8);
|
||||
obj.someFn.clearRef(5, 8);
|
||||
obj.someFn.deleteRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
obj.someFn.clearRef(5, 8);
|
||||
obj.someFn.deleteRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
obj.someFn.clearRef(12, 4);
|
||||
obj.someFn.deleteRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
obj.someFn(77, 11);
|
||||
obj.someFn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
obj.someFn.clear();
|
||||
a.deep(value, [10, 88], "Clear");
|
||||
};
|
||||
32
test/lib/normalizers/0.js
Normal file
32
test/lib/normalizers/0.js
Normal file
@@ -0,0 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../..');
|
||||
|
||||
module.exports = {
|
||||
"": function (a) {
|
||||
var i = 0, fn = function () { ++i; return 3; };
|
||||
|
||||
fn = memoize(fn);
|
||||
a(fn(), 3, "First");
|
||||
a(fn(1), 3, "Second");
|
||||
a(fn(5), 3, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Delete": function (a) {
|
||||
var i = 0, fn, mfn, x = {};
|
||||
|
||||
fn = function (a, b, c) {
|
||||
return a + (++i);
|
||||
};
|
||||
mfn = memoize(fn, { length: 0 });
|
||||
a(mfn(3), 4, "Init");
|
||||
a(mfn(5), 4, "Other");
|
||||
a(i, 1, "Pre clear");
|
||||
mfn.delete(6, x, 1);
|
||||
a(i, 1, "After clear");
|
||||
a(mfn(6, x, 1), 8, "Reinit");
|
||||
a(i, 2, "Reinit count");
|
||||
a(mfn(3, x, 1), 8, "Reinit Cached");
|
||||
a(i, 2, "Reinit count");
|
||||
}
|
||||
};
|
||||
43
test/lib/normalizers/get-primitive-fixed.js
Normal file
43
test/lib/normalizers/get-primitive-fixed.js
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../..');
|
||||
|
||||
module.exports = {
|
||||
"": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = memoize(fn, { primitive: true });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foobarzeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Delete": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = memoize(fn, { primitive: true });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foobarzeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
mfn.delete('foo', { toString: function () { return 'bar'; } },
|
||||
'zeta');
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#3");
|
||||
a(i, 2, "Called twice");
|
||||
},
|
||||
"Clear": function (a) {
|
||||
var i = 0, fn;
|
||||
fn = memoize(function (x) {
|
||||
if (++i < 2) fn(x);
|
||||
});
|
||||
a.throws(function () {
|
||||
fn('foo');
|
||||
}, 'CIRCULAR_INVOCATION');
|
||||
|
||||
i = 0;
|
||||
fn = memoize(function (x, y) {
|
||||
if (++i < 2) fn(x, y);
|
||||
});
|
||||
a.throws(function () {
|
||||
fn('foo', 'bar');
|
||||
}, 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
};
|
||||
56
test/lib/normalizers/get-regular-1.js
Normal file
56
test/lib/normalizers/get-regular-1.js
Normal file
@@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../..');
|
||||
|
||||
module.exports = {
|
||||
"": function (t, a) {
|
||||
var i = 0, fn = function (x) { ++i; return x; };
|
||||
|
||||
fn = memoize(fn);
|
||||
return {
|
||||
"No arg": function () {
|
||||
i = 0;
|
||||
a(fn(), undefined, "First");
|
||||
a(fn(), undefined, "Second");
|
||||
a(fn(), undefined, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Arg": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a(fn(x, 8), x, "First");
|
||||
a(fn(x, 4), x, "Second");
|
||||
a(fn(x, 2), x, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Other Arg": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a(fn(x, 2), x, "First");
|
||||
a(fn(x, 9), x, "Second");
|
||||
a(fn(x, 3), x, "Third");
|
||||
a(i, 1, "Called once");
|
||||
}
|
||||
};
|
||||
},
|
||||
"Delete": function (a) {
|
||||
var i = 0, fn, mfn, x = {};
|
||||
|
||||
fn = function (a, b, c) {
|
||||
return a + (++i);
|
||||
};
|
||||
mfn = memoize(fn, { length: 1 });
|
||||
a(mfn(3), 4, "Init");
|
||||
a(mfn(4, x, 1), 6, "Init #2");
|
||||
mfn.delete(4);
|
||||
a(mfn(3, x, 1), 4, "Cached");
|
||||
mfn(3, x, 1);
|
||||
a(i, 2, "Pre clear");
|
||||
mfn.delete(3, x, 1);
|
||||
a(i, 2, "After clear");
|
||||
a(mfn(3, x, 1), 6, "Reinit");
|
||||
a(i, 3, "Reinit count");
|
||||
a(mfn(3, x, 1), 6, "Reinit Cached");
|
||||
a(i, 3, "Reinit count");
|
||||
}
|
||||
};
|
||||
91
test/lib/normalizers/get-regular-fixed.js
Normal file
91
test/lib/normalizers/get-regular-fixed.js
Normal file
@@ -0,0 +1,91 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../..');
|
||||
|
||||
module.exports = {
|
||||
"": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return [x, y, z]; }, r;
|
||||
|
||||
fn = memoize(fn);
|
||||
return {
|
||||
"No args": function () {
|
||||
i = 0;
|
||||
a.deep(r = fn(), [undefined, undefined, undefined], "First");
|
||||
a(fn(), r, "Second");
|
||||
a(fn(), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Some Args": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(r = fn(x, 8), [x, 8, undefined], "First");
|
||||
a(fn(x, 8), r, "Second");
|
||||
a(fn(x, 8), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
return {
|
||||
"Other": function () {
|
||||
a.deep(r = fn(x, 5), [x, 5, undefined], "Second");
|
||||
a(fn(x, 5), r, "Third");
|
||||
a(i, 2, "Called once");
|
||||
}
|
||||
};
|
||||
},
|
||||
"Full stuff": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(r = fn(x, 8, 23, 98), [x, 8, 23], "First");
|
||||
a(fn(x, 8, 23, 43), r, "Second");
|
||||
a(fn(x, 8, 23, 9), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
return {
|
||||
"Other": function () {
|
||||
a.deep(r = fn(x, 23, 8, 13), [x, 23, 8], "Second");
|
||||
a(fn(x, 23, 8, 22), r, "Third");
|
||||
a(i, 2, "Called once");
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
"Delete": function (a) {
|
||||
var i = 0, fn, mfn, x = {};
|
||||
|
||||
fn = function (a, b, c) {
|
||||
return a + (++i);
|
||||
};
|
||||
mfn = memoize(fn);
|
||||
a(mfn(3, x, 1), 4, "Init");
|
||||
a(mfn(4, x, 1), 6, "Init #2");
|
||||
mfn.delete(4, x, 1);
|
||||
a(mfn(3, x, 1), 4, "Cached");
|
||||
mfn(3, x, 1);
|
||||
a(i, 2, "Pre clear");
|
||||
mfn.delete(3, x, 1);
|
||||
a(i, 2, "After clear");
|
||||
a(mfn(3, x, 1), 6, "Reinit");
|
||||
a(i, 3, "Reinit count");
|
||||
a(mfn(3, x, 1), 6, "Reinit Cached");
|
||||
a(i, 3, "Reinit count");
|
||||
},
|
||||
"Clear": function (a) {
|
||||
var i = 0, fn, x = {};
|
||||
|
||||
fn = function () {
|
||||
++i;
|
||||
return arguments;
|
||||
};
|
||||
|
||||
fn = memoize(fn, { length: 3 });
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
a(i, 2, "Pre clear");
|
||||
fn.clear();
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
a(i, 4, "After clear");
|
||||
}
|
||||
};
|
||||
59
test/lib/normalizers/get-regular.js
Normal file
59
test/lib/normalizers/get-regular.js
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
var aFrom = require('es5-ext/array/from')
|
||||
, memoize = require('../../..');
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
"": function (a) {
|
||||
var i = 0, fn = function () { ++i; return arguments; }, r;
|
||||
|
||||
fn = memoize(fn, { length: false });
|
||||
return {
|
||||
"No args": function () {
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn()), [], "First");
|
||||
a(fn(), r, "Second");
|
||||
a(fn(), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Some Args": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn(x, 8)), [x, 8], "First");
|
||||
a(fn(x, 8), r, "Second");
|
||||
a(fn(x, 8), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Many args": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn(x, 8, 23, 98)), [x, 8, 23, 98], "First");
|
||||
a(fn(x, 8, 23, 98), r, "Second");
|
||||
a(fn(x, 8, 23, 98), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
}
|
||||
};
|
||||
},
|
||||
"Delete": function (a) {
|
||||
var i = 0, fn, mfn, x = {};
|
||||
|
||||
fn = function (a, b, c) {
|
||||
return a + (++i);
|
||||
};
|
||||
mfn = memoize(fn, { length: false });
|
||||
a(mfn(3, x, 1), 4, "Init");
|
||||
a(mfn(4, x, 1), 6, "Init #2");
|
||||
mfn.delete(4, x, 1);
|
||||
a(mfn(3, x, 1), 4, "Cached");
|
||||
mfn(3, x, 1);
|
||||
a(i, 2, "Pre clear");
|
||||
mfn.delete(3, x, 1);
|
||||
a(i, 2, "After clear");
|
||||
a(mfn(3, x, 1), 6, "Reinit");
|
||||
a(i, 3, "Reinit count");
|
||||
a(mfn(3, x, 1), 6, "Reinit Cached");
|
||||
a(i, 3, "Reinit count");
|
||||
}
|
||||
};
|
||||
};
|
||||
18
test/lib/normalizers/primitive.js
Normal file
18
test/lib/normalizers/primitive.js
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../..')
|
||||
|
||||
, join = Array.prototype.join;
|
||||
|
||||
module.exports = function (a) {
|
||||
var i = 0, fn = function () { ++i; return join.call(arguments, '|'); }
|
||||
, y = { toString: function () { return 'foo'; } }, mfn;
|
||||
mfn = memoize(fn, { primitive: true, length: false });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foo|bar|zeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foo|bar|zeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
a(mfn(y, 'bar'), 'foo|bar', "#3");
|
||||
a(i, 2, "Called twice");
|
||||
a(mfn(y, 'bar'), 'foo|bar', "#4");
|
||||
a(i, 2, "Called twice #2");
|
||||
};
|
||||
6
test/lib/registered-extensions.js
Normal file
6
test/lib/registered-extensions.js
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (t, a) {
|
||||
require('../../ext/async');
|
||||
a(typeof t.async, 'function');
|
||||
};
|
||||
10
test/lib/resolve-length.js
Normal file
10
test/lib/resolve-length.js
Normal file
@@ -0,0 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (t, a) {
|
||||
a(t(1, 2), 1, "Options");
|
||||
a(t(1, 2, true), 1, "Options: Async ");
|
||||
a(t(undefined, 2), 2, "Function");
|
||||
a(t(undefined, 2, true), 1, "Function: Async");
|
||||
a(t(undefined, undefined, false), 1, "Unknown");
|
||||
a(t(undefined, undefined, true), 1, "Unknown: async");
|
||||
};
|
||||
34
test/methods-plain.js
Normal file
34
test/methods-plain.js
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
var d = require('d');
|
||||
|
||||
require('../ext/dispose');
|
||||
require('../ext/ref-counter');
|
||||
|
||||
module.exports = function (t, a) {
|
||||
var value = [], obj = {};
|
||||
Object.defineProperties(obj, t({
|
||||
someFn: d(function (x, y) { a(this, obj); return x + y; },
|
||||
{ refCounter: true,
|
||||
dispose: function (val) { value.push(val); } })
|
||||
}));
|
||||
|
||||
obj = Object.create(obj);
|
||||
obj.someFn(3, 7);
|
||||
obj.someFn(5, 8);
|
||||
obj.someFn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
obj.someFn(5, 8);
|
||||
obj.someFn.deleteRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
obj.someFn.deleteRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
obj.someFn.deleteRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
obj.someFn(77, 11);
|
||||
obj.someFn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
};
|
||||
31
test/methods.js
Normal file
31
test/methods.js
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
var d = require('d');
|
||||
|
||||
module.exports = function (t, a) {
|
||||
var value = [], obj = {};
|
||||
Object.defineProperties(obj, t({
|
||||
someFn: d(function (x, y) { a(this, obj); return x + y; },
|
||||
{ refCounter: true,
|
||||
dispose: function (val) { value.push(val); } })
|
||||
}));
|
||||
|
||||
obj = Object.create(obj);
|
||||
obj.someFn(3, 7);
|
||||
obj.someFn(5, 8);
|
||||
obj.someFn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
obj.someFn(5, 8);
|
||||
obj.someFn.deleteRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
obj.someFn.deleteRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
obj.someFn.deleteRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
obj.someFn(77, 11);
|
||||
obj.someFn.clear();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
};
|
||||
29
test/plain.js
Normal file
29
test/plain.js
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (t) {
|
||||
return {
|
||||
"": function (a) {
|
||||
var i = 0, fn = function (x) { ++i; return x; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = t(fn, { primitive: true });
|
||||
a(typeof mfn, 'function', "Returns");
|
||||
a(mfn.__memoized__, true, "Marked");
|
||||
a(t(mfn), mfn, "Do not memoize memoized");
|
||||
a(mfn(y), y, "#1");
|
||||
a(mfn('foo'), y, "#2");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Clear cache": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = t(fn, { primitive: true });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foobarzeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
mfn.delete('foo', { toString: function () { return 'bar'; } },
|
||||
'zeta');
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#3");
|
||||
a(i, 2, "Called twice");
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var join = Array.prototype.join;
|
||||
|
||||
module.exports = function (t) {
|
||||
return {
|
||||
"No args": function (a) {
|
||||
var i = 0, fn = function () { ++i; return arguments[0]; }, mfn;
|
||||
mfn = t(fn, { primitive: true });
|
||||
a(mfn('ble'), 'ble', "#1");
|
||||
a(mfn({}), 'ble', "#2");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"One arg": function (a) {
|
||||
var i = 0, fn = function (x) { ++i; return x; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = t(fn, { primitive: true });
|
||||
a(mfn(y), y, "#1");
|
||||
a(mfn('foo'), y, "#2");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Many args": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = t(fn, { primitive: true });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foobarzeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Many args: Length false": function (a) {
|
||||
var i = 0, fn = function () { ++i; return join.call(arguments, '|'); }
|
||||
, y = { toString: function () { return 'foo'; } }, mfn;
|
||||
mfn = t(fn, { primitive: true, length: false });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foo|bar|zeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foo|bar|zeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
a(mfn(y, 'bar'), 'foo|bar', "#3");
|
||||
a(i, 2, "Called twice");
|
||||
a(mfn(y, 'bar'), 'foo|bar', "#4");
|
||||
a(i, 2, "Called twice #2");
|
||||
},
|
||||
"Clear cache": function (a) {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return x + y + z; }, mfn
|
||||
, y = { toString: function () { return 'foo'; } };
|
||||
mfn = t(fn, { primitive: true });
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#1");
|
||||
a(mfn('foo', 'bar', 'zeta'), 'foobarzeta', "#2");
|
||||
a(i, 1, "Called once");
|
||||
mfn.clear('foo', { toString: function () { return 'bar'; } },
|
||||
'zeta');
|
||||
a(mfn(y, 'bar', 'zeta'), 'foobarzeta', "#3");
|
||||
a(i, 2, "Called twice");
|
||||
},
|
||||
"Circular": function (a) {
|
||||
var i = 0, fn;
|
||||
fn = t(function (x) {
|
||||
if (++i < 2) fn(x);
|
||||
});
|
||||
a.throws(function () {
|
||||
fn('foo');
|
||||
}, 'CIRCULAR_INVOCATION');
|
||||
|
||||
i = 0;
|
||||
fn = t(function (x, y) {
|
||||
if (++i < 2) fn(x, y);
|
||||
});
|
||||
a.throws(function () {
|
||||
fn('foo', 'bar');
|
||||
}, 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
};
|
||||
};
|
||||
223
test/regular.js
223
test/regular.js
@@ -1,223 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var aFrom = require('es5-ext/array/from');
|
||||
|
||||
module.exports = function (t, a) {
|
||||
return {
|
||||
"0": function () {
|
||||
var i = 0, fn = function () { ++i; return 3; };
|
||||
|
||||
fn = t(fn);
|
||||
a(fn(), 3, "First");
|
||||
a(fn(1), 3, "Second");
|
||||
a(fn(5), 3, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"1": function () {
|
||||
var i = 0, fn = function (x) { ++i; return x; };
|
||||
|
||||
fn = t(fn);
|
||||
return {
|
||||
"No arg": function () {
|
||||
i = 0;
|
||||
a(fn(), undefined, "First");
|
||||
a(fn(), undefined, "Second");
|
||||
a(fn(), undefined, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Arg": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a(fn(x, 8), x, "First");
|
||||
a(fn(x, 4), x, "Second");
|
||||
a(fn(x, 2), x, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Other Arg": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a(fn(x, 2), x, "First");
|
||||
a(fn(x, 9), x, "Second");
|
||||
a(fn(x, 3), x, "Third");
|
||||
a(i, 1, "Called once");
|
||||
}
|
||||
};
|
||||
},
|
||||
"3": function () {
|
||||
var i = 0, fn = function (x, y, z) { ++i; return [x, y, z]; }, r;
|
||||
|
||||
fn = t(fn);
|
||||
return {
|
||||
"No args": function () {
|
||||
i = 0;
|
||||
a.deep(r = fn(), [undefined, undefined, undefined], "First");
|
||||
a(fn(), r, "Second");
|
||||
a(fn(), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Some Args": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(r = fn(x, 8), [x, 8, undefined], "First");
|
||||
a(fn(x, 8), r, "Second");
|
||||
a(fn(x, 8), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
return {
|
||||
"Other": function () {
|
||||
a.deep(r = fn(x, 5), [x, 5, undefined], "Second");
|
||||
a(fn(x, 5), r, "Third");
|
||||
a(i, 2, "Called once");
|
||||
}
|
||||
};
|
||||
},
|
||||
"Full stuff": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(r = fn(x, 8, 23, 98), [x, 8, 23], "First");
|
||||
a(fn(x, 8, 23, 43), r, "Second");
|
||||
a(fn(x, 8, 23, 9), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
return {
|
||||
"Other": function () {
|
||||
a.deep(r = fn(x, 23, 8, 13), [x, 23, 8], "Second");
|
||||
a(fn(x, 23, 8, 22), r, "Third");
|
||||
a(i, 2, "Called once");
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
"Dynamic": function () {
|
||||
var i = 0, fn = function () { ++i; return arguments; }, r;
|
||||
|
||||
fn = t(fn, { length: false });
|
||||
return {
|
||||
"No args": function () {
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn()), [], "First");
|
||||
a(fn(), r, "Second");
|
||||
a(fn(), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Some Args": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn(x, 8)), [x, 8], "First");
|
||||
a(fn(x, 8), r, "Second");
|
||||
a(fn(x, 8), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
},
|
||||
"Many args": function () {
|
||||
var x = {};
|
||||
i = 0;
|
||||
a.deep(aFrom(r = fn(x, 8, 23, 98)), [x, 8, 23, 98], "First");
|
||||
a(fn(x, 8, 23, 98), r, "Second");
|
||||
a(fn(x, 8, 23, 98), r, "Third");
|
||||
a(i, 1, "Called once");
|
||||
}
|
||||
};
|
||||
},
|
||||
"Clear Cache": {
|
||||
"Specific": function () {
|
||||
var i = 0, fn, mfn, x = {};
|
||||
|
||||
fn = function (a, b, c) {
|
||||
return a + (++i);
|
||||
};
|
||||
|
||||
return {
|
||||
"0": function (a) {
|
||||
mfn = t(fn, { length: 0 });
|
||||
a(mfn(3), 4, "Init");
|
||||
a(mfn(5), 4, "Other");
|
||||
a(i, 1, "Pre clear");
|
||||
mfn.clear(6, x, 1);
|
||||
a(i, 1, "After clear");
|
||||
a(mfn(6, x, 1), 8, "Reinit");
|
||||
a(i, 2, "Reinit count");
|
||||
a(mfn(3, x, 1), 8, "Reinit Cached");
|
||||
a(i, 2, "Reinit count");
|
||||
},
|
||||
"1": function (a) {
|
||||
i = 0;
|
||||
mfn = t(fn, { length: 1 });
|
||||
a(mfn(3), 4, "Init");
|
||||
a(mfn(4, x, 1), 6, "Init #2");
|
||||
mfn.clear(4);
|
||||
a(mfn(3, x, 1), 4, "Cached");
|
||||
mfn(3, x, 1);
|
||||
a(i, 2, "Pre clear");
|
||||
mfn.clear(3, x, 1);
|
||||
a(i, 2, "After clear");
|
||||
a(mfn(3, x, 1), 6, "Reinit");
|
||||
a(i, 3, "Reinit count");
|
||||
a(mfn(3, x, 1), 6, "Reinit Cached");
|
||||
a(i, 3, "Reinit count");
|
||||
},
|
||||
"3": function (a) {
|
||||
i = 0;
|
||||
mfn = t(fn);
|
||||
a(mfn(3, x, 1), 4, "Init");
|
||||
a(mfn(4, x, 1), 6, "Init #2");
|
||||
mfn.clear(4, x, 1);
|
||||
a(mfn(3, x, 1), 4, "Cached");
|
||||
mfn(3, x, 1);
|
||||
a(i, 2, "Pre clear");
|
||||
mfn.clear(3, x, 1);
|
||||
a(i, 2, "After clear");
|
||||
a(mfn(3, x, 1), 6, "Reinit");
|
||||
a(i, 3, "Reinit count");
|
||||
a(mfn(3, x, 1), 6, "Reinit Cached");
|
||||
a(i, 3, "Reinit count");
|
||||
},
|
||||
"Any": function (a) {
|
||||
i = 0;
|
||||
mfn = t(fn, { length: false });
|
||||
a(mfn(3, x, 1), 4, "Init");
|
||||
a(mfn(4, x, 1), 6, "Init #2");
|
||||
mfn.clear(4, x, 1);
|
||||
a(mfn(3, x, 1), 4, "Cached");
|
||||
mfn(3, x, 1);
|
||||
a(i, 2, "Pre clear");
|
||||
mfn.clear(3, x, 1);
|
||||
a(i, 2, "After clear");
|
||||
a(mfn(3, x, 1), 6, "Reinit");
|
||||
a(i, 3, "Reinit count");
|
||||
a(mfn(3, x, 1), 6, "Reinit Cached");
|
||||
a(i, 3, "Reinit count");
|
||||
}
|
||||
};
|
||||
},
|
||||
"All": function (a) {
|
||||
var i = 0, fn, x = {};
|
||||
|
||||
fn = function () {
|
||||
++i;
|
||||
return arguments;
|
||||
};
|
||||
|
||||
fn = t(fn, { length: 3 });
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
a(i, 2, "Pre clear");
|
||||
fn.clearAll();
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
fn(1, x, 3);
|
||||
fn(1, x, 4);
|
||||
a(i, 4, "After clear");
|
||||
}
|
||||
},
|
||||
"Circular": function (a) {
|
||||
var i = 0, fn;
|
||||
fn = t(function (x) {
|
||||
if (++i < 2) fn(x);
|
||||
});
|
||||
a.throws(function () {
|
||||
fn(34);
|
||||
}, 'CIRCULAR_INVOCATION');
|
||||
}
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user