Last active
September 27, 2018 23:53
-
-
Save dsherret/dde191b7a68c19c14155def5b157fe51 to your computer and use it in GitHub Desktop.
A weak cache with support for ES5.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class WeakCache<T extends object, U> { | |
private readonly cacheItems: WeakDictionary<T, U>; | |
constructor() { | |
if (typeof WeakMap !== "undefined") | |
this.cacheItems = new WeakMap<T, U>(); | |
else | |
this.cacheItems = new Es5WeakMap(); | |
} | |
getOrCreate<TCreate extends U = U>(key: T, createFunc: () => TCreate) { | |
let item = this.get(key) as TCreate; | |
if (item == null) { | |
item = createFunc(); | |
this.set(key, item); | |
} | |
return item; | |
} | |
has(key: T) { | |
return this.cacheItems.has(key); | |
} | |
get(key: T) { | |
return this.cacheItems.get(key); | |
} | |
set(key: T, value: U) { | |
this.cacheItems.set(key, value); | |
} | |
removeByKey(key: T) { | |
this.cacheItems.delete(key); | |
} | |
} | |
export interface WeakDictionary<K extends object, V> { | |
get(key: K): V | undefined; | |
set(key: K, value: V): void; | |
has(key: K): boolean; | |
delete(key: K): void; | |
} | |
export class Es5WeakMap<K extends object, V> implements WeakDictionary<K, V> { | |
private propSaver = new Es5PropSaver<K, V>(); | |
get(key: K) { | |
return this.propSaver.get(key); | |
} | |
set(key: K, value: V) { | |
this.propSaver.set(key, value); | |
} | |
has(key: K) { | |
return this.propSaver.get(key) != null; | |
} | |
delete(key: K) { | |
this.propSaver.remove(key); | |
} | |
} | |
export class Es5PropSaver<TObject, TValue> { | |
private readonly propName = `__key_${Es5PropSaver.instanceCount++}`; | |
private static instanceCount = 0; | |
get(obj: TObject) { | |
return (obj as any)[this.propName] as TValue | undefined; | |
} | |
set(obj: TObject, value: TValue) { | |
Object.defineProperty(obj, this.propName, { | |
configurable: true, | |
enumerable: false, | |
writable: false, | |
value | |
}); | |
} | |
remove(obj: TObject) { | |
delete (obj as any)[this.propName]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment