mirror of
https://github.com/BreizhHardware/memoizee.git
synced 2026-01-18 16:37:21 +01:00
Modularization. Cleanup and logic improvements.
Additionally changed max option algorithm from FIFO to LRU
This commit is contained in:
@@ -3,46 +3,111 @@
|
||||
// Simple benchmark for very simple memoization case (fibonacci series)
|
||||
// To run it, do following in memoizee package path:
|
||||
//
|
||||
// $ npm install bench underscore lodash lru-cache
|
||||
// $ npm install underscore lodash lru-cache
|
||||
// $ node benchmark/fibonacci.js
|
||||
|
||||
var getFib = function (memoize, opts) {
|
||||
var forEach = require('es5-ext/lib/Object/for-each')
|
||||
, pad = require('es5-ext/lib/String/prototype/pad')
|
||||
, memoizee = require('../lib')
|
||||
, underscore = require('underscore').memoize
|
||||
, lodash = require('lodash').memoize
|
||||
, lruCache = require('lru-cache')
|
||||
|
||||
, now = Date.now
|
||||
|
||||
, time, getFib, lru, memo, total, index = 3000, count = 10, i, lruMax = 1000
|
||||
, data = {}, lruObj;
|
||||
|
||||
getFib = function (memoize, opts) {
|
||||
var fib = memoize(function (x) {
|
||||
return (x < 2) ? 1 : fib(x - 1) + fib(x - 2);
|
||||
}, opts);
|
||||
return fib;
|
||||
};
|
||||
|
||||
var memoizee = getFib(require('../lib/memoize'), { primitive: true })
|
||||
, underscore = getFib(require('underscore').memoize)
|
||||
, lodash = getFib(require('lodash').memoize)
|
||||
|
||||
, index = 200;
|
||||
|
||||
var lruCache = require('lru-cache')({});
|
||||
|
||||
var lru = function (x) {
|
||||
var value = lruCache.get(x);
|
||||
lru = function (x) {
|
||||
var value = lruObj.get(x);
|
||||
if (value === undefined) {
|
||||
value = ((x < 2) ? 1 : lru(x - 1) + lru(x - 2));
|
||||
lruCache.set(x, value);
|
||||
lruObj.set(x, value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
exports.compare = {
|
||||
"Underscore": function () {
|
||||
underscore(index);
|
||||
},
|
||||
"Lodash": function () {
|
||||
lodash(index);
|
||||
},
|
||||
"Memoizee": function () {
|
||||
memoizee(index);
|
||||
},
|
||||
"LruCache": function () {
|
||||
lru(index);
|
||||
}
|
||||
};
|
||||
console.log("Fibonacci", index, "x" + count + ":\n");
|
||||
|
||||
require('bench').runMain();
|
||||
total = 0;
|
||||
i = count;
|
||||
while (i--) {
|
||||
memo = getFib(memoizee);
|
||||
time = now();
|
||||
memo(index);
|
||||
total += now() - time;
|
||||
}
|
||||
data["Memoizee (object mode)"] = total;
|
||||
|
||||
total = 0;
|
||||
i = count;
|
||||
while (i--) {
|
||||
memo = getFib(memoizee, { primitive: true });
|
||||
time = now();
|
||||
memo(index);
|
||||
total += now() - time;
|
||||
}
|
||||
data["Memoizee (primitive mode)"] = total;
|
||||
|
||||
total = 0;
|
||||
i = count;
|
||||
while (i--) {
|
||||
memo = getFib(underscore);
|
||||
time = now();
|
||||
memo(index);
|
||||
total += now() - time;
|
||||
}
|
||||
data["Underscore"] = total;
|
||||
|
||||
total = 0;
|
||||
i = count;
|
||||
while (i--) {
|
||||
memo = getFib(lodash);
|
||||
time = now();
|
||||
memo(index);
|
||||
total += now() - time;
|
||||
}
|
||||
data["Lo-dash"] = total;
|
||||
|
||||
total = 0;
|
||||
i = count;
|
||||
while (i--) {
|
||||
memo = getFib(memoizee, { primitive: true, max: lruMax });
|
||||
time = now();
|
||||
memo(index);
|
||||
total += now() - time;
|
||||
}
|
||||
data["Memoizee (primitive mode) LRU (max: 1000)"] = total;
|
||||
|
||||
total = 0;
|
||||
i = count;
|
||||
while (i--) {
|
||||
memo = getFib(memoizee, { max: lruMax });
|
||||
time = now();
|
||||
memo(index);
|
||||
total += now() - time;
|
||||
}
|
||||
data["Memoizee (object mode) LRU (max: 1000)"] = total;
|
||||
|
||||
total = 0;
|
||||
i = count;
|
||||
while (i--) {
|
||||
lruObj = lruCache({ max: lruMax });
|
||||
time = now();
|
||||
lru(index);
|
||||
total += now() - time;
|
||||
}
|
||||
data["lru-cache LRU (max: 1000)"] = total;
|
||||
|
||||
forEach(data, function (value, name, obj, index) {
|
||||
console.log(index + 1 + ":", pad.call(value, " ", 5) + "ms ", name);
|
||||
}, null, function (a, b) {
|
||||
return this[a] - this[b];
|
||||
});
|
||||
|
||||
52
lib/_base.js
Normal file
52
lib/_base.js
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
var callable = require('es5-ext/lib/Object/valid-callable')
|
||||
, forEach = require('es5-ext/lib/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]);
|
||||
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);
|
||||
|
||||
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.emit('ready');
|
||||
return conf.memoized;
|
||||
};
|
||||
};
|
||||
ext = exports.ext = {};
|
||||
92
lib/ext/async.js
Normal file
92
lib/ext/async.js
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
|
||||
var toArray = require('es5-ext/lib/Array/from')
|
||||
, last = require('es5-ext/lib/Array/prototype/last')
|
||||
, forEach = require('es5-ext/lib/Object/for-each')
|
||||
, isCallable = require('es5-ext/lib/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, options) {
|
||||
var cache;
|
||||
|
||||
cache = conf.async = {};
|
||||
|
||||
(function (org) {
|
||||
var value, cb;
|
||||
|
||||
conf.on('init', function (id) {
|
||||
value.id = id;
|
||||
cache[id] = cb ? [cb] : [];
|
||||
});
|
||||
|
||||
conf.on('hit', function (id) {
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isArray(cache[id])) {
|
||||
cache[id].push(cb);
|
||||
} else {
|
||||
nextTick(apply.bind(cb, cache[id].context, cache[id]));
|
||||
}
|
||||
});
|
||||
conf.fn = function () {
|
||||
var id, args, asyncArgs;
|
||||
args = arguments;
|
||||
asyncArgs = toArray(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 (err) {
|
||||
conf.clear(self.id);
|
||||
} else {
|
||||
arguments.context = this;
|
||||
cache[self.id] = arguments;
|
||||
}
|
||||
for (i = 0; cb = waiting[i]; ++i) {
|
||||
res = apply.call(cb, this, arguments);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
return apply.call(org, this, asyncArgs);
|
||||
};
|
||||
|
||||
(function (fn) {
|
||||
var resolver = function (args) {
|
||||
cb = last.call(args);
|
||||
if (isCallable(cb)) {
|
||||
return slice.call(args, 0, -1);
|
||||
} else {
|
||||
cb = null;
|
||||
return args;
|
||||
}
|
||||
};
|
||||
conf.memoized = function () {
|
||||
return fn.apply(this, resolver(arguments));
|
||||
};
|
||||
forEach(fn, function (value, name) {
|
||||
memoized[name] = function () {
|
||||
return fn[name].apply(this, resolver(arguments));
|
||||
};
|
||||
});
|
||||
|
||||
}(conf.memoized));
|
||||
|
||||
}(conf.fn));
|
||||
|
||||
conf.on('purge', function (id) {
|
||||
delete cache[id];
|
||||
});
|
||||
|
||||
conf.on('purgeall', function () {
|
||||
cache = conf.async = {};
|
||||
});
|
||||
};
|
||||
31
lib/ext/dispose.js
Normal file
31
lib/ext/dispose.js
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
var callable = require('es5-ext/lib/Object/valid-callable')
|
||||
, forEach = require('es5-ext/lib/Object/for-each')
|
||||
, ext = require('../_base').ext
|
||||
|
||||
, isArray = Array.isArray, slice = Array.prototype.slice;
|
||||
|
||||
ext.dispose = function (dispose, conf, options) {
|
||||
var clear;
|
||||
|
||||
callable(dispose);
|
||||
|
||||
conf.on('purge', clear = (options.async && ext.async) ? function (id) {
|
||||
var value = conf.async[id];
|
||||
delete conf.cache[id];
|
||||
if (!isArray(value)) {
|
||||
dispose.apply(null, slice.call(value, 1));
|
||||
}
|
||||
}: function (id) {
|
||||
var value = conf.cache[id];
|
||||
delete conf.cache[id];
|
||||
dispose(value);
|
||||
});
|
||||
|
||||
conf.on('purgeall', function () {
|
||||
forEach(conf.cache, function (value, id, cache) {
|
||||
clear(id);
|
||||
});
|
||||
});
|
||||
};
|
||||
27
lib/ext/max-age.js
Normal file
27
lib/ext/max-age.js
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
var forEach = require('es5-ext/lib/Object/for-each');
|
||||
|
||||
require('../_base').ext.maxAge = function (maxAge, conf) {
|
||||
var cache;
|
||||
|
||||
maxAge = maxAge >>> 0;
|
||||
if (!maxAge) {
|
||||
return;
|
||||
}
|
||||
|
||||
cache = {};
|
||||
conf.on('init', function (id) {
|
||||
cache[id] = setTimeout(function () { conf.clear(id); }, maxAge);
|
||||
});
|
||||
conf.on('purge', function (id) {
|
||||
clearTimeout(cache[id]);
|
||||
delete cache[id];
|
||||
});
|
||||
conf.on('purgeall', function (id) {
|
||||
forEach(cache, function (id) {
|
||||
clearTimeout(id);
|
||||
});
|
||||
cache = {};
|
||||
});
|
||||
};
|
||||
55
lib/ext/max.js
Normal file
55
lib/ext/max.js
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
require('../_base').ext.max = function (max, conf) {
|
||||
var index, base, size, add, top, clear, queue, map;
|
||||
|
||||
max = max >>> 0;
|
||||
if (!max) {
|
||||
return;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
base = size = 0;
|
||||
queue = {};
|
||||
map = {};
|
||||
|
||||
conf.on('init', function (id) {
|
||||
queue[++index] = id;
|
||||
map[id] = index;
|
||||
++size;
|
||||
if (size > max) {
|
||||
conf.clear(queue[base]);
|
||||
}
|
||||
});
|
||||
|
||||
conf.on('hit', function (id) {
|
||||
var oldIndex = map[id];
|
||||
queue[++index] = queue[oldIndex];
|
||||
map[id] = index;
|
||||
delete queue[oldIndex];
|
||||
if (base === oldIndex) {
|
||||
while (!queue.hasOwnProperty(++base)) continue;
|
||||
}
|
||||
});
|
||||
|
||||
conf.on('purge', 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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
conf.on('purgeall', function (id) {
|
||||
index = -1;
|
||||
base = size = 0;
|
||||
queue = {};
|
||||
map = {};
|
||||
});
|
||||
};
|
||||
33
lib/ext/method.js
Normal file
33
lib/ext/method.js
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
var extend = require('es5-ext/lib/Object/extend')
|
||||
, isString = require('es5-ext/lib/String/is-string')
|
||||
|
||||
, slice = Array.prototype.slice, create = Object.create
|
||||
, defineProperty = Object.defineProperty;
|
||||
|
||||
require('../_base').ext.method = function (method, conf, options) {
|
||||
if (isString(options.method)) {
|
||||
method = { name: String(options.method),
|
||||
descriptor: { configurable: true, writable: true } };
|
||||
} else {
|
||||
method = options.method;
|
||||
method.name = String(method.name);
|
||||
method.descriptor = (method.descriptor == null) ?
|
||||
{ configurable: true, writable: true } : Object(method.descriptor);
|
||||
}
|
||||
options = create(options);
|
||||
options.method = undefined;
|
||||
|
||||
(function (fn) {
|
||||
conf.memoized = function () {
|
||||
if (this && (this !== global)) {
|
||||
method.descriptor.value = conf.memoize(conf.fn.bind(this), options);
|
||||
defineProperty(this, method.name, method.descriptor);
|
||||
return method.descriptor.value.apply(this, arguments);
|
||||
}
|
||||
return fn.apply(this, arguments);
|
||||
};
|
||||
extend(conf.memoized, fn);
|
||||
}(conf.memoized));
|
||||
};
|
||||
@@ -4,23 +4,35 @@ var partial = require('es5-ext/lib/Function/prototype/partial')
|
||||
, forEach = require('es5-ext/lib/Object/for-each')
|
||||
, contains = require('es5-ext/lib/String/prototype/contains')
|
||||
, pad = require('es5-ext/lib/String/prototype/pad')
|
||||
, memoize = require('./memoize')
|
||||
|
||||
, max = Math.max
|
||||
|
||||
, stats = exports.statistics = {};
|
||||
, stats = exports.statistics = {}, ext;
|
||||
|
||||
memoize._profile = function () {
|
||||
var id, stack = (new Error()).stack;
|
||||
id = stack.split('\n')[3].replace(/\n/g, "\\n").trim();
|
||||
if (contains.call(id, '/memoizee/lib')) {
|
||||
id = stack.split('\n')[4].replace(/\n/g, "\\n").trim();
|
||||
require('../_base').ext.profile = ext = function (conf) {
|
||||
var id, stack, data;
|
||||
stack = (new Error()).stack
|
||||
if (!stack.split('\n').slice(3).some(function (line) {
|
||||
if ((line.indexOf('/memoizee/') === -1) &&
|
||||
(line.indexOf('/es5-ext/') === -1) &&
|
||||
(line.indexOf('/next/lib/fs/_memoize-watcher') === -1) &&
|
||||
(line.indexOf(' (native)') === -1)) {
|
||||
id = line.replace(/\n/g, "\\n").trim();
|
||||
return true;
|
||||
}
|
||||
})) {
|
||||
id = 'unknown';
|
||||
}
|
||||
|
||||
if (!stats[id]) {
|
||||
stats[id] = { initial: 0, cached: 0, time: 0 };
|
||||
stats[id] = { initial: 0, cached: 0 };
|
||||
}
|
||||
return stats[id];
|
||||
data = stats[id];
|
||||
|
||||
conf.on('init', function (id) { ++data.initial; });
|
||||
conf.on('hit', function (id) { ++data.cached; });
|
||||
};
|
||||
ext.force = true;
|
||||
|
||||
exports.log = function () {
|
||||
var initial, cached, time, ordered, ipad, cpad, ppad, toPrc, tpad, atime, log;
|
||||
@@ -41,7 +53,6 @@ exports.log = function () {
|
||||
forEach(stats, function (data, name) {
|
||||
initial += data.initial;
|
||||
cached += data.cached;
|
||||
time += data.time;
|
||||
ordered.push([name, data]);
|
||||
}, null, function (a, b) {
|
||||
return (this[b].initial + this[b].cached) -
|
||||
@@ -52,26 +63,18 @@ exports.log = function () {
|
||||
max(String(initial).length, "Init".length));
|
||||
cpad = partial.call(pad, " ", max(String(cached).length, "Cache".length));
|
||||
ppad = partial.call(pad, " ", "%Cache".length);
|
||||
tpad = partial.call(pad, " ", max((String(time.toFixed(3)) + "s").length,
|
||||
"Avg init time".length));
|
||||
log += ipad.call("Init") + " " +
|
||||
cpad.call("Cache") + " " +
|
||||
ppad.call("%Cache") + " " +
|
||||
tpad.call("Avg init time") + " Source location\n";
|
||||
ppad.call("%Cache") + " Source location\n";
|
||||
log += ipad.call(initial) + " " +
|
||||
cpad.call(cached) + " " +
|
||||
ppad.call(toPrc(initial, cached)) + " " +
|
||||
tpad.call((atime = initial ? ((time / initial) / 1000) : 0).toFixed(3) +
|
||||
"s") + " (all)\n";
|
||||
ppad.call(toPrc(initial, cached)) + " (all)\n";
|
||||
ordered.forEach(function (data) {
|
||||
var name = data[0];
|
||||
data = data[1];
|
||||
log += ipad.call(data.initial) + " " +
|
||||
cpad.call(data.cached) + " " +
|
||||
ppad.call(toPrc(data.initial, data.cached)) + " " +
|
||||
tpad.call((atime =
|
||||
data.initial ? ((data.time / data.initial) / 1000) : 0).toFixed(3) +
|
||||
"s") + " " + name + "\n";
|
||||
ppad.call(toPrc(data.initial, data.cached)) + " " + name + "\n";
|
||||
});
|
||||
log += "------------------------------------------------------------\n";
|
||||
return log;
|
||||
24
lib/ext/ref-counter.js
Normal file
24
lib/ext/ref-counter.js
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
require('../_base').ext.refCounter = function (ignore, conf) {
|
||||
var cache, get, clear;
|
||||
|
||||
cache = {};
|
||||
|
||||
conf.on('init', function (id) { cache[id] = 1; });
|
||||
conf.on('hit', function (id) { ++cache[id]; });
|
||||
conf.on('purge', function (id) { delete cache[id]; });
|
||||
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;
|
||||
};
|
||||
};
|
||||
38
lib/ext/resolvers.js
Normal file
38
lib/ext/resolvers.js
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
var toArray = require('es5-ext/lib/Array/from')
|
||||
, forEach = require('es5-ext/lib/Object/for-each')
|
||||
, callable = require('es5-ext/lib/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));
|
||||
};
|
||||
20
lib/index.js
Normal file
20
lib/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var regular = require('./regular')
|
||||
, primitive = require('./primitive')
|
||||
|
||||
, apply = Function.prototype.apply;
|
||||
|
||||
// Order is important!
|
||||
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 apply.call(options.primitive ? primitive : regular, this, arguments);
|
||||
};
|
||||
478
lib/memoize.js
478
lib/memoize.js
@@ -1,478 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var global = require('es5-ext/lib/global')
|
||||
, toArray = require('es5-ext/lib/Array/from')
|
||||
, clearArr = require('es5-ext/lib/Array/prototype/clear')
|
||||
, indexOf = require('es5-ext/lib/Array/prototype/e-index-of')
|
||||
, last = require('es5-ext/lib/Array/prototype/last')
|
||||
, remove = require('es5-ext/lib/Array/prototype/remove')
|
||||
, curry = require('es5-ext/lib/Function/prototype/curry')
|
||||
, partial = require('es5-ext/lib/Function/prototype/partial')
|
||||
, callable = require('es5-ext/lib/Object/valid-callable')
|
||||
, isCallable = require('es5-ext/lib/Object/is-callable')
|
||||
, isCopy = require('es5-ext/lib/Object/is-copy')
|
||||
, forEach = require('es5-ext/lib/Object/for-each')
|
||||
, isString = require('es5-ext/lib/String/is-string')
|
||||
, nextTick = require('next-tick')
|
||||
|
||||
, slice = Array.prototype.slice, now = Date.now
|
||||
, apply = Function.prototype.apply
|
||||
, create = Object.create, defineProperty = Object.defineProperty
|
||||
|
||||
, resolve, memoize;
|
||||
|
||||
resolve = function (args) {
|
||||
return this.map(function (r, i) {
|
||||
return r ? r(args[i]) : args[i];
|
||||
}).concat(slice.call(args, this.length));
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
memoize = module.exports = function (fn/*, options*/) {
|
||||
var mfn, options, length, resolver, method, cache, find, save, clear
|
||||
, value, primitive, serialize, profile, refCounter, async, initAsync
|
||||
, maxAge, max, queue, dispose, orgDispose, purgePrimitive;
|
||||
|
||||
callable(fn);
|
||||
if (fn.memoized) {
|
||||
// Prevent memoization of already memoized function
|
||||
return fn;
|
||||
}
|
||||
|
||||
options = Object(arguments[1]);
|
||||
|
||||
async = Boolean(options.async);
|
||||
if (isNaN(options.length)) {
|
||||
length = fn.length;
|
||||
if (async) {
|
||||
--length;
|
||||
}
|
||||
} else if (options.length === false) {
|
||||
length = false;
|
||||
} else {
|
||||
length = Number(options.length);
|
||||
}
|
||||
if (options.resolvers) {
|
||||
resolver = toArray(options.resolvers);
|
||||
resolver.forEach(function (r) {
|
||||
(r == null) || callable(r);
|
||||
});
|
||||
resolver = resolve.bind(resolver);
|
||||
}
|
||||
if (options.method) {
|
||||
if (isString(options.method)) {
|
||||
method = { name: String(options.method),
|
||||
descriptor: { configurable: true, writable: true } };
|
||||
} else {
|
||||
method = options.method;
|
||||
method.name = String(method.name);
|
||||
method.descriptor = (method.descriptor == null) ?
|
||||
{ configurable: true, writable: true } : Object(method.descriptor);
|
||||
}
|
||||
options = create(options);
|
||||
options.method = undefined;
|
||||
}
|
||||
primitive = Boolean(options.primitive);
|
||||
refCounter = Boolean(options.refCounter);
|
||||
maxAge = options.maxAge >>> 0;
|
||||
max = options.max >>> 0;
|
||||
if (options.dispose != null) {
|
||||
dispose = orgDispose = callable(options.dispose);
|
||||
if (async) {
|
||||
dispose = function (value) {
|
||||
if (value.value) {
|
||||
apply.call(orgDispose, null, slice.call(value.value, 1));
|
||||
}
|
||||
};
|
||||
} else if (refCounter) {
|
||||
dispose = function (value) { orgDispose(value.value); };
|
||||
}
|
||||
}
|
||||
|
||||
cache = primitive ? {} : [];
|
||||
|
||||
if (memoize._profile) {
|
||||
profile = memoize._profile();
|
||||
}
|
||||
|
||||
if (max) {
|
||||
queue = [];
|
||||
}
|
||||
|
||||
find = function (length, args) {
|
||||
var index = 0, rset = cache, i;
|
||||
|
||||
if (length === 0) {
|
||||
value = rset[length];
|
||||
return rset.hasOwnProperty(length);
|
||||
} else if ((rset = rset[length])) {
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(rset[0], args[index]);
|
||||
if (i === -1) {
|
||||
return false;
|
||||
}
|
||||
rset = rset[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(rset[0], args[index]);
|
||||
if (i === -1) {
|
||||
return false;
|
||||
}
|
||||
value = rset[1][i];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
save = function (length, args, value) {
|
||||
var index = 0, rset = cache, i;
|
||||
|
||||
if (length === 0) {
|
||||
rset[length] = value;
|
||||
} else {
|
||||
if (!rset[length]) {
|
||||
rset[length] = [[], []];
|
||||
}
|
||||
rset = rset[length];
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(rset[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = rset[0].push(args[index]) - 1;
|
||||
rset[1].push([[], []]);
|
||||
}
|
||||
rset = rset[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(rset[0], args[index]);
|
||||
if (i === -1) {
|
||||
i = rset[0].push(args[index]) - 1;
|
||||
}
|
||||
rset[1][i] = value;
|
||||
}
|
||||
};
|
||||
|
||||
clear = function (length, args) {
|
||||
var index = 0, rset = cache, i, path = [], value;
|
||||
|
||||
if (length === 0) {
|
||||
if (dispose && rset.hasOwnProperty("0")) {
|
||||
value = rset[0];
|
||||
delete rset[0];
|
||||
dispose(value);
|
||||
} else {
|
||||
delete rset[length];
|
||||
}
|
||||
} else if ((rset = rset[length])) {
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(rset[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
path.push(rset, i);
|
||||
rset = rset[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(rset[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
rset[0].splice(i, 1);
|
||||
if (dispose) {
|
||||
dispose(rset[1][i]);
|
||||
}
|
||||
rset[1].splice(i, 1);
|
||||
while (!rset[0].length && path.length) {
|
||||
i = path.pop();
|
||||
rset = path.pop();
|
||||
rset[0].splice(i, 1);
|
||||
rset[1].splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (primitive && (length !== 1)) {
|
||||
serialize = function (args, length) {
|
||||
var id = '', i;
|
||||
if (length) {
|
||||
id += args[i = 0];
|
||||
while (--length) {
|
||||
id += '\u0001' + args[++i];
|
||||
}
|
||||
} else {
|
||||
id = '\u0002';
|
||||
}
|
||||
return id;
|
||||
};
|
||||
}
|
||||
|
||||
purgePrimitive = function (id) {
|
||||
var value;
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
value = cache[id];
|
||||
delete cache[id];
|
||||
if (dispose) {
|
||||
dispose(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initAsync = function (args, cb, maxAgeData) {
|
||||
var waiting = cb ? [cb] : []
|
||||
, value = { waiting: waiting }, time;
|
||||
args.push(function (err) {
|
||||
var args2 = arguments;
|
||||
if (profile) {
|
||||
profile.time += (now() - time);
|
||||
}
|
||||
if (!err) {
|
||||
value.value = arguments;
|
||||
if (max) {
|
||||
if (primitive) {
|
||||
queue.push(maxAgeData);
|
||||
if (queue.length > max) {
|
||||
purgePrimitive(queue.shift());
|
||||
}
|
||||
} else {
|
||||
queue.push([maxAgeData, args]);
|
||||
if (queue.length > max) {
|
||||
clear.apply(null, queue.shift());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxAge) {
|
||||
setTimeout(primitive ? partial.call(purgePrimitive, maxAgeData) :
|
||||
partial.call(clear, maxAgeData, args.slice(0, -1)), maxAge);
|
||||
}
|
||||
} else {
|
||||
mfn.clear.apply(this, args.slice(0, -1));
|
||||
}
|
||||
waiting.forEach(function (cb) {
|
||||
cb.apply(null, args2);
|
||||
});
|
||||
delete value.waiting;
|
||||
});
|
||||
if (profile) {
|
||||
time = now();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
mfn = function () {
|
||||
var args, alength, id, cb, time;
|
||||
if (method && this && (this !== global)) {
|
||||
method.descriptor.value = memoize(fn.bind(this), options);
|
||||
defineProperty(this, method.name, method.descriptor);
|
||||
return method.descriptor.value.apply(this, arguments);
|
||||
}
|
||||
args = arguments;
|
||||
if (async) {
|
||||
cb = last.call(args);
|
||||
if (isCallable(cb)) {
|
||||
args = slice.call(args, 0, -1);
|
||||
} else {
|
||||
cb = null;
|
||||
}
|
||||
}
|
||||
if (resolver) {
|
||||
args = resolver(args);
|
||||
}
|
||||
alength = (length === false) ? args.length : length;
|
||||
|
||||
if (primitive) {
|
||||
id = (length === 1) ? args[0] : serialize(args, alength);
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
profile && ++profile.cached;
|
||||
value = cache[id];
|
||||
} else {
|
||||
profile && ++profile.initial;
|
||||
mfn.args = arguments;
|
||||
mfn.preventCache = false;
|
||||
if (async) {
|
||||
args = toArray(args);
|
||||
value = initAsync(args, cb, id);
|
||||
value.sync = apply.call(fn, this, args);
|
||||
} else {
|
||||
if (profile) {
|
||||
time = now();
|
||||
}
|
||||
value = apply.call(fn, this, args);
|
||||
if (profile) {
|
||||
profile.time += (now() - time);
|
||||
}
|
||||
}
|
||||
if (!mfn.preventCache) {
|
||||
if (refCounter) {
|
||||
if (async) {
|
||||
value.count = cb ? 1 : 0;
|
||||
} else {
|
||||
value = { value: value, count: 1 };
|
||||
}
|
||||
}
|
||||
cache[id] = value;
|
||||
if (max && !async) {
|
||||
queue.push(id);
|
||||
if (queue.length > max) {
|
||||
purgePrimitive(queue.shift());
|
||||
}
|
||||
}
|
||||
if (maxAge && !async) {
|
||||
setTimeout(partial.call(purgePrimitive, id), maxAge);
|
||||
}
|
||||
}
|
||||
delete mfn.args;
|
||||
return async ? value.sync : (refCounter ? value.value : value);
|
||||
}
|
||||
} else if (find(alength, args)) {
|
||||
profile && ++profile.cached;
|
||||
} else {
|
||||
profile && ++profile.initial;
|
||||
mfn.args = arguments;
|
||||
mfn.preventCache = false;
|
||||
if (async) {
|
||||
args = toArray(args);
|
||||
value = initAsync(args, cb, alength);
|
||||
value.sync = apply.call(fn, this, args);
|
||||
} else {
|
||||
if (profile) {
|
||||
time = now();
|
||||
}
|
||||
value = apply.call(fn, this, args);
|
||||
if (profile) {
|
||||
profile.time += (now() - time);
|
||||
}
|
||||
}
|
||||
if (!mfn.preventCache) {
|
||||
if (refCounter) {
|
||||
if (async) {
|
||||
value.count = cb ? 1 : 0;
|
||||
} else {
|
||||
value = { value: value, count: 1 };
|
||||
}
|
||||
}
|
||||
save(alength, args, value);
|
||||
if (max && !async) {
|
||||
queue.push([alength, args]);
|
||||
if (queue.length > max) {
|
||||
clear.apply(null, queue.shift());
|
||||
}
|
||||
}
|
||||
if (maxAge && !async) {
|
||||
setTimeout(partial.call(clear, alength, args), maxAge);
|
||||
}
|
||||
}
|
||||
delete mfn.args;
|
||||
return async ? value.sync : (refCounter ? value.value : value);
|
||||
}
|
||||
|
||||
if (async) {
|
||||
if (cb) {
|
||||
if (refCounter) {
|
||||
++value.count;
|
||||
}
|
||||
if (value.value) {
|
||||
nextTick(function () {
|
||||
cb.apply(null, this);
|
||||
}.bind(value.value));
|
||||
} else {
|
||||
value.waiting.push(cb);
|
||||
}
|
||||
}
|
||||
return value.sync;
|
||||
} else {
|
||||
if (refCounter) {
|
||||
++value.count;
|
||||
value = value.value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
mfn.memoized = true;
|
||||
|
||||
mfn.clear = function () {
|
||||
var args, alength, id;
|
||||
args = resolver ? resolver(arguments) : arguments;
|
||||
alength = (length === false) ? args.length : length;
|
||||
|
||||
if (primitive) {
|
||||
id = (length === 1) ? args[0] : serialize(args, alength);
|
||||
if (max) {
|
||||
remove.call(queue, id);
|
||||
}
|
||||
purgePrimitive(id);
|
||||
} else {
|
||||
if (max) {
|
||||
if (find.call(queue, function (data, index) {
|
||||
if (isCopy(data, [alength, args], 2)) {
|
||||
id = index;
|
||||
return true;
|
||||
}
|
||||
})) {
|
||||
queue.splice(id, 1);
|
||||
}
|
||||
}
|
||||
clear(alength, args);
|
||||
}
|
||||
};
|
||||
|
||||
mfn.clearAll = function () {
|
||||
if (dispose) {
|
||||
if (primitive) {
|
||||
forEach(cache, curry.call(dispose, 1));
|
||||
} else {
|
||||
cache.forEach(function self(value, index) {
|
||||
if (!index) {
|
||||
dispose(value);
|
||||
return;
|
||||
}
|
||||
--index;
|
||||
value[1].forEach(function (value) { self(value, index); });
|
||||
});
|
||||
}
|
||||
}
|
||||
if (max) {
|
||||
clearArr.call(queue);
|
||||
}
|
||||
cache = primitive ? {} : [];
|
||||
};
|
||||
|
||||
if (refCounter) {
|
||||
mfn.clearRef = function () {
|
||||
var args, alength, id;
|
||||
args = resolver ? resolver(arguments) : arguments;
|
||||
alength = (length === false) ? args.length : length;
|
||||
|
||||
if (primitive) {
|
||||
id = (length === 1) ? args[0] : serialize(args, alength);
|
||||
if (!cache.hasOwnProperty(id)) {
|
||||
return null;
|
||||
}
|
||||
value = cache[id];
|
||||
} else if (!find(alength, args)) {
|
||||
return null;
|
||||
}
|
||||
if (!--value.count) {
|
||||
mfn.clear.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
return mfn;
|
||||
};
|
||||
81
lib/primitive.js
Normal file
81
lib/primitive.js
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict';
|
||||
|
||||
var hasListeners = require('event-emitter/lib/has-listeners')
|
||||
|
||||
, getId0 = function () { return ''; }
|
||||
, getId1 = function (args) { return args[0]; }
|
||||
|
||||
, apply = Function.prototype.apply, call = Function.prototype.call;
|
||||
|
||||
module.exports = require('./_base')(function (conf, length) {
|
||||
var get, cache = conf.cache = {}, fn
|
||||
, hitListeners, initListeners, purgeListeners;
|
||||
|
||||
if (length === 1) {
|
||||
get = conf.get = getId1;
|
||||
} else if (length === false) {
|
||||
get = conf.get = function (args, length) {
|
||||
var id = '', i;
|
||||
if (length) {
|
||||
id += args[i = 0];
|
||||
while (--length) {
|
||||
id += '\u0001' + args[++i];
|
||||
}
|
||||
} else {
|
||||
id = '\u0002';
|
||||
}
|
||||
return id;
|
||||
};
|
||||
} 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 = getId0;
|
||||
}
|
||||
|
||||
conf.memoized = (length === 1) ? function (id) {
|
||||
var value;
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
hitListeners && conf.emit('hit', id);
|
||||
return cache[id];
|
||||
} else {
|
||||
if (arguments.length === 1) {
|
||||
value = call.call(fn, this, id);
|
||||
} else {
|
||||
value = apply.call(fn, this, arguments);
|
||||
}
|
||||
cache[id] = value;
|
||||
initListeners && conf.emit('init', id);
|
||||
return value;
|
||||
}
|
||||
} : function () {
|
||||
var id = get(arguments), value;
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
hitListeners && conf.emit('hit', id);
|
||||
return cache[id];
|
||||
} else {
|
||||
value = apply.call(conf.fn, this, arguments);
|
||||
cache[id] = value;
|
||||
initListeners && conf.emit('init', id);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
conf.clear = function (id) {
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
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');
|
||||
});
|
||||
});
|
||||
240
lib/regular.js
Normal file
240
lib/regular.js
Normal file
@@ -0,0 +1,240 @@
|
||||
'use strict';
|
||||
|
||||
var indexOf = require('es5-ext/lib/Array/prototype/e-index-of')
|
||||
, hasListeners = require('event-emitter/lib/has-listeners')
|
||||
|
||||
, apply = Function.prototype.apply
|
||||
|
||||
, getId0 = function () { return ''; };
|
||||
|
||||
// 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 = {};
|
||||
|
||||
if (length === 0) {
|
||||
get = set = clear = conf.get = getId0;
|
||||
conf.clearAll = function () { cache = conf.cache = {}; };
|
||||
} else {
|
||||
count = 0;
|
||||
if (length === 1) {
|
||||
map1 = []; map2 = [];
|
||||
get = conf.get = function (args) {
|
||||
return map2[indexOf.call(map1, args[0])];
|
||||
};
|
||||
set = function (args) {
|
||||
map1.push(args[0]);
|
||||
map2.push(++count);
|
||||
return count;
|
||||
};
|
||||
clear = function (args) {
|
||||
var index = indexOf.call(map1, args[0]), id;
|
||||
if (index !== -1) {
|
||||
id = map2[index];
|
||||
map1.splice(index, 1);
|
||||
map2.splice(index, 1);
|
||||
return id;
|
||||
}
|
||||
};
|
||||
conf.clearAll = function () {
|
||||
map1 = [];
|
||||
map2 = [];
|
||||
cache = conf.cache = {};
|
||||
};
|
||||
} else if (length === false) {
|
||||
map = [];
|
||||
get = conf.get = function (args) {
|
||||
var index = 0, set = map, i, length = args.length;
|
||||
if (length === 0) {
|
||||
return set[length];
|
||||
} else if ((set = set[length])) {
|
||||
while (index < (length - 1)) {
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
set = set[1][i];
|
||||
++index;
|
||||
}
|
||||
i = indexOf.call(set[0], args[index]);
|
||||
if (i === -1) {
|
||||
return;
|
||||
}
|
||||
return set[1][i];
|
||||
}
|
||||
return;
|
||||
};
|
||||
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;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
clear = function (args) {
|
||||
var index = 0, set = map, i, length = args.length, path =[], id;
|
||||
if (length === 0) {
|
||||
id = set[length];
|
||||
delete set[length];
|
||||
return id;
|
||||
} 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);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
};
|
||||
conf.clearAll = function () {
|
||||
map = [];
|
||||
cache = conf.cache = {};
|
||||
};
|
||||
} else {
|
||||
map = [[], []];
|
||||
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];
|
||||
};
|
||||
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;
|
||||
return count;
|
||||
};
|
||||
clear = function (args) {
|
||||
var index = 0, set = map, i, path =[], 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);
|
||||
}
|
||||
return id;
|
||||
};
|
||||
conf.clearAll = function () {
|
||||
map = [[], []];
|
||||
cache = conf.cache = {};
|
||||
};
|
||||
}
|
||||
}
|
||||
conf.memoized = function () {
|
||||
var id = get(arguments), value;
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
hitListeners && conf.emit('hit', id);
|
||||
return cache[id];
|
||||
} else {
|
||||
value = apply.call(fn, this, arguments);
|
||||
id = set(arguments);
|
||||
cache[id] = value;
|
||||
initListeners && conf.emit('init', id);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
conf.clear = function (id) {
|
||||
if (cache.hasOwnProperty(id)) {
|
||||
clear(id);
|
||||
purgeListeners && conf.emit('purge', id);
|
||||
delete cache[id];
|
||||
}
|
||||
};
|
||||
|
||||
conf.once('ready', function () {
|
||||
fn = conf.fn;
|
||||
hitListeners = hasListeners(conf, 'hit');
|
||||
initListeners = hasListeners(conf, 'init');
|
||||
purgeListeners = hasListeners(conf, 'purge');
|
||||
});
|
||||
});
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "memoizee",
|
||||
"version": "0.1.1",
|
||||
"description": "Complete memoize/cache solution. Works with any type and length of function arguments",
|
||||
"main": "lib/memoize",
|
||||
"main": "lib",
|
||||
"scripts": {
|
||||
"test": "node node_modules/tad/bin/tad lib"
|
||||
},
|
||||
@@ -35,6 +35,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"es5-ext": "0.9.x",
|
||||
"event-emitter": "~0.2.1",
|
||||
"next-tick": "0.1.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
15
test/_base.js
Normal file
15
test/_base.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (t, a) {
|
||||
var mfn, m = t(function (conf, length) {
|
||||
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");
|
||||
};
|
||||
351
test/ext/async.js
Normal file
351
test/ext/async.js
Normal file
@@ -0,0 +1,351 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
module.exports = function (a) {
|
||||
return {
|
||||
"Regular": {
|
||||
"Success": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0, invoked = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Init Called");
|
||||
a(invoked, 5, "Cb Called");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Init Called #2");
|
||||
a(invoked, 7, "Cb Called #2");
|
||||
|
||||
mfn.clear(3, 7);
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Init After clear");
|
||||
a(invoked, 9, "Cb After clear");
|
||||
d();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
"Reference counter": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, refCounter: true });
|
||||
|
||||
a(mfn.clearRef(3, 7), null, "Clear ref before");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
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(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Call After clear");
|
||||
d();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
"Error": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0, e = new Error("Test");
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(e);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 4, "Again Called #2");
|
||||
d();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
"Primitive": {
|
||||
"Success": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, primitive: true });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
mfn.clear(3, 7);
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Call After clear");
|
||||
d();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
"Reference counter": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, primitive: true, refCounter: true });
|
||||
|
||||
a(mfn.clearRef(3, 7), null, "Clear ref before");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
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(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Call After clear");
|
||||
d();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
"Error": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0, e = new Error("Test");
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(e);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, primitive: true });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [e, undefined], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 4, "Again Called #2");
|
||||
d();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
191
test/ext/dispose.js
Normal file
191
test/ext/dispose.js
Normal file
@@ -0,0 +1,191 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
module.exports = function (a) {
|
||||
return {
|
||||
"Regular": {
|
||||
"Sync": function (a) {
|
||||
var mfn, fn, i = 0, value = [], x, invoked;
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { dispose: function (val) { value.push(val); } });
|
||||
|
||||
mfn(3, 7);
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
|
||||
x = {};
|
||||
invoked = false;
|
||||
mfn = memoize(function () { return x; },
|
||||
{ dispose: function (val) { invoked = val; } });
|
||||
|
||||
mfn.clear();
|
||||
a(invoked, false, "No args: Post invalid clear");
|
||||
mfn();
|
||||
a(invoked, false, "No args: Post cache");
|
||||
mfn.clear();
|
||||
a(invoked, x, "No args: Pre clear");
|
||||
},
|
||||
"Ref counter": function (a) {
|
||||
var mfn, fn, i = 0, value = [];
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { refCounter: true,
|
||||
dispose: function (val) { value.push(val); } });
|
||||
|
||||
mfn(3, 7);
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn(5, 8);
|
||||
mfn.clearRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clearRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clearRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0, value = [];
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true,
|
||||
dispose: function (val) { value.push(val); } });
|
||||
|
||||
mfn(3, 7, function () {
|
||||
mfn(5, 8, function () {
|
||||
mfn(12, 4, function () {
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11, function () {
|
||||
mfn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
d();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
"Primitive": {
|
||||
"Sync": function (a) {
|
||||
var mfn, fn, i = 0, value = [];
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { dispose: function (val) { value.push(val); } });
|
||||
|
||||
mfn(3, 7);
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Ref counter": function (a) {
|
||||
var mfn, fn, i = 0, value = [];
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { refCounter: true,
|
||||
dispose: function (val) { value.push(val); } });
|
||||
|
||||
mfn(3, 7);
|
||||
mfn(5, 8);
|
||||
mfn(12, 4);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn(5, 8);
|
||||
mfn.clearRef(5, 8);
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clearRef(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clearRef(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11);
|
||||
mfn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0, value = [];
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true,
|
||||
dispose: function (val) { value.push(val); } });
|
||||
|
||||
mfn(3, 7, function () {
|
||||
mfn(5, 8, function () {
|
||||
mfn(12, 4, function () {
|
||||
a.deep(value, [], "Pre");
|
||||
mfn.clear(5, 8);
|
||||
a.deep(value, [13], "#1");
|
||||
value = [];
|
||||
mfn.clear(12, 4);
|
||||
a.deep(value, [16], "#2");
|
||||
|
||||
value = [];
|
||||
mfn(77, 11, function () {
|
||||
mfn.clearAll();
|
||||
a.deep(value, [10, 88], "Clear all");
|
||||
d();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
201
test/ext/max-age.js
Normal file
201
test/ext/max-age.js
Normal file
@@ -0,0 +1,201 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
module.exports = function (a) {
|
||||
return {
|
||||
"Regular": {
|
||||
"Sync": function (a, d) {
|
||||
var mfn, fn, i = 0;
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { maxAge: 100 });
|
||||
|
||||
a(mfn(3, 7), 10, "Result #1");
|
||||
a(i, 1, "Called #1");
|
||||
a(mfn(3, 7), 10, "Result #2");
|
||||
a(i, 1, "Called #2");
|
||||
a(mfn(5, 8), 13, "Result B #1");
|
||||
a(i, 2, "Called B #1");
|
||||
a(mfn(3, 7), 10, "Result #3");
|
||||
a(i, 2, "Called #3");
|
||||
a(mfn(5, 8), 13, "Result B #2");
|
||||
a(i, 2, "Called B #2");
|
||||
|
||||
setTimeout(function () {
|
||||
a(mfn(3, 7), 10, "Result: Wait");
|
||||
a(i, 2, "Called: Wait");
|
||||
a(mfn(5, 8), 13, "Result: Wait B");
|
||||
a(i, 2, "Called: Wait B");
|
||||
|
||||
setTimeout(function () {
|
||||
a(mfn(3, 7), 10, "Result: Wait After");
|
||||
a(i, 3, "Called: Wait After");
|
||||
a(mfn(5, 8), 13, "Result: Wait After B");
|
||||
a(i, 4, "Called: Wait After B");
|
||||
|
||||
a(mfn(3, 7), 10, "Result: Wait After #2");
|
||||
a(i, 4, "Called: Wait After #2");
|
||||
a(mfn(5, 8), 13, "Result: Wait After B #2");
|
||||
a(i, 4, "Called: Wait After B #2");
|
||||
d();
|
||||
}, 100);
|
||||
}, 20);
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, maxAge: 100 });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
setTimeout(function () {
|
||||
a(i, 2, "Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
setTimeout(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 4, "Call After clear");
|
||||
d();
|
||||
});
|
||||
}, 100);
|
||||
}, 20);
|
||||
}
|
||||
},
|
||||
"Primitive": {
|
||||
"Sync": function (a, d) {
|
||||
var mfn, fn, i = 0;
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { primitive: true, maxAge: 100 });
|
||||
|
||||
a(mfn(3, 7), 10, "Result #1");
|
||||
a(i, 1, "Called #1");
|
||||
a(mfn(3, 7), 10, "Result #2");
|
||||
a(i, 1, "Called #2");
|
||||
a(mfn(5, 8), 13, "Result B #1");
|
||||
a(i, 2, "Called B #1");
|
||||
a(mfn(3, 7), 10, "Result #3");
|
||||
a(i, 2, "Called #3");
|
||||
a(mfn(5, 8), 13, "Result B #2");
|
||||
a(i, 2, "Called B #2");
|
||||
|
||||
setTimeout(function () {
|
||||
a(mfn(3, 7), 10, "Result: Wait");
|
||||
a(i, 2, "Called: Wait");
|
||||
a(mfn(5, 8), 13, "Result: Wait B");
|
||||
a(i, 2, "Called: Wait B");
|
||||
|
||||
setTimeout(function () {
|
||||
a(mfn(3, 7), 10, "Result: Wait After");
|
||||
a(i, 3, "Called: Wait After");
|
||||
a(mfn(5, 8), 13, "Result: Wait After B");
|
||||
a(i, 4, "Called: Wait After B");
|
||||
|
||||
a(mfn(3, 7), 10, "Result: Wait After #2");
|
||||
a(i, 4, "Called: Wait After #2");
|
||||
a(mfn(5, 8), 13, "Result: Wait After B #2");
|
||||
a(i, 4, "Called: Wait After B #2");
|
||||
d();
|
||||
}, 100);
|
||||
}, 20);
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, primitive: true, maxAge: 100 });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
setTimeout(function () {
|
||||
a(i, 2, "Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
setTimeout(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 4, "Call After clear");
|
||||
d();
|
||||
});
|
||||
}, 100);
|
||||
}, 20);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
361
test/ext/max.js
Normal file
361
test/ext/max.js
Normal file
@@ -0,0 +1,361 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
, nextTick = require('next-tick');
|
||||
|
||||
module.exports = function (a) {
|
||||
return {
|
||||
"Regular": {
|
||||
"Sync": function (a) {
|
||||
var mfn, fn, i = 0;
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { max: 3 });
|
||||
|
||||
a(mfn(3, 7), 10, "Result #1");
|
||||
a(i, 1, "Called #1");
|
||||
a(mfn(3, 7), 10, "Result #2");
|
||||
a(i, 1, "Called #2");
|
||||
a(mfn(5, 8), 13, "Result B #1");
|
||||
a(i, 2, "Called B #1");
|
||||
a(mfn(3, 7), 10, "Result #3");
|
||||
a(i, 2, "Called #3");
|
||||
a(mfn(5, 8), 13, "Result B #2");
|
||||
a(i, 2, "Called B #2");
|
||||
a(mfn(12, 4), 16, "Result C #1");
|
||||
a(i, 3, "Called C #1");
|
||||
a(mfn(3, 7), 10, "Result #4");
|
||||
a(i, 3, "Called #4");
|
||||
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(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(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7), 10, "Result #5"); // Clear 77, 11
|
||||
a(i, 6, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Clear 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(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, max: 3 });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
a(i, 1, "Called #1");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
a(i, 1, "Called #2");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
a(i, 2, "Called B #1");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
a(i, 2, "Called #3");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
a(i, 2, "Called B #2");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16], "Result C #1");
|
||||
a(i, 3, "Called C #1");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #4");
|
||||
a(i, 3, "Called #4");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #3");
|
||||
a(i, 3, "Called B #3");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88], "Result D #1");
|
||||
a(i, 4, "Called D #1");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #4");
|
||||
a(i, 4, "Called B #4");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16], "Result C #2");
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #5");
|
||||
a(i, 6, "Called #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #2");
|
||||
a(i, 7, "Called D #2");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16],
|
||||
"Result C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #5");
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(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();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
|
||||
a(mfn(77, 11,
|
||||
function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
|
||||
d();
|
||||
}), u, "Initial D #5");
|
||||
}), u, "Initial B #6");
|
||||
}), u, "Initial D #4");
|
||||
}), u, "Initial D #3");
|
||||
}), u, "Initial B #5");
|
||||
}), u, "Initial C #3");
|
||||
}), u, "Initial D #2");
|
||||
}), u, "Initial #5");
|
||||
}), u, "Initial C #2");
|
||||
}), u, "Initial B #4");
|
||||
}), u, "Initial D #1");
|
||||
}), u, "Initial B #3");
|
||||
}), u, "Initial #4");
|
||||
}), u, "Initial C #1");
|
||||
}), u, "Initial B #2");
|
||||
}), u, "Initial #3");
|
||||
}), u, "Initial B #1");
|
||||
}), u, "Initial #2");
|
||||
}), u, "Initial #1");
|
||||
}
|
||||
},
|
||||
"Primitive": {
|
||||
"Sync": function (a) {
|
||||
var mfn, fn, i = 0;
|
||||
fn = function (x, y) {
|
||||
++i;
|
||||
return x + y;
|
||||
};
|
||||
mfn = memoize(fn, { primitive: true, max: 3 });
|
||||
|
||||
a(mfn(3, 7), 10, "Result #1");
|
||||
a(i, 1, "Called #1");
|
||||
a(mfn(3, 7), 10, "Result #2");
|
||||
a(i, 1, "Called #2");
|
||||
a(mfn(5, 8), 13, "Result B #1");
|
||||
a(i, 2, "Called B #1");
|
||||
a(mfn(3, 7), 10, "Result #3");
|
||||
a(i, 2, "Called #3");
|
||||
a(mfn(5, 8), 13, "Result B #2");
|
||||
a(i, 2, "Called B #2");
|
||||
a(mfn(12, 4), 16, "Result C #1");
|
||||
a(i, 3, "Called C #1");
|
||||
a(mfn(3, 7), 10, "Result #4");
|
||||
a(i, 3, "Called #4");
|
||||
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(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(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7), 10, "Result #5"); // Clear 77, 11
|
||||
a(i, 6, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Clear 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(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
cb(null, x + y);
|
||||
});
|
||||
return u;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { async: true, primitive: true, max: 3 });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
a(i, 1, "Called #1");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
a(i, 1, "Called #2");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
a(i, 2, "Called B #1");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
a(i, 2, "Called #3");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
a(i, 2, "Called B #2");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16], "Result C #1");
|
||||
a(i, 3, "Called C #1");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #4");
|
||||
a(i, 3, "Called #4");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #3");
|
||||
a(i, 3, "Called B #3");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88], "Result D #1");
|
||||
a(i, 4, "Called D #1");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13], "Result B #4");
|
||||
a(i, 4, "Called B #4");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16], "Result C #2");
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #5");
|
||||
a(i, 6, "Called #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #2");
|
||||
a(i, 7, "Called D #2");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16],
|
||||
"Result C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #5");
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(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();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
|
||||
a(mfn(77, 11,
|
||||
function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
|
||||
d();
|
||||
}), u, "Initial D #5");
|
||||
}), u, "Initial B #6");
|
||||
}), u, "Initial D #4");
|
||||
}), u, "Initial D #3");
|
||||
}), u, "Initial B #5");
|
||||
}), u, "Initial C #3");
|
||||
}), u, "Initial D #2");
|
||||
}), u, "Initial #5");
|
||||
}), u, "Initial C #2");
|
||||
}), u, "Initial B #4");
|
||||
}), u, "Initial D #1");
|
||||
}), u, "Initial B #3");
|
||||
}), u, "Initial #4");
|
||||
}), u, "Initial C #1");
|
||||
}), u, "Initial B #2");
|
||||
}), u, "Initial #3");
|
||||
}), u, "Initial B #1");
|
||||
}), u, "Initial #2");
|
||||
}), u, "Initial #1");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
34
test/ext/method.js
Normal file
34
test/ext/method.js
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib');
|
||||
|
||||
module.exports = function (a) {
|
||||
return {
|
||||
"No descriptor": function (a) {
|
||||
var mfn, x = {}, i = 0, fn = function () {
|
||||
++i;
|
||||
return this;
|
||||
};
|
||||
|
||||
mfn = memoize(fn, { method: 'foo' });
|
||||
a(mfn.call(x), x, "Context");
|
||||
a(x.foo(), x, "Method");
|
||||
a(i, 1, "Cached");
|
||||
},
|
||||
"Descriptor": function (a) {
|
||||
var mfn, x = {}, i = 0, fn = function () {
|
||||
++i;
|
||||
return this;
|
||||
};
|
||||
|
||||
mfn = memoize(fn,
|
||||
{ method: { name: 'foo', descriptor: { configurable: true } } });
|
||||
a(mfn.call(x), 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,9 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../lib/memoize');
|
||||
var memoize = require('../../lib');
|
||||
|
||||
module.exports = function (t, a) {
|
||||
a(typeof memoize._profile, 'function', "Set on memoize");
|
||||
a(typeof t.statistics, 'object', "Access to statistics");
|
||||
a(typeof t.log, 'function', "Access to log function");
|
||||
a(typeof t.log(), 'string', "Log outputs string");
|
||||
};
|
||||
48
test/ext/ref-counter.js
Normal file
48
test/ext/ref-counter.js
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
var memoize = require('../../lib')
|
||||
|
||||
module.exports = function (a) {
|
||||
return {
|
||||
"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(3, 5, 7), 15, "Initial");
|
||||
a(mfn(3, 5, 7), 15, "Cache");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #1");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #2");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(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");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Restarted");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Cached again");
|
||||
},
|
||||
"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(3, 5, 7), 15, "Initial");
|
||||
a(mfn(3, 5, 7), 15, "Cache");
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #1");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(3, 5, 7), false, "Clear #2");
|
||||
mfn(3, 5, 7);
|
||||
a(mfn.clearRef(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");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Restarted");
|
||||
mfn(3, 5, 7);
|
||||
a(i, 2, "Cached again");
|
||||
}
|
||||
};
|
||||
};
|
||||
47
test/ext/resolvers.js
Normal file
47
test/ext/resolvers.js
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
|
||||
var toArray = require('es5-ext/lib/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 toArray(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(toArray(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(toArray(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(toArray(r = fn(1, 34, x, 34)),
|
||||
[true, '34', x, 34], "Second");
|
||||
a(fn(1, 34, x, 89), r, "Third");
|
||||
a(i, 2, "Called once");
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -121,7 +121,7 @@ module.exports = function (t, a) {
|
||||
"Original arguments": function (a) {
|
||||
var fn, mfn, x = {};
|
||||
fn = function (x, y) { x = y; return toArray(mfn.args); };
|
||||
mfn = t(fn);
|
||||
mfn = t(fn, { resolvers: [] });
|
||||
|
||||
a.deep(mfn(23, 'raz', x), [23, 'raz', x]);
|
||||
},
|
||||
@@ -320,7 +320,7 @@ module.exports = function (t, a) {
|
||||
"Async": {
|
||||
"Regular": {
|
||||
"Success": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
var mfn, fn, u = {}, i = 0, invoked = 0;
|
||||
fn = function (x, y, cb) {
|
||||
nextTick(function () {
|
||||
++i;
|
||||
@@ -332,45 +332,57 @@ module.exports = function (t, a) {
|
||||
mfn = t(fn, { async: true });
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Result #1");
|
||||
}), u, "Initial");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Result #2");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Result B #1");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Result #3");
|
||||
}), u, "Initial #2");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Result B #2");
|
||||
}), u, "Initial #3");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Called #2");
|
||||
a(i, 2, "Init Called");
|
||||
a(invoked, 5, "Cb Called");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 2, "Again Called #2");
|
||||
a(i, 2, "Init Called #2");
|
||||
a(invoked, 7, "Cb Called #2");
|
||||
|
||||
mfn.clear(3, 7);
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 10], "Again: Result");
|
||||
}), u, "Again: Initial");
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
++invoked;
|
||||
a.deep([err, res], [null, 13], "Again B: Result");
|
||||
}), u, "Again B: Initial");
|
||||
|
||||
nextTick(function () {
|
||||
a(i, 3, "Call After clear");
|
||||
a(i, 3, "Init After clear");
|
||||
a(invoked, 9, "Cb After clear");
|
||||
d();
|
||||
});
|
||||
});
|
||||
@@ -870,35 +882,35 @@ module.exports = function (t, a) {
|
||||
a(mfn(5, 8), 13, "Result B #3");
|
||||
a(i, 3, "Called B #3");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #1"); // Clear 3, 7
|
||||
a(mfn(77, 11), 88, "Result D #1"); // Clear 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");
|
||||
a(i, 4, "Called C #2");
|
||||
a(mfn(12, 4), 16, "Result C #2"); // Clear 3, 7
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7), 10, "Result #5"); // Clear 5, 8
|
||||
a(i, 5, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2");
|
||||
a(i, 5, "Called D #2");
|
||||
a(mfn(3, 7), 10, "Result #5"); // Clear 77, 11
|
||||
a(i, 6, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Clear 5, 8
|
||||
a(i, 7, "Called D #2");
|
||||
a(mfn(12, 4), 16, "Result C #3");
|
||||
a(i, 5, "Called C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8), 13, "Result B #5"); // Clear 12, 4
|
||||
a(i, 6, "Called B #5");
|
||||
a(mfn(5, 8), 13, "Result B #5"); // Clear 3, 7
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 6, "Called D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 7, "Called D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 8, "Called B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
a(i, 9, "Called D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
@@ -954,49 +966,49 @@ module.exports = function (t, a) {
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16], "Result C #2");
|
||||
a(i, 4, "Called C #2");
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #5");
|
||||
a(i, 5, "Called #5");
|
||||
a(i, 6, "Called #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #2");
|
||||
a(i, 5, "Called D #2");
|
||||
a(i, 7, "Called D #2");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16],
|
||||
"Result C #3");
|
||||
a(i, 5, "Called C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #5");
|
||||
a(i, 6, "Called B #5");
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #3");
|
||||
a(i, 6, "Called D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #4");
|
||||
a(i, 7, "Called D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
a(i, 8, "Called B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
|
||||
a(mfn(77, 11,
|
||||
function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #5");
|
||||
a(i, 9, "Called D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
|
||||
d();
|
||||
}), u, "Initial D #5");
|
||||
@@ -1046,35 +1058,35 @@ module.exports = function (t, a) {
|
||||
a(mfn(5, 8), 13, "Result B #3");
|
||||
a(i, 3, "Called B #3");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #1");
|
||||
a(mfn(77, 11), 88, "Result D #1"); // Clear 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");
|
||||
a(i, 4, "Called C #2");
|
||||
a(mfn(12, 4), 16, "Result C #2"); // Clear 3, 7
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7), 10, "Result #5");
|
||||
a(i, 5, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2");
|
||||
a(i, 5, "Called D #2");
|
||||
a(mfn(3, 7), 10, "Result #5"); // Clear 77, 11
|
||||
a(i, 6, "Called #5");
|
||||
a(mfn(77, 11), 88, "Result D #2"); // Clear 5, 8
|
||||
a(i, 7, "Called D #2");
|
||||
a(mfn(12, 4), 16, "Result C #3");
|
||||
a(i, 5, "Called C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8), 13, "Result B #5");
|
||||
a(i, 6, "Called B #5");
|
||||
a(mfn(5, 8), 13, "Result B #5"); // Clear 3, 7
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11), 88, "Result D #3");
|
||||
a(i, 6, "Called D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
a(mfn(77, 11), 88, "Result D #4");
|
||||
a(i, 7, "Called D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
a(mfn(5, 8), 13, "Result B #6");
|
||||
a(i, 8, "Called B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
a(mfn(77, 11), 88, "Result D #5");
|
||||
a(i, 9, "Called D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
},
|
||||
"Async": function (a, d) {
|
||||
var mfn, fn, u = {}, i = 0;
|
||||
@@ -1130,48 +1142,49 @@ module.exports = function (t, a) {
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16], "Result C #2");
|
||||
a(i, 4, "Called C #2");
|
||||
a(i, 5, "Called C #2");
|
||||
|
||||
a(mfn(3, 7, function (err, res) {
|
||||
a.deep([err, res], [null, 10], "Result #5");
|
||||
a(i, 5, "Called #5");
|
||||
a(i, 6, "Called #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #2");
|
||||
a(i, 5, "Called D #2");
|
||||
a(i, 7, "Called D #2");
|
||||
|
||||
a(mfn(12, 4, function (err, res) {
|
||||
a.deep([err, res], [null, 16],
|
||||
"Result C #3");
|
||||
a(i, 5, "Called C #3");
|
||||
a(i, 7, "Called C #3");
|
||||
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #5");
|
||||
a(i, 6, "Called B #5");
|
||||
a(i, 8, "Called B #5");
|
||||
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #3");
|
||||
a(i, 6, "Called D #3");
|
||||
a(i, 8, "Called D #3");
|
||||
|
||||
mfn.clear(77, 11);
|
||||
a(mfn(77, 11, function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #4");
|
||||
a(i, 7, "Called D #4");
|
||||
a(i, 9, "Called D #4");
|
||||
|
||||
mfn.clearAll();
|
||||
a(mfn(5, 8, function (err, res) {
|
||||
a.deep([err, res], [null, 13],
|
||||
"Result B #6");
|
||||
a(i, 8, "Called B #6");
|
||||
a(i, 10, "Called B #6");
|
||||
|
||||
a(mfn(77, 11,
|
||||
function (err, res) {
|
||||
a.deep([err, res], [null, 88],
|
||||
"Result D #5");
|
||||
a(i, 9, "Called D #5");
|
||||
a(i, 11, "Called D #5");
|
||||
|
||||
d();
|
||||
}), u, "Initial D #5");
|
||||
41
test/primitive.js
Normal file
41
test/primitive.js
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (t, a) {
|
||||
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");
|
||||
},
|
||||
"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");
|
||||
}
|
||||
};
|
||||
};
|
||||
175
test/regular.js
Normal file
175
test/regular.js
Normal file
@@ -0,0 +1,175 @@
|
||||
'use strict';
|
||||
|
||||
var toArray = require('es5-ext/lib/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(toArray(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(toArray(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(toArray(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) {
|
||||
if (c === 3) {
|
||||
++i;
|
||||
}
|
||||
return arguments;
|
||||
};
|
||||
|
||||
mfn = t(fn);
|
||||
mfn(1, x, 3);
|
||||
mfn(1, x, 4);
|
||||
mfn.clear(1, x, 4);
|
||||
mfn(1, x, 3);
|
||||
mfn(1, x, 3);
|
||||
a(i, 1, "Pre clear");
|
||||
mfn.clear(1, x, 3);
|
||||
mfn(1, x, 3);
|
||||
a(i, 2, "After clear");
|
||||
|
||||
i = 0;
|
||||
mfn = t(fn, { length: false });
|
||||
mfn(1, x, 3);
|
||||
mfn(1, x, 3);
|
||||
mfn();
|
||||
mfn();
|
||||
mfn.clear();
|
||||
mfn(1, x, 3);
|
||||
a(i, 1, "Proper no arguments clear");
|
||||
},
|
||||
"All": function () {
|
||||
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");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user