1'use strict';
2
3const {
4  ObjectFreeze,
5  SafeFinalizationRegistry,
6  SafeSet,
7  SafeWeakMap,
8  SafeWeakRef,
9  SymbolIterator,
10} = primordials;
11
12// This class is modified from the example code in the WeakRefs specification:
13// https://github.com/tc39/proposal-weakrefs
14// Licensed under ECMA's MIT-style license, see:
15// https://github.com/tc39/ecma262/blob/HEAD/LICENSE.md
16class IterableWeakMap {
17  #weakMap = new SafeWeakMap();
18  #refSet = new SafeSet();
19  #finalizationGroup = new SafeFinalizationRegistry(cleanup);
20
21  set(key, value) {
22    const entry = this.#weakMap.get(key);
23    if (entry) {
24      // If there's already an entry for the object represented by "key",
25      // the value can be updated without creating a new WeakRef:
26      this.#weakMap.set(key, { value, ref: entry.ref });
27    } else {
28      const ref = new SafeWeakRef(key);
29      this.#weakMap.set(key, { value, ref });
30      this.#refSet.add(ref);
31      this.#finalizationGroup.register(key, {
32        set: this.#refSet,
33        ref,
34      }, ref);
35    }
36  }
37
38  get(key) {
39    return this.#weakMap.get(key)?.value;
40  }
41
42  has(key) {
43    return this.#weakMap.has(key);
44  }
45
46  delete(key) {
47    const entry = this.#weakMap.get(key);
48    if (!entry) {
49      return false;
50    }
51    this.#weakMap.delete(key);
52    this.#refSet.delete(entry.ref);
53    this.#finalizationGroup.unregister(entry.ref);
54    return true;
55  }
56
57  [SymbolIterator]() {
58    const iterator = this.#refSet[SymbolIterator]();
59
60    const next = () => {
61      const result = iterator.next();
62      if (result.done) return result;
63      const key = result.value.deref();
64      if (key == null) return next();
65      const { value } = this.#weakMap.get(key);
66      return { done: false, value };
67    };
68
69    return {
70      [SymbolIterator]() { return this; },
71      next,
72    };
73  }
74}
75
76function cleanup({ set, ref }) {
77  set.delete(ref);
78}
79
80ObjectFreeze(IterableWeakMap.prototype);
81
82module.exports = {
83  IterableWeakMap,
84};
85