UNPKG

4.7 kBJavaScriptView Raw
1/**
2 * Created by Andy Likuski on 2018.12.28
3 * Copyright (c) 2018 Andy Likuski
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 *
7 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 */
11import * as R from 'ramda';
12import NamedTupleMap from 'namedtuplemap';
13import {flattenObj} from './functions';
14
15/**
16 *
17 * Code modified from memoize-immutable. Memoizes a function using a flatArg version of the args
18 * @param {Function} fn Function expecting any number of arguments
19 * @returns {function([*], Object)} A function expecting
20 * an array of the normal args for the second argument
21 * an object of flattened args for the first argument
22 */
23const memoize = fn => {
24 const cache = new NamedTupleMap();
25
26 const memoized = R.curry((normalArgs, flatArg) => {
27 if (!cache.has(flatArg)) {
28 const result = R.apply(fn, normalArgs);
29 cache.set(flatArg, result);
30 return result;
31 }
32 return cache.get(flatArg);
33 });
34
35
36 // Give a meaningful displayName to the memoized function
37 if (fn.name) {
38 memoized.displayName = fn.name + 'Memoized';
39 }
40
41 return memoized;
42};
43
44/** *
45 * Memomizes a function to a single argument function so that we can always NamedTupleMap for the cache.
46 * In order for this to work all objects have to be flattened into one big object. This Cache won't
47 * accept inner objects that have changed. So the function coverts three args like
48 * {a: {wombat: 1, emu: 2}}, {b: {caracal: 1, serval: 2}}, 'hamster' to
49 * {arg1.a: {wombat: 1, emu: 2}, arg2.b: {caracal: 1, serval: 2}, arg3: 'hamster}.
50 * You can provide any depth of objects as arguments, but it will have performance penalties
51 * Consider memoizedWith to filter out unimportant data from arguments
52 * @param {Function} func A function with any number and type of args
53 * @returns {Function} A function that expects the same args as func
54 */
55export const memoized = func => {
56 return memoizedWith((...args) => args, func);
57};
58
59/** *
60 * Memomizes a function to a single argument function so that we can always NamedTupleMap for the cache.
61 * In order for this to work all objects have to be flattened into one big object. This Cache won't
62 * accept inner objects that have changed. So the function coverts three args like
63 * {a: {wombat: 1, emu: 2}}, {b: {caracal: 1, serval: 2}}, 'hamster' to
64 * {arg1.a: {wombat: 1, emu: 2}, arg2.b: {caracal: 1, serval: 2}, arg3: 'hamster}.
65 * You can provide any depth of objects as arguments, but it will have performance penalties.
66 * To simplify the arguments and remove incomparable things like functions, use argumentFilter.
67 * @param {Function} argumentFilter Expects the same number of arguments as func and returns an equal
68 * number in an array. Each argument can be filtered to remove expensive objects or functions. Make
69 * sure not to filter out anything that is used by func, since it will not figure into the argument uniqueness
70 * @param {Function} func A function with any number and type of args. argumentFilter must match it
71 * @returns {Function} A function that expects the same args as func. This function is curried, expecting
72 * whatever number of arguments func is declared with, so you can call it partially
73 */
74export const memoizedWith = (argumentFilter, func) => {
75 // memoize(func) returns the memoized function expecting args and the flattened obj
76 const memo = memoize(func);
77 // Returns a function expecting the args for fun
78 return R.curryN(func.length, (...args) => {
79 // Function that flattens the original args and called memoizedFunc with the single flattened arg
80 return R.compose(
81 memo(args),
82 flattenObj,
83 // Filter out unneeded parts of the arguments, or does nothing if argumentFilter is ...args => args
84 R.apply(argumentFilter)
85 )(args);
86 });
87};