You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.8 KiB
134 lines
3.8 KiB
"use strict"; |
|
|
|
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; |
|
}; |
|
};
|
|
|