mirror of
https://github.com/BreizhHardware/memoizee.git
synced 2026-01-18 16:37:21 +01:00
- Move out main modules from `lib` folder - Introduce `normalizer` based configurations, and convert primitive and regular handlers into thos normalizers (can be found in lib/normalizers folder). Custom normalizers can be provided at run time via `normaizer` option - Provide `plain` module which does not load any extensions or normalizers. Any extensions that have to be used should be required upfront and normalizers should be provided directly - Remove `method` option, instead `methods` and `methods-plan` modules are provided which generate descriptors for lazy created memoized methods - `profile` is no longer extension. To be used it should be required directly - Improve logic for `async` handling - Take out `max` extensionLRU logic into external `lru-queue` package - Remove `context` option - Remove possibility to access original arguments when resolvers are used - Assure expected length of memoized functions
145 lines
4.3 KiB
JavaScript
145 lines
4.3 KiB
JavaScript
'use strict';
|
|
|
|
var toArray = require('es5-ext/array/to-array')
|
|
, customError = require('es5-ext/error/custom')
|
|
, defineLength = require('es5-ext/function/_define-length')
|
|
, callable = require('es5-ext/object/valid-callable')
|
|
, d = require('d')
|
|
, ee = require('event-emitter').methods
|
|
|
|
, slice = Array.prototype.slice
|
|
, apply = Function.prototype.apply, call = Function.prototype.call
|
|
, create = Object.create, hasOwnProperty = Object.prototype.hasOwnProperty
|
|
, defineProperties = Object.defineProperties
|
|
, on = ee.on, emit = ee.emit, resolveArgs;
|
|
|
|
resolveArgs = function (args) {
|
|
return this.map(function (r, i) {
|
|
return r ? r(args[i]) : args[i];
|
|
}).concat(slice.call(args, this.length));
|
|
};
|
|
|
|
module.exports = function (original, length, options) {
|
|
var cache = create(null), conf, memLength, get, set, del, clear
|
|
, getListeners, setListeners, deleteListeners, memoized, resolve, resolvers;
|
|
if (length !== false) memLength = length;
|
|
else if (isNaN(original.length)) memLength = 1;
|
|
else memLength = original.length;
|
|
|
|
if (options.normalizer) {
|
|
get = callable(options.normalizer.get);
|
|
if (options.normalizer.set !== undefined) {
|
|
set = callable(options.normalizer.set);
|
|
del = callable(options.normalizer.delete);
|
|
clear = callable(options.normalizer.clear);
|
|
} else {
|
|
set = get;
|
|
}
|
|
} else if (options.serialize) {
|
|
set = get = (function (serialize) {
|
|
return function (args) { return serialize.apply(null, args); };
|
|
}(callable(options.serialize)));
|
|
}
|
|
|
|
if (options.resolvers != null) {
|
|
resolvers = toArray(options.resolvers);
|
|
resolvers.forEach(function (r) {
|
|
if (r != null) callable(r);
|
|
});
|
|
resolve = resolveArgs.bind(resolvers);
|
|
}
|
|
|
|
if (get) {
|
|
memoized = defineLength(function (arg) {
|
|
var id, result, args = arguments;
|
|
if (resolve) args = resolve(args);
|
|
id = get(args);
|
|
if (id !== null) {
|
|
if (hasOwnProperty.call(cache, id)) {
|
|
if (getListeners) conf.emit('get', id, args, this);
|
|
return cache[id];
|
|
}
|
|
}
|
|
if (args.length === 1) result = call.call(original, this, arg);
|
|
else result = apply.call(original, this, args);
|
|
if (id === null) {
|
|
id = get(args);
|
|
if (id !== null) throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
|
id = set(args);
|
|
} else if (hasOwnProperty.call(cache, id)) {
|
|
throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
|
}
|
|
cache[id] = result;
|
|
if (setListeners) conf.emit('set', id);
|
|
return result;
|
|
}, memLength);
|
|
} else {
|
|
memoized = function (arg) {
|
|
var result, args = arguments;
|
|
if (resolve) {
|
|
args = resolve(arguments);
|
|
arg = args[0];
|
|
}
|
|
if (hasOwnProperty.call(cache, arg)) {
|
|
if (getListeners) conf.emit('get', arg, args, this);
|
|
return cache[arg];
|
|
}
|
|
if (args.length === 1) result = call.call(original, this, arg);
|
|
else result = apply.call(original, this, args);
|
|
if (hasOwnProperty.call(cache, arg)) {
|
|
throw customError("Circular invocation", 'CIRCULAR_INVOCATION');
|
|
}
|
|
cache[arg] = result;
|
|
if (setListeners) conf.emit('set', arg);
|
|
return result;
|
|
};
|
|
}
|
|
conf = {
|
|
original: original,
|
|
memoized: memoized,
|
|
get: function (args) {
|
|
if (resolve) args = resolve(args);
|
|
if (get) return get(args);
|
|
return args[0];
|
|
},
|
|
has: function (id) { return hasOwnProperty.call(cache, id); },
|
|
delete: function (id) {
|
|
var result;
|
|
if (!hasOwnProperty.call(cache, id)) return;
|
|
if (del) del(id);
|
|
result = cache[id];
|
|
delete cache[id];
|
|
if (deleteListeners) conf.emit('delete', id, result);
|
|
},
|
|
clear: function () {
|
|
var oldCache = cache;
|
|
if (clear) clear();
|
|
cache = create(null);
|
|
conf.emit('clear', oldCache);
|
|
},
|
|
on: function (type, listener) {
|
|
if (type === 'get') getListeners = true;
|
|
else if (type === 'set') setListeners = true;
|
|
else if (type === 'delete') deleteListeners = true;
|
|
return on.call(this, type, listener);
|
|
},
|
|
emit: emit,
|
|
updateEnv: function () { original = conf.original; }
|
|
};
|
|
defineProperties(memoized, {
|
|
__memoized__: d(true),
|
|
delete: d(get ? defineLength(function (arg) {
|
|
var id, args = arguments;
|
|
if (resolve) args = resolve(args);
|
|
id = get(args);
|
|
if (id === null) return;
|
|
conf.delete(id);
|
|
}, memLength) : function (arg) {
|
|
if (resolve) arg = resolve(arguments)[0];
|
|
return conf.delete(arg);
|
|
}),
|
|
clear: d(conf.clear)
|
|
});
|
|
return conf;
|
|
};
|