这是 JS 中的 TupleSet。我们怎样才能使它成为WeakTupleSet?

问题描述 投票:0回答:1

这是一个 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 舞蹈可能是可能的。

javascript tuples weak-references multikey weakmap
1个回答
0
投票

我认为您不需要

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
中删除。

© www.soinside.com 2019 - 2024. All rights reserved.