Spaces:
Runtime error
Runtime error
; | |
var customError = require("es5-ext/error/custom") | |
, defineLength = require("es5-ext/function/_define-length") | |
, partial = require("es5-ext/function/#/partial") | |
, copy = require("es5-ext/object/copy") | |
, normalizeOpts = require("es5-ext/object/normalize-options") | |
, callable = require("es5-ext/object/valid-callable") | |
, d = require("d") | |
, WeakMap = require("es6-weak-map") | |
, resolveLength = require("./resolve-length") | |
, extensions = require("./registered-extensions") | |
, resolveResolve = require("./resolve-resolve") | |
, resolveNormalize = require("./resolve-normalize"); | |
var slice = Array.prototype.slice, defineProperties = Object.defineProperties; | |
module.exports = function (memoize) { | |
return function (fn/*, options*/) { | |
var map, length, options = normalizeOpts(arguments[1]), memoized, resolve, normalizer; | |
callable(fn); | |
// Do not memoize already memoized function | |
if (hasOwnProperty.call(fn, "__memoized__") && !options.force) return fn; | |
length = resolveLength(options.length, fn.length, options.async && extensions.async); | |
options.length = length ? length - 1 : 0; | |
map = new WeakMap(); | |
if (options.resolvers) resolve = resolveResolve(options.resolvers); | |
if (options.normalizer) normalizer = resolveNormalize(options.normalizer); | |
if ( | |
length === 1 && | |
!normalizer && | |
!options.async && | |
!options.dispose && | |
!options.maxAge && | |
!options.max && | |
!options.refCounter | |
) { | |
return defineProperties( | |
function (obj) { | |
var result, args = arguments; | |
if (resolve) args = resolve(args); | |
obj = args[0]; | |
if (map.has(obj)) return map.get(obj); | |
result = fn.apply(this, args); | |
if (map.has(obj)) { | |
throw customError("Circular invocation", "CIRCULAR_INVOCATION"); | |
} | |
map.set(obj, result); | |
return result; | |
}, | |
{ | |
__memoized__: d(true), | |
delete: d(function (obj) { | |
if (resolve) obj = resolve(arguments)[0]; | |
return map.delete(obj); | |
}) | |
} | |
); | |
} | |
memoized = defineProperties( | |
defineLength(function (obj) { | |
var memoizer, args = arguments; | |
if (resolve) { | |
args = resolve(args); | |
obj = args[0]; | |
} | |
memoizer = map.get(obj); | |
if (!memoizer) { | |
if (normalizer) { | |
options = copy(options); | |
options.normalizer = copy(normalizer); | |
options.normalizer.get = partial.call(options.normalizer.get, obj); | |
options.normalizer.set = partial.call(options.normalizer.set, obj); | |
if (options.normalizer.delete) { | |
options.normalizer.delete = partial.call( | |
options.normalizer.delete, obj | |
); | |
} | |
} | |
map.set(obj, memoizer = memoize(partial.call(fn, obj), options)); | |
} | |
return memoizer.apply(this, slice.call(args, 1)); | |
}, length), | |
{ | |
__memoized__: d(true), | |
delete: d( | |
defineLength(function (obj) { | |
var memoizer, args = arguments; | |
if (resolve) { | |
args = resolve(args); | |
obj = args[0]; | |
} | |
memoizer = map.get(obj); | |
if (!memoizer) return; | |
memoizer.delete.apply(this, slice.call(args, 1)); | |
}, length) | |
) | |
} | |
); | |
if (!options.refCounter) return memoized; | |
defineProperties(memoized, { | |
deleteRef: d( | |
defineLength(function (obj) { | |
var memoizer, args = arguments; | |
if (resolve) { | |
args = resolve(args); | |
obj = args[0]; | |
} | |
memoizer = map.get(obj); | |
if (!memoizer) return null; | |
return memoizer.deleteRef.apply(this, slice.call(args, 1)); | |
}, length) | |
), | |
getRefCount: d( | |
defineLength(function (obj) { | |
var memoizer, args = arguments; | |
if (resolve) { | |
args = resolve(args); | |
obj = args[0]; | |
} | |
memoizer = map.get(obj); | |
if (!memoizer) return 0; | |
return memoizer.getRefCount.apply(this, slice.call(args, 1)); | |
}, length) | |
) | |
}); | |
return memoized; | |
}; | |
}; | |