import IterableWeakMap from "./iterable-weak-map.mjs";

/**
 * Stores a set of objects with weak references to them, allowing them to be garbage collected. Can be iterated over,
 * unlike a WeakSet.
 * @template {WeakKey} [T=WeakKey]
 * @implements {WeakSet<T>}
 */
export default class IterableWeakSet {
  /**
   * The backing iterable weak map.
   * @type {IterableWeakMap<T, T>}
   */
  #map = new IterableWeakMap();

  /**
   * @param {Iterable<T, void, unknown>} [entries]  The initial entries.
   */
  constructor(entries=[]) {
    for ( const entry of entries ) this.add(entry);
  }

  /* -------------------------------------------- */

  /**
   * Enumerate the values.
   * @returns {Generator<T, void, unknown>}
   */
  [Symbol.iterator]() {
    return this.values();
  }

  /* -------------------------------------------- */

  /**
   * Add a value to the set.
   * @param {T} value  The value to add.
   * @returns {this}
   */
  add(value) {
    this.#map.set(value, value);
    return this;
  }

  /* -------------------------------------------- */

  /**
   * Delete a value from the set.
   * @param {T} value  The value to delete.
   * @returns {boolean}
   */
  delete(value) {
    return this.#map.delete(value);
  }

  /* -------------------------------------------- */

  /**
   * Whether this set contains the given value.
   * @param {T} value  The value to test.
   * @returns {boolean}
   */
  has(value) {
    return this.#map.has(value);
  }

  /* -------------------------------------------- */

  /**
   * Enumerate the collection.
   * @returns {Generator<T, void, unknown>}
   */
  values() {
    return this.#map.values();
  }

  /* -------------------------------------------- */

  /**
   * Clear all values from the set.
   */
  clear() {
    this.#map.clear();
  }
}
