1 | // function utils
|
2 | import { lruQueue } from './lruQueue.js';
|
3 | /**
|
4 | * Memoize a given function by caching the computed result.
|
5 | * The cache of a memoized function can be cleared by deleting the `cache`
|
6 | * property of the function.
|
7 | *
|
8 | * @param {function} fn The function to be memoized.
|
9 | * Must be a pure function.
|
10 | * @param {Object} [options]
|
11 | * @param {function(args: Array): string} [options.hasher]
|
12 | * A custom hash builder. Is JSON.stringify by default.
|
13 | * @param {number | undefined} [options.limit]
|
14 | * Maximum number of values that may be cached. Undefined indicates
|
15 | * unlimited (default)
|
16 | * @return {function} Returns the memoized function
|
17 | */
|
18 |
|
19 | export function memoize(fn) {
|
20 | var {
|
21 | hasher,
|
22 | limit
|
23 | } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
24 | limit = limit == null ? Number.POSITIVE_INFINITY : limit;
|
25 | hasher = hasher == null ? JSON.stringify : hasher;
|
26 | return function memoize() {
|
27 | if (typeof memoize.cache !== 'object') {
|
28 | memoize.cache = {
|
29 | values: new Map(),
|
30 | lru: lruQueue(limit || Number.POSITIVE_INFINITY)
|
31 | };
|
32 | }
|
33 |
|
34 | var args = [];
|
35 |
|
36 | for (var i = 0; i < arguments.length; i++) {
|
37 | args[i] = arguments[i];
|
38 | }
|
39 |
|
40 | var hash = hasher(args);
|
41 |
|
42 | if (memoize.cache.values.has(hash)) {
|
43 | memoize.cache.lru.hit(hash);
|
44 | return memoize.cache.values.get(hash);
|
45 | }
|
46 |
|
47 | var newVal = fn.apply(fn, args);
|
48 | memoize.cache.values.set(hash, newVal);
|
49 | memoize.cache.values.delete(memoize.cache.lru.hit(hash));
|
50 | return newVal;
|
51 | };
|
52 | }
|
53 | /**
|
54 | * Memoize a given function by caching all results and the arguments,
|
55 | * and comparing against the arguments of previous results before
|
56 | * executing again.
|
57 | * This is less performant than `memoize` which calculates a hash,
|
58 | * which is very fast to compare. Use `memoizeCompare` only when it is
|
59 | * not possible to create a unique serializable hash from the function
|
60 | * arguments.
|
61 | * The isEqual function must compare two sets of arguments
|
62 | * and return true when equal (can be a deep equality check for example).
|
63 | * @param {function} fn
|
64 | * @param {function(a: *, b: *) : boolean} isEqual
|
65 | * @returns {function}
|
66 | */
|
67 |
|
68 | export function memoizeCompare(fn, isEqual) {
|
69 | var memoize = function memoize() {
|
70 | var args = [];
|
71 |
|
72 | for (var i = 0; i < arguments.length; i++) {
|
73 | args[i] = arguments[i];
|
74 | }
|
75 |
|
76 | for (var c = 0; c < memoize.cache.length; c++) {
|
77 | var cached = memoize.cache[c];
|
78 |
|
79 | if (isEqual(args, cached.args)) {
|
80 | // TODO: move this cache entry to the top so recently used entries move up?
|
81 | return cached.res;
|
82 | }
|
83 | }
|
84 |
|
85 | var res = fn.apply(fn, args);
|
86 | memoize.cache.unshift({
|
87 | args,
|
88 | res
|
89 | });
|
90 | return res;
|
91 | };
|
92 |
|
93 | memoize.cache = [];
|
94 | return memoize;
|
95 | }
|
96 | /**
|
97 | * Find the maximum number of arguments expected by a typed function.
|
98 | * @param {function} fn A typed function
|
99 | * @return {number} Returns the maximum number of expected arguments.
|
100 | * Returns -1 when no signatures where found on the function.
|
101 | */
|
102 |
|
103 | export function maxArgumentCount(fn) {
|
104 | return Object.keys(fn.signatures || {}).reduce(function (args, signature) {
|
105 | var count = (signature.match(/,/g) || []).length + 1;
|
106 | return Math.max(args, count);
|
107 | }, -1);
|
108 | } |
\ | No newline at end of file |