Skip to content

Instantly share code, notes, and snippets.

@SwadicalRag
Last active June 3, 2023 12:01
Show Gist options
  • Save SwadicalRag/ad637b1f6105c5a0b8b43e7900a5e5aa to your computer and use it in GitHub Desktop.
Save SwadicalRag/ad637b1f6105c5a0b8b43e7900a5e5aa to your computer and use it in GitHub Desktop.
Two way weak map in TypeScript
class TwoWayWeakMap {
constructor() {
this.keyToValue = new WeakMap();
this.valueToKey = new WeakMap();
this.keys = new Set();
this.values = new Set();
}
set(key, value) {
const weakValue = new WeakRef(value);
const weakKey = new WeakRef(key);
this.keyToValue.set(key, weakValue);
this.valueToKey.set(value, weakKey);
this.keys.add(new WeakRef(key));
this.values.add(new WeakRef(value));
}
getValue(key) {
const weakValue = this.keyToValue.get(key);
if (!weakValue) {
return undefined;
}
const value = weakValue.deref();
if (!value) {
this.keyToValue.delete(key);
this.cleanup();
}
return value;
}
getKey(value) {
const weakKey = this.valueToKey.get(value);
if (!weakKey) {
return undefined;
}
const key = weakKey.deref();
if (!key) {
this.valueToKey.delete(value);
this.cleanup();
}
return key;
}
cleanupRefs(refSet) {
for (let ref of refSet) {
if (ref.deref() === undefined) {
refSet.delete(ref);
}
}
}
cleanup() {
this.cleanupRefs(this.keys);
this.cleanupRefs(this.values);
}
}
class TwoWayWeakMap<K extends object, V extends object> {
private keyToValue: WeakMap<K, WeakRef<V>>;
private valueToKey: WeakMap<V, WeakRef<K>>;
private keys: Set<WeakRef<K>>;
private values: Set<WeakRef<V>>;
constructor() {
this.keyToValue = new WeakMap<K, WeakRef<V>>();
this.valueToKey = new WeakMap<V, WeakRef<K>>();
this.keys = new Set<WeakRef<K>>();
this.values = new Set<WeakRef<V>>();
}
set(key: K, value: V): void {
const weakValue = new WeakRef<V>(value);
const weakKey = new WeakRef<K>(key);
this.keyToValue.set(key, weakValue);
this.valueToKey.set(value, weakKey);
this.keys.add(new WeakRef<K>(key));
this.values.add(new WeakRef<V>(value));
}
getValue(key: K): V | undefined {
const weakValue = this.keyToValue.get(key);
if (!weakValue) {
return undefined;
}
const value = weakValue.deref();
if (!value) {
this.keyToValue.delete(key);
this.cleanup();
}
return value;
}
getKey(value: V): K | undefined {
const weakKey = this.valueToKey.get(value);
if (!weakKey) {
return undefined;
}
const key = weakKey.deref();
if (!key) {
this.valueToKey.delete(value);
this.cleanup();
}
return key;
}
private cleanupRefs(refSet: Set<WeakRef<K | V>>): void {
for (let ref of refSet) {
if (ref.deref() === undefined) {
refSet.delete(ref);
}
}
}
cleanup(): void {
this.cleanupRefs(this.keys);
this.cleanupRefs(this.values);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment