-
Notifications
You must be signed in to change notification settings - Fork 9
/
memoize.ts
56 lines (51 loc) · 2.18 KB
/
memoize.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import type {AnyToAnyFnSignature} from './functions';
/** Memoized function type */
export type MemoizedFn<T extends AnyToAnyFnSignature> = T & {
/** Cache instance */
cache: Map<null | string, ReturnType<T>>;
/** Clear memoization cache */
clear: () => void;
/** Check existence of cache for passed params */
has: (...params: Parameters<T>) => boolean;
};
/**
* Memoization decorator function. Caches the original function result according to hash generated from arguments.
* In case the hash function returns `undefined` value will not be memoized.
* @see MemoHashFn Hash function signature.
*/
export function memoizeFn<F extends AnyToAnyFnSignature>(fn: F, hashFn: MemoHashFn<F> = defaultArgsHashFn): MemoizedFn<F> {
function memo(...args: Parameters<F>): any {
const key = hashFn(...args);
if (key !== null && typeof key !== 'string') {
console.warn(`[ESL]: Can't cache value for ${fn.name} call.`);
return fn.apply(this, args);
}
if (!memo.cache.has(key)) {
memo.cache.set(key, fn.apply(this, args));
}
return memo.cache.get(key);
}
memo.cache = new Map<null | string, ReturnType<F>>();
memo.clear = (): void => memo.cache.clear();
memo.has = (...args: Parameters<F>): boolean => {
const key = hashFn(...args);
return key === undefined ? false : memo.cache.has(key);
};
return memo as MemoizedFn<F>;
}
/**
* Describe abstract memoization hash function. Memoization should have the same or compatible signature as the decorated function.
* Hash function can return string or null as a hash result. Note: null is correct hash for arguments!
* If the result is `undefined` - it means that the hash can not be generated.
*/
export type MemoHashFn<F extends AnyToAnyFnSignature = AnyToAnyFnSignature> = (...args: Parameters<F>) => undefined | null | string;
/**
* Default arguments hash function.
* Supports only 0-1 arguments with a primitive type.
*/
export function defaultArgsHashFn(...args: any[]): string | null | undefined {
if (args.length === 0) return null;
if (args.length > 1) return;
if (typeof args[0] !== 'string' && typeof args[0] !== 'number' && typeof args[0] !== 'boolean') return;
return String(args[0]);
}