simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

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 }