@@ -36,47 +36,85 @@ export class Cache<T> {
36
36
}
37
37
}
38
38
39
+ export function identity < T > ( t : T ) : T {
40
+ return t ;
41
+ }
42
+
43
+ interface ICacheOptions < TArg > {
44
+ /**
45
+ * The cache key is used to identify the cache entry.
46
+ * Strict equality is used to compare cache keys.
47
+ */
48
+ getCacheKey : ( arg : TArg ) => unknown ;
49
+ }
50
+
39
51
/**
40
52
* Uses a LRU cache to make a given parametrized function cached.
41
- * Caches just the last value.
53
+ * Caches just the last key/ value.
42
54
*/
43
55
export class LRUCachedFunction < TArg , TComputed > {
44
56
private lastCache : TComputed | undefined = undefined ;
45
57
private lastArgKey : unknown | undefined = undefined ;
46
58
47
- constructor (
48
- private readonly fn : ( arg : TArg ) => TComputed ,
49
- private readonly _computeKey : ( arg : TArg ) => unknown = JSON . stringify ,
50
- ) {
59
+ private readonly _fn : ( arg : TArg ) => TComputed ;
60
+ private readonly _computeKey : ( arg : TArg ) => unknown ;
61
+
62
+ constructor ( fn : ( arg : TArg ) => TComputed ) ;
63
+ constructor ( options : ICacheOptions < TArg > , fn : ( arg : TArg ) => TComputed ) ;
64
+ constructor ( arg1 : ICacheOptions < TArg > | ( ( arg : TArg ) => TComputed ) , arg2 ?: ( arg : TArg ) => TComputed ) {
65
+ if ( typeof arg1 === 'function' ) {
66
+ this . _fn = arg1 ;
67
+ this . _computeKey = identity ;
68
+ } else {
69
+ this . _fn = arg2 ! ;
70
+ this . _computeKey = arg1 . getCacheKey ;
71
+ }
51
72
}
52
73
53
74
public get ( arg : TArg ) : TComputed {
54
75
const key = this . _computeKey ( arg ) ;
55
76
if ( this . lastArgKey !== key ) {
56
77
this . lastArgKey = key ;
57
- this . lastCache = this . fn ( arg ) ;
78
+ this . lastCache = this . _fn ( arg ) ;
58
79
}
59
80
return this . lastCache ! ;
60
81
}
61
82
}
62
83
63
84
/**
64
- * Uses an unbounded cache (referential equality) to memoize the results of the given function.
85
+ * Uses an unbounded cache to memoize the results of the given function.
65
86
*/
66
- export class CachedFunction < TArg , TValue > {
67
- private readonly _map = new Map < TArg , TValue > ( ) ;
68
- public get cachedValues ( ) : ReadonlyMap < TArg , TValue > {
87
+ export class CachedFunction < TArg , TComputed > {
88
+ private readonly _map = new Map < TArg , TComputed > ( ) ;
89
+ private readonly _map2 = new Map < unknown , TComputed > ( ) ;
90
+ public get cachedValues ( ) : ReadonlyMap < TArg , TComputed > {
69
91
return this . _map ;
70
92
}
71
93
72
- constructor ( private readonly fn : ( arg : TArg ) => TValue ) { }
94
+ private readonly _fn : ( arg : TArg ) => TComputed ;
95
+ private readonly _computeKey : ( arg : TArg ) => unknown ;
73
96
74
- public get ( arg : TArg ) : TValue {
75
- if ( this . _map . has ( arg ) ) {
76
- return this . _map . get ( arg ) ! ;
97
+ constructor ( fn : ( arg : TArg ) => TComputed ) ;
98
+ constructor ( options : ICacheOptions < TArg > , fn : ( arg : TArg ) => TComputed ) ;
99
+ constructor ( arg1 : ICacheOptions < TArg > | ( ( arg : TArg ) => TComputed ) , arg2 ?: ( arg : TArg ) => TComputed ) {
100
+ if ( typeof arg1 === 'function' ) {
101
+ this . _fn = arg1 ;
102
+ this . _computeKey = identity ;
103
+ } else {
104
+ this . _fn = arg2 ! ;
105
+ this . _computeKey = arg1 . getCacheKey ;
77
106
}
78
- const value = this . fn ( arg ) ;
107
+ }
108
+
109
+ public get ( arg : TArg ) : TComputed {
110
+ const key = this . _computeKey ( arg ) ;
111
+ if ( this . _map2 . has ( key ) ) {
112
+ return this . _map2 . get ( key ) ! ;
113
+ }
114
+
115
+ const value = this . _fn ( arg ) ;
79
116
this . _map . set ( arg , value ) ;
117
+ this . _map2 . set ( key , value ) ;
80
118
return value ;
81
119
}
82
120
}
0 commit comments