function frozenStringArray(values) {
    return Object.freeze([...values]);
}
function frozenEntries(entries) {
    return Object.freeze([...entries]);
}
function copyEntryMap(source) {
    const entries = new Map();
    for (const [element, dots] of source.entries) {
        entries.set(element, frozenStringArray(dots));
    }
    return entries;
}
/**
 * Read-side OR-set view for public immutable snapshots.
 */
export default class SnapshotORSet {
    #entries;
    #tombstones;
    #tombstoneSet;
    constructor(source) {
        this.#entries = copyEntryMap(source);
        this.#tombstones = frozenStringArray(source.tombstones);
        this.#tombstoneSet = new Set(this.#tombstones);
        Object.freeze(this);
    }
    contains(element) {
        const dots = this.#entries.get(element);
        if (dots === undefined) {
            return false;
        }
        return dots.some((dot) => !this.#tombstoneSet.has(dot));
    }
    elements() {
        const elements = [];
        for (const element of this.#entries.keys()) {
            if (this.contains(element)) {
                elements.push(element);
            }
        }
        return Object.freeze(elements);
    }
    countEntries() {
        let count = 0;
        for (const dots of this.#entries.values()) {
            count += dots.length;
        }
        return count;
    }
    countLiveDots() {
        let count = 0;
        for (const dots of this.#entries.values()) {
            count += dots.filter((dot) => !this.#tombstoneSet.has(dot)).length;
        }
        return count;
    }
    countTombstones() {
        let count = 0;
        for (const dots of this.#entries.values()) {
            count += dots.filter((dot) => this.#tombstoneSet.has(dot)).length;
        }
        return count;
    }
    getDots(element) {
        const dots = this.#entries.get(element) ?? [];
        return frozenStringArray(dots.filter((dot) => !this.#tombstoneSet.has(dot)));
    }
    hasDot(element, encodedDot) {
        return this.#entries.get(element)?.includes(encodedDot) === true;
    }
    isTombstoned(encodedDot) {
        return this.#tombstoneSet.has(encodedDot);
    }
    entries() {
        const entries = [];
        for (const [element, dots] of this.#entries) {
            entries.push(Object.freeze({
                element,
                dots: frozenStringArray(dots),
            }));
        }
        return frozenEntries(entries);
    }
    entryDots() {
        const dots = [];
        for (const entryDots of this.#entries.values()) {
            dots.push(...entryDots);
        }
        return Object.freeze(dots);
    }
    tombstones() {
        return frozenStringArray(this.#tombstones);
    }
}
