"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WeakList = void 0;
const DEFAULT_MINIMUM_LENGTH_TO_REALLOCATE = 8;
const DEFAULT_MODULUS_TO_REALLOCATE_ON_PUSH = 1024;
const MIN_DEAD_REFS_FOR_REALLOCATION_PERCENTAGE = 0.5;
/**
 * A list-like collection that holds weak references to objects.
 * Automatically cleans up dead references when a threshold is met.
 *
 * FinalizationRegistry is not used here due to it's lack of determinism.
 * FinalizationRegsitry callbacks are not guaranteed to be called after an object is garbage collected.
 */
class WeakList {
    #list;
    #minimumLengthToReallocate;
    #modulusToReallocateOnPush;
    constructor() {
        this.#list = [];
        this.#minimumLengthToReallocate = DEFAULT_MINIMUM_LENGTH_TO_REALLOCATE;
        this.#modulusToReallocateOnPush = DEFAULT_MODULUS_TO_REALLOCATE_ON_PUSH;
    }
    *[Symbol.iterator]() {
        let deadRefCount = 0;
        for (const weakRef of this.#list) {
            const value = weakRef.deref();
            if (value === undefined) {
                ++deadRefCount;
            }
            else {
                yield value;
            }
        }
        if (this.#list.length >= this.#minimumLengthToReallocate &&
            this.#shouldReallocate(deadRefCount)) {
            this.#reallocate(deadRefCount);
        }
    }
    push(value) {
        const weakRef = new WeakRef(value);
        this.#list.push(weakRef);
        if (this.#list.length >= this.#minimumLengthToReallocate &&
            this.#list.length % this.#modulusToReallocateOnPush === 0) {
            let deadRefCount = 0;
            for (const ref of this.#list) {
                if (ref.deref() === undefined) {
                    ++deadRefCount;
                }
            }
            if (this.#shouldReallocate(deadRefCount)) {
                this.#reallocate(deadRefCount);
            }
        }
    }
    #reallocate(deadRefCount) {
        const newList = new Array(this.#list.length - deadRefCount);
        let i = 0;
        for (const ref of this.#list) {
            if (ref.deref()) {
                newList[i++] = ref;
            }
        }
        this.#list = newList;
    }
    #shouldReallocate(deadRefCount) {
        return (deadRefCount >=
            this.#list.length * MIN_DEAD_REFS_FOR_REALLOCATION_PERCENTAGE);
    }
}
exports.WeakList = WeakList;
//# sourceMappingURL=WeakList.js.map