export default class WeakValueMap {
constructor(items = []) {
this._map = new Map;
for (let [key, value] of items)
this.set(key, value);
}
// Public
get size() {
let size = 0;
for (let wrapper of this._map.values()) {
if (wrapper.deref())
++size;
}
return size;
}
has(key) {
let wrapper = this._map.get(key);
return !!wrapper?.deref();
}
get(key) {
let wrapper = this._map.get(key);
return wrapper?.deref();
}
set(key, value) {
console.assert(typeof value === "object", value);
console.assert(value !== null, value);
this._map.set(key, new WeakRef(value));
this._finalizationRegistry.register(value, {weakThis: new WeakRef(this), key: new WeakRef(key)}, key);
}
delete(key) {
let result = this._map.delete(key);
this._finalizationRegistry.unregister(key);
return result;
}
take(key) {
let wrapper = this._map.get(key);
this._map.delete(key);
this._finalizationRegistry.unregister(key);
return wrapper?.deref();
}
clear() {
for (let key of this._map.keys())
this._finalizationRegistry.unregister(key);
this._map.clear();
}
*keys() {
for (let entry of this.entries())
yield entry[0];
}
*values() {
for (let entry of this.entries())
yield entry[1];
}
*entries() {
for (let [key, wrapper] of this._map) {
let value = wrapper.deref();
if (value)
yield [key, value];
}
}
[Symbol.iterator]() {
return this.entries();
}
toJSON() {
return Array.from(this);
}
// Private
get _finalizationRegistry() {
return WeakValueMap._finalizationRegistry ??= new FinalizationRegistry(function(heldValue) {
heldValue.weakThis.deref()?._map.delete(heldValue.key.deref());
});
}
}