function.js (3339B)
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 }