Title: [290612] trunk
Revision
290612
Author
[email protected]
Date
2022-02-28 13:00:47 -0800 (Mon, 28 Feb 2022)

Log Message

Web Inspector: add `IterableWeakSet`
https://bugs.webkit.org/show_bug.cgi?id=237141

Reviewed by Patrick Angle.

Source/WebInspectorUI:

This allows clients to have a way to have an iterable collection that doesn't keep the
objects in the collection alive. We cannot just use `WeakSet` as it's not iterable (the
former) or `Array`/`Set` as it keeps the objects alive (the latter).

`IterableWeakSet` is a combination of:
- a `Set` of `WeakRef` for each object, which gives us iterability with order preserved
- a `WeakMap` of each object mapping to the wrapper `WeakRef` in the `Set` (see below)
- a `FinalizationRegistry` to remove the wrapper `WeakRef` when the object is destroyed

* UserInterface/Base/IterableWeakSet.js: Added.
(IterableWeakSet):
(IterableWeakSet.prototype.get size):
(IterableWeakSet.prototype.has):
(IterableWeakSet.prototype.add):
(IterableWeakSet.prototype.delete):
(IterableWeakSet.prototype.take):
(IterableWeakSet.prototype.clear):
(IterableWeakSet.prototype.keys):
(IterableWeakSet.prototype.values):
(IterableWeakSet.prototype.Symbol.iterator):
(IterableWeakSet.prototype.copy):
(IterableWeakSet.prototype.toJSON):
(IterableWeakSet.prototype.get _finalizationRegistry):
We could just have a `Set`/`Array` of `WeakRef`, but that would require iterating the entire
array to find the `WeakRef` that matches the given object, which is less efficient.

* UserInterface/Controllers/GridOverlayConfigurationDiagnosticEventRecorder.js:
(WI.GridOverlayConfigurationDiagnosticEventRecorder):
Don't keep `WI.DOMNode` that are `layoutOverlayShowing` alive in order to record diagnostics.

* UserInterface/Main.html:
* UserInterface/Test.html:

LayoutTests:

* inspector/unit-tests/iterableweakset.html: Added.
* inspector/unit-tests/iterableweakset-expected.txt: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (290611 => 290612)


--- trunk/LayoutTests/ChangeLog	2022-02-28 20:26:43 UTC (rev 290611)
+++ trunk/LayoutTests/ChangeLog	2022-02-28 21:00:47 UTC (rev 290612)
@@ -1,3 +1,13 @@
+2022-02-28  Devin Rousso  <[email protected]>
+
+        Web Inspector: add `IterableWeakSet`
+        https://bugs.webkit.org/show_bug.cgi?id=237141
+
+        Reviewed by Patrick Angle.
+
+        * inspector/unit-tests/iterableweakset.html: Added.
+        * inspector/unit-tests/iterableweakset-expected.txt: Added.
+
 2022-02-28  Matteo Flores  <[email protected]>
 
         REGRESSION(r288070): [ Monterey ] platform/mac/fast/text/international/Geeza-Pro-vertical-metrics-adjustment.html is a constant text failure.

Added: trunk/LayoutTests/inspector/unit-tests/iterableweakset-expected.txt (0 => 290612)


--- trunk/LayoutTests/inspector/unit-tests/iterableweakset-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/iterableweakset-expected.txt	2022-02-28 21:00:47 UTC (rev 290612)
@@ -0,0 +1,86 @@
+Testing all methods of IterableWeakSet.
+
+
+== Running test suite: IterableWeakSet
+-- Running test case: IterableWeakSet.prototype.constructor.Empty
+[]
+
+-- Running test case: IterableWeakSet.prototype.constructor.NonEmpty
+[{"value":1},{"value":2},{"value":3}]
+
+-- Running test case: IterableWeakSet.prototype.has
+[{"value":1},{"value":2},{"value":3}]
+PASS: 'has' should return true if a key exists.
+PASS: 'has' should return true if a key exists (more than once).
+PASS: 'has' should return true if a key exists.
+PASS: 'has' should return false if a key doesn't exist.
+
+-- Running test case: IterableWeakSet.prototype.add
+[]
+[{"value":1}]
+[{"value":1},{"value":2}]
+[{"value":1},{"value":2},{"value":3}]
+[{"value":1},{"value":2},{"value":3}]
+
+-- Running test case: IterableWeakSet.prototype.delete
+[{"value":1},{"value":2},{"value":3}]
+PASS: 'delete' should return true for a known key.
+[{"value":2},{"value":3}]
+PASS: 'delete' should return true for a known key.
+[{"value":3}]
+PASS: 'delete' should return false for an already deleted key.
+[{"value":3}]
+PASS: 'delete' should return true for a known key.
+[]
+PASS: 'delete' should return false for an unknown key.
+[]
+
+-- Running test case: IterableWeakSet.prototype.take
+[{"value":1},{"value":2},{"value":3}]
+PASS: 'take' should return the key for a known key.
+[{"value":2},{"value":3}]
+PASS: 'take' should return the key for a known key.
+[{"value":3}]
+PASS: 'take' should return undefined for an already deleted key.
+[{"value":3}]
+PASS: 'take' should return the key for a known key.
+[]
+PASS: 'take' should return undefined for an unknown key.
+[]
+
+-- Running test case: IterableWeakSet.prototype.clear
+[{"value":1},{"value":2},{"value":3}]
+[]
+
+-- Running test case: IterableWeakSet.prototype.keys
+[{"value":1},{"value":2},{"value":3}]
+
+-- Running test case: IterableWeakSet.prototype.values
+[{"value":1},{"value":2},{"value":3}]
+
+-- Running test case: IterableWeakSet.prototype.copy
+[{"value":1},{"value":2},{"value":3}]
+PASS: Copy should not return the same object.
+PASS: Copy should return a deep copy.
+PASS: Modifying the original should not modify the copy.
+
+-- Running test case: IterableWeakSet.DoesNotKeepObjectsAlive
+Evaluating `IterableWeakSet` source in the inspected page...
+Testing `IterableWeakSet` in the inspected page...
+[{"value":1},{"value":2},{"value":3}]
+PASS: 'has' should return true for '{"value":1}' after construction.
+PASS: 'has' should return true for '{"value":2}' after construction.
+PASS: 'has' should return true for '{"value":3}' after construction.
+[{"value":2},{"value":3}]
+PASS: Should not contain '{"value": 1}' after `_one_ = null`.
+PASS: 'has' should return true for '{"value":2}' after `_one_ = null`.
+PASS: 'has' should return true for '{"value":3}' after `_one_ = null`.
+[{"value":3}]
+PASS: Should not contain '{"value": 1}' after `two = null`.
+PASS: Should not contain '{"value": 2}' after `two = null`.
+PASS: 'has' should return true for '{"value":3}' after `two = null`.
+[]
+PASS: Should not contain '{"value": 1}' after `three = null`.
+PASS: Should not contain '{"value": 2}' after `three = null`.
+PASS: Should not contain '{"value": 3}' after `three = null`.
+

Added: trunk/LayoutTests/inspector/unit-tests/iterableweakset.html (0 => 290612)


--- trunk/LayoutTests/inspector/unit-tests/iterableweakset.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/iterableweakset.html	2022-02-28 21:00:47 UTC (rev 290612)
@@ -0,0 +1,281 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+async function checkDoesNotKeepObjectsAlive()
+{
+    let _one_ = [{value: 1}];
+    let two = [{value: 2}];
+    let three = [{value: 3}];
+
+    let iterableWeakSet = new IterableWeakSet([one[0], two[0], three[0], two[0]]);
+
+    function check(description, itemOrValue, present) {
+        if (typeof itemOrValue === "object")
+            TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-log", {message: `${iterableWeakSet.has(itemOrValue) === present ? "PASS" : "FAIL"}: 'has' should return ${present ? "true" : "false"} for '${JSON.stringify(itemOrValue)}' after ${description}.`});
+
+        if (typeof itemOrValue === "number") {
+            let found = false;
+            for (let item of iterableWeakSet) {
+                if (item.value !== itemOrValue)
+                    continue;
+
+                if (found) {
+                    TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-log", {message: `FAIL: Should not find '${JSON.stringify(itemOrValue)}' more than once after ${description}.`});
+                    continue;
+                }
+
+                found = true;
+            }
+
+            TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-log", {message: `${found === present ? "PASS" : "FAIL"}: Should ${present ? "" : "not"} contain '{"value": ${itemOrValue}}' after ${description}.`});
+        }
+    }
+
+    TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-log", {message: JSON.stringify(iterableWeakSet)});
+    check("construction", one[0], true);
+    check("construction", two[0], true);
+    check("construction", three[0], true);
+
+    nukeArray(one);
+    await new Promise(setTimeout);
+    gc();
+    await new Promise(setTimeout);
+
+    TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-log", {message: JSON.stringify(iterableWeakSet)});
+    check("`_one_ = null`", 1, false);
+    check("`_one_ = null`", two[0], true);
+    check("`_one_ = null`", three[0], true);
+
+    nukeArray(two);
+    await new Promise(setTimeout);
+    gc();
+    await new Promise(setTimeout);
+
+    TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-log", {message: JSON.stringify(iterableWeakSet)});
+    check("`two = null`", 1, false);
+    check("`two = null`", 2, false);
+    check("`two = null`", three[0], true);
+
+    nukeArray(three);
+    await new Promise(setTimeout);
+    gc();
+    await new Promise(setTimeout);
+
+    TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-log", {message: JSON.stringify(iterableWeakSet)});
+    check("`three = null`", 1, false);
+    check("`three = null`", 2, false);
+    check("`three = null`", 3, false);
+
+    TestPage.dispatchEventToFrontend("TestPage-checkDoesNotKeepObjectsAlive-done");
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("IterableWeakSet");
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.constructor.Empty",
+        async test() {
+            let iterableWeakSet = new IterableWeakSet;
+            InspectorTest.log(iterableWeakSet);
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.constructor.NonEmpty",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(iterableWeakSet);
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.has",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+            let four = {value: 4};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(iterableWeakSet);
+            InspectorTest.expectTrue(iterableWeakSet.has(one), "'has' should return true if a key exists.");
+            InspectorTest.expectTrue(iterableWeakSet.has(two), "'has' should return true if a key exists (more than once).");
+            InspectorTest.expectTrue(iterableWeakSet.has(three), "'has' should return true if a key exists.");
+            InspectorTest.expectFalse(iterableWeakSet.has(four), "'has' should return false if a key doesn't exist.");
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.add",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+
+            let iterableWeakSet = new IterableWeakSet;
+            InspectorTest.log(iterableWeakSet);
+
+            iterableWeakSet.add(one);
+            InspectorTest.log(iterableWeakSet);
+
+            iterableWeakSet.add(two);
+            InspectorTest.log(iterableWeakSet);
+
+            iterableWeakSet.add(three);
+            InspectorTest.log(iterableWeakSet);
+
+            iterableWeakSet.add(two);
+            InspectorTest.log(iterableWeakSet);
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.delete",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+            let four = {value: 4};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectTrue(iterableWeakSet.delete(one), "'delete' should return true for a known key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectTrue(iterableWeakSet.delete(two), "'delete' should return true for a known key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectFalse(iterableWeakSet.delete(two), "'delete' should return false for an already deleted key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectTrue(iterableWeakSet.delete(three), "'delete' should return true for a known key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectFalse(iterableWeakSet.delete(four), "'delete' should return false for an unknown key.");
+            InspectorTest.log(iterableWeakSet);
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.take",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+            let four = {value: 4};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectEqual(iterableWeakSet.take(one)?.value, 1, "'take' should return the key for a known key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectEqual(iterableWeakSet.take(two)?.value, 2, "'take' should return the key for a known key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectEqual(iterableWeakSet.take(two), undefined, "'take' should return undefined for an already deleted key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectEqual(iterableWeakSet.take(three)?.value, 3, "'take' should return the key for a known key.");
+            InspectorTest.log(iterableWeakSet);
+
+            InspectorTest.expectEqual(iterableWeakSet.take(four), undefined, "'take' should return undefined for an unknown key.");
+            InspectorTest.log(iterableWeakSet);
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.clear",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(iterableWeakSet);
+
+            iterableWeakSet.clear();
+            InspectorTest.log(iterableWeakSet);
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.keys",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(Array.from(iterableWeakSet.keys()));
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.values",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(Array.from(iterableWeakSet.values()));
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.prototype.copy",
+        async test() {
+            let _one_ = {value: 1};
+            let two = {value: 2};
+            let three = {value: 3};
+            let four = {value: 4};
+
+            let iterableWeakSet = new IterableWeakSet([one, two, three, two]);
+            InspectorTest.log(iterableWeakSet);
+
+            let copy = iterableWeakSet.copy();
+            InspectorTest.expectNotEqual(iterableWeakSet, copy, "Copy should not return the same object.")
+            InspectorTest.expectEqual(JSON.stringify(iterableWeakSet), JSON.stringify(copy), "Copy should return a deep copy.");
+
+            iterableWeakSet.add(four);
+            InspectorTest.expectNotEqual(JSON.stringify(iterableWeakSet), JSON.stringify(copy), "Modifying the original should not modify the copy.");
+        },
+    });
+
+    suite.addTestCase({
+        name: "IterableWeakSet.DoesNotKeepObjectsAlive",
+        async test() {
+            // Send `IterableWeakSet` to the page so that `GCController` can be used.
+            InspectorTest.log("Evaluating `IterableWeakSet` source in the inspected page...");
+            await InspectorTest.evaluateInPage(String(IterableWeakSet));
+
+            InspectorTest.addEventListener("TestPage-checkDoesNotKeepObjectsAlive-log", (event) => {
+                InspectorTest.log(event.data.message);
+            });
+
+            InspectorTest.log("Testing `IterableWeakSet` in the inspected page...");
+            await Promise.all([
+                InspectorTest.awaitEvent("TestPage-checkDoesNotKeepObjectsAlive-done"),
+                InspectorTest.evaluateInPage(`checkDoesNotKeepObjectsAlive()`),
+            ]);
+        },
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Testing all methods of IterableWeakSet.</p>
+</body>
+</html>

Modified: trunk/Source/WebInspectorUI/ChangeLog (290611 => 290612)


--- trunk/Source/WebInspectorUI/ChangeLog	2022-02-28 20:26:43 UTC (rev 290611)
+++ trunk/Source/WebInspectorUI/ChangeLog	2022-02-28 21:00:47 UTC (rev 290612)
@@ -1,3 +1,43 @@
+2022-02-28  Devin Rousso  <[email protected]>
+
+        Web Inspector: add `IterableWeakSet`
+        https://bugs.webkit.org/show_bug.cgi?id=237141
+
+        Reviewed by Patrick Angle.
+
+        This allows clients to have a way to have an iterable collection that doesn't keep the
+        objects in the collection alive. We cannot just use `WeakSet` as it's not iterable (the
+        former) or `Array`/`Set` as it keeps the objects alive (the latter).
+
+        `IterableWeakSet` is a combination of:
+        - a `Set` of `WeakRef` for each object, which gives us iterability with order preserved
+        - a `WeakMap` of each object mapping to the wrapper `WeakRef` in the `Set` (see below)
+        - a `FinalizationRegistry` to remove the wrapper `WeakRef` when the object is destroyed
+
+        * UserInterface/Base/IterableWeakSet.js: Added.
+        (IterableWeakSet):
+        (IterableWeakSet.prototype.get size):
+        (IterableWeakSet.prototype.has):
+        (IterableWeakSet.prototype.add):
+        (IterableWeakSet.prototype.delete):
+        (IterableWeakSet.prototype.take):
+        (IterableWeakSet.prototype.clear):
+        (IterableWeakSet.prototype.keys):
+        (IterableWeakSet.prototype.values):
+        (IterableWeakSet.prototype.Symbol.iterator):
+        (IterableWeakSet.prototype.copy):
+        (IterableWeakSet.prototype.toJSON):
+        (IterableWeakSet.prototype.get _finalizationRegistry):
+        We could just have a `Set`/`Array` of `WeakRef`, but that would require iterating the entire
+        array to find the `WeakRef` that matches the given object, which is less efficient.
+
+        * UserInterface/Controllers/GridOverlayConfigurationDiagnosticEventRecorder.js:
+        (WI.GridOverlayConfigurationDiagnosticEventRecorder):
+        Don't keep `WI.DOMNode` that are `layoutOverlayShowing` alive in order to record diagnostics.
+
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+
 2022-02-24  Devin Rousso  <[email protected]>
 
         Web Inspector: merge WI.OverlayManager into WI.DOMNode

Added: trunk/Source/WebInspectorUI/UserInterface/Base/IterableWeakSet.js (0 => 290612)


--- trunk/Source/WebInspectorUI/UserInterface/Base/IterableWeakSet.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/IterableWeakSet.js	2022-02-28 21:00:47 UTC (rev 290612)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+class IterableWeakSet
+{
+    constructor(items = [])
+    {
+        this._wrappers = new Set;
+        this._wrapperForItem = new WeakMap;
+
+        for (let item of items)
+            this.add(item);
+    }
+
+    // Public
+
+    get size()
+    {
+        let size = 0;
+        for (let wrapper of this._wrappers) {
+            if (wrapper.deref())
+                ++size;
+        }
+        return size;
+    }
+
+    has(item)
+    {
+        let result = this._wrapperForItem.has(item);
+        console.assert(Array.from(this._wrappers).some((wrapper) => wrapper.deref() === item) === result, this, item);
+        return result;
+    }
+
+    add(item)
+    {
+        console.assert(typeof item === "object", item);
+        console.assert(item !== null, item);
+
+        if (this.has(item))
+            return;
+
+        let wrapper = new WeakRef(item);
+        this._wrappers.add(wrapper);
+        this._wrapperForItem.set(item, wrapper);
+        this._finalizationRegistry.register(item, {weakThis: new WeakRef(this), wrapper}, wrapper);
+    }
+
+    delete(item)
+    {
+        return !!this.take(item);
+    }
+
+    take(item)
+    {
+        let wrapper = this._wrapperForItem.get(item);
+        if (!wrapper)
+            return undefined;
+
+        let itemDeleted = this._wrapperForItem.delete(item);
+        console.assert(itemDeleted, this, item);
+
+        let wrapperDeleted = this._wrappers.delete(wrapper);
+        console.assert(wrapperDeleted, this, item);
+
+        this._finalizationRegistry.unregister(wrapper);
+
+        console.assert(wrapper.deref() === item, this, item);
+        return item;
+    }
+
+    clear()
+    {
+        for (let wrapper of this._wrappers) {
+            this._wrapperForItem.delete(wrapper);
+            this._finalizationRegistry.unregister(wrapper);
+        }
+
+        this._wrappers.clear();
+    }
+
+    keys()
+    {
+        return this.values();
+    }
+
+    *values()
+    {
+        for (let wrapper of this._wrappers) {
+            let item = wrapper.deref();
+            console.assert(!item === !this._wrapperForItem.has(item), this, item);
+            if (item)
+                yield item;
+        }
+    }
+
+    [Symbol.iterator]()
+    {
+        return this.values();
+    }
+
+    copy()
+    {
+        return new IterableWeakSet(this.toJSON());
+    }
+
+    toJSON()
+    {
+        return Array.from(this);
+    }
+
+    // Private
+
+    get _finalizationRegistry()
+    {
+        return IterableWeakSet._finalizationRegistry ??= new FinalizationRegistry(function(heldValue) {
+            heldValue.weakThis.deref()?._wrappers.delete(heldValue.wrapper);
+        });
+    }
+}

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/GridOverlayConfigurationDiagnosticEventRecorder.js (290611 => 290612)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/GridOverlayConfigurationDiagnosticEventRecorder.js	2022-02-28 20:26:43 UTC (rev 290611)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/GridOverlayConfigurationDiagnosticEventRecorder.js	2022-02-28 21:00:47 UTC (rev 290612)
@@ -32,7 +32,7 @@
         this._inspectorHasFocus = true;
         this._lastUserInteractionTimestamp = undefined;
         this._eventSamplingTimerIdentifier = undefined;
-        this._nodesShowingGridLayoutOverlay = new Set;
+        this._nodesShowingGridLayoutOverlay = new IterableWeakSet;
     }
 
     // Static

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (290611 => 290612)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2022-02-28 20:26:43 UTC (rev 290611)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2022-02-28 21:00:47 UTC (rev 290612)
@@ -310,6 +310,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (290611 => 290612)


--- trunk/Source/WebInspectorUI/UserInterface/Test.html	2022-02-28 20:26:43 UTC (rev 290611)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html	2022-02-28 21:00:47 UTC (rev 290612)
@@ -39,6 +39,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to