这是一个 JavaScript
TupleSet
,即包含唯一元组的集合,其中每个元组内的顺序并不重要(在某些方面类似于 Java 中的 MultiKeyMap
):
export class TupleSet {
tuples = new Set<Array<unknown>>()
add(tuple: Array<unknown>) {
return this.#findTuple(
tuple,
() => false, // found (not added)
() => {
this.tuples.add(tuple)
return true // not found (added)
},
)
}
delete(tuple: Array<unknown>) {
return this.#findTuple(
tuple,
tuple => {
this.tuples.delete(tuple)
return true // found (deleted)
},
() => false, // not found (not deleted)
)
}
has(tuple: Array<unknown>) {
return this.#findTuple(
tuple,
() => true,
() => false,
)
}
#findTuple(tuple: Array<unknown>, onFound: (foundTuple: Array<unknown>) => boolean, onNotFound: () => boolean) {
outer: for (const testTuple of this.tuples) {
if (tuple.length !== testTuple.length) continue
for (const value of tuple) if (!testTuple.includes(value)) continue outer
return onFound(testTuple)
}
return onNotFound()
}
}
我们如何制作一个weakTupleSet(名为WeakTupleSet),使得如果元组中的至少一项不再被WeakTupleSet外部引用,则该元组会自动从WeakTupleSet中删除?
(如果集合之外的用户代码没有对元组中的项目的所有原始引用,则不可能再次使用该元组,因此应从集合中删除该元组)
示例:
const set = new WeakTupleSet()
globalThis.obj1 = {}
globalThis.obj2 = {}
globalThis.obj3 = {}
const tuple = [globalThis.obj1, globalThis.obj2, globalThis.obj3]
set.add(tuple)
set.has(tuple) // true
// later, unreference obj2
tuple[1] = undefined
delete globalThis.obj2
// even later, the set should no longer contain the tuple, and obj2 is fully garbage collected
我有一种感觉 WeakRef 舞蹈可能是可能的。
我认为您不需要
WeakRef
,但 WeakSet
会派上用场,并且已知尺寸,可用于比较。然后按照您的计划使用 FinalisationRegistry
从集合中删除不完整的条目。
class WeakEntry<T> extends WeakSet<T> {
constructor(elements) {
super(elements);
this.size = (elements instanceof Set ? elements : new Set(elements)).size;
}
equals(other: Set<T>): boolean {
if (this.size != other.size) return false;
for (const el of other) if (!this.has(el)) return false;
return true;
}
}
export class WeakSetSet<T extends object> {
#entries = new Set<WeakEntry<T>>();
#cleanup = new FinalisationRegistry(entry => {
this.#entries.delete(entry);
});
add(values: Set<T>): boolean {
for (const entry of this.#entries) if (entry.equals(values)) {
return false; // found (not added)
}
const newEntry = new WeakEntry(values);
for (const value of values) {
this.#cleanup.register(value, newEntry);
}
this.#entries.add(newEntry)
return true; // not found (added)
}
delete(values: Set<T>): boolean {
for (const entry of this.#entries) if (entry.equals(values)) {
this.#entries.delete(entry);
return true; // found (deleted)
}
return false; // not found (not deleted)
}
add(values: Set<T>): boolean {
for (const entry of this.#entries) if (entry.equals(values)) {
return true;
}
return false;
}
}
关键是
#cleanup.register(value, newEntry)
中的 add
:当任何 values
被垃圾收集时,newEntry
就会从 #entries
中删除。