Skip to content

Commit c132d06

Browse files
authored
Improves cache utilities (microsoft#210471)
1 parent 55f2a29 commit c132d06

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

src/vs/base/common/cache.ts

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,47 +36,85 @@ export class Cache<T> {
3636
}
3737
}
3838

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+
3951
/**
4052
* Uses a LRU cache to make a given parametrized function cached.
41-
* Caches just the last value.
53+
* Caches just the last key/value.
4254
*/
4355
export class LRUCachedFunction<TArg, TComputed> {
4456
private lastCache: TComputed | undefined = undefined;
4557
private lastArgKey: unknown | undefined = undefined;
4658

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+
}
5172
}
5273

5374
public get(arg: TArg): TComputed {
5475
const key = this._computeKey(arg);
5576
if (this.lastArgKey !== key) {
5677
this.lastArgKey = key;
57-
this.lastCache = this.fn(arg);
78+
this.lastCache = this._fn(arg);
5879
}
5980
return this.lastCache!;
6081
}
6182
}
6283

6384
/**
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.
6586
*/
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> {
6991
return this._map;
7092
}
7193

72-
constructor(private readonly fn: (arg: TArg) => TValue) { }
94+
private readonly _fn: (arg: TArg) => TComputed;
95+
private readonly _computeKey: (arg: TArg) => unknown;
7396

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;
77106
}
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);
79116
this._map.set(arg, value);
117+
this._map2.set(key, value);
80118
return value;
81119
}
82120
}

src/vs/base/common/strings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,7 @@ export class AmbiguousCharacters {
11491149
private static readonly cache = new LRUCachedFunction<
11501150
string[],
11511151
AmbiguousCharacters
1152-
>((locales) => {
1152+
>({ getCacheKey: JSON.stringify }, (locales) => {
11531153
function arrayToMap(arr: number[]): Map<number, number> {
11541154
const result = new Map<number, number>();
11551155
for (let i = 0; i < arr.length; i += 2) {

src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ export class BulkEditPane extends ViewPane {
410410
resources,
411411
getResourceDiffEditorInputIdOfOperation
412412
};
413-
}, key => key);
413+
});
414414

415415
private _onContextMenu(e: ITreeContextMenuEvent<any>): void {
416416

0 commit comments

Comments
 (0)