[set-methods] Add isSupersetOf method
This CL adds the generic path for isSupersetOf method
to set methods.
Bug: v8:13556
Change-Id: I7a4d3285b3dbcce6502989a9a0cde7efddf998ee
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4656305
Reviewed-by: Rezvan Mahdavi Hezaveh <rezvan@chromium.org>
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Commit-Queue: Rezvan Mahdavi Hezaveh <rezvan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#89258}
diff --git a/BUILD.bazel b/BUILD.bazel
index 9fdc895..f88edf2 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -904,6 +904,7 @@
"src/builtins/set-difference.tq",
"src/builtins/set-intersection.tq",
"src/builtins/set-is-subset-of.tq",
+ "src/builtins/set-is-superset-of.tq",
"src/builtins/set-symmetric-difference.tq",
"src/builtins/set-union.tq",
"src/builtins/string-at.tq",
diff --git a/BUILD.gn b/BUILD.gn
index b177099..72e11bf 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1913,6 +1913,7 @@
"src/builtins/set-difference.tq",
"src/builtins/set-intersection.tq",
"src/builtins/set-is-subset-of.tq",
+ "src/builtins/set-is-superset-of.tq",
"src/builtins/set-symmetric-difference.tq",
"src/builtins/set-union.tq",
"src/builtins/string-at.tq",
diff --git a/src/builtins/set-is-superset-of.tq b/src/builtins/set-is-superset-of.tq
new file mode 100644
index 0000000..0d0e173
--- /dev/null
+++ b/src/builtins/set-is-superset-of.tq
@@ -0,0 +1,66 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace collections {
+
+// https://tc39.es/proposal-set-methods/#sec-set.prototype.issupersetof
+transitioning javascript builtin SetPrototypeIsSupersetOf(
+ js-implicit context: NativeContext,
+ receiver: JSAny)(other: JSAny): Boolean {
+ const methodName: constexpr string = 'Set.prototype.isSupersetOf';
+ const fastIteratorResultMap = GetIteratorResultMap();
+
+ // 1. Let O be the this value.
+ // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
+ const o = Cast<JSSet>(receiver) otherwise
+ ThrowTypeError(
+ MessageTemplate::kIncompatibleMethodReceiver, methodName, receiver);
+
+ const table = Cast<OrderedHashSet>(o.table) otherwise unreachable;
+
+ // 3. Let otherRec be ? GetSetRecord(other).
+ let otherRec = GetSetRecord(other, methodName);
+
+ // 4. Let thisSize be the number of elements in O.[[SetData]].
+ const thisSize =
+ LoadOrderedHashTableMetadata(table, kOrderedHashSetNumberOfElementsIndex);
+
+ // 5. If thisSize < otherRec.[[Size]], return false.
+ if (thisSize < Convert<int32>(otherRec.size)) {
+ return False;
+ }
+
+ // 6. Let keysIter be ? GetKeysIterator(otherRec).
+ let keysIter =
+ GetKeysIterator(otherRec.object, UnsafeCast<Callable>(otherRec.keys));
+
+ // 7. Let next be true.
+ let nextRecord: JSReceiver;
+
+ // 8. Repeat, while next is not false,
+ while (true) {
+ // a. Set next to ? IteratorStep(keysIter).
+ try {
+ nextRecord = iterator::IteratorStep(keysIter, fastIteratorResultMap)
+ otherwise Done;
+ } label Done {
+ // 9. Return true.
+ return True;
+ }
+ // b. If next is not false, then
+ // i. Let nextValue be ? IteratorValue(next).
+ const nextValue =
+ iterator::IteratorValue(nextRecord, fastIteratorResultMap);
+ // ii. If SetDataHas(O.[[SetData]], nextValue) is false, then
+ if (!TableHasKey(table, nextValue)) {
+ // 1. Perform ? IteratorClose(keysIter,
+ // NormalCompletion(unused)).
+ // 2. Return false.
+ iterator::IteratorClose(keysIter);
+ return False;
+ }
+ }
+ unreachable;
+}
+}
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index 1c4a4a9..d0a7a1a 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -4728,6 +4728,8 @@
Builtin::kSetPrototypeSymmetricDifference, 1, true);
SimpleInstallFunction(isolate(), set_prototype, "isSubsetOf",
Builtin::kSetPrototypeIsSubsetOf, 1, true);
+ SimpleInstallFunction(isolate(), set_prototype, "isSupersetOf",
+ Builtin::kSetPrototypeIsSupersetOf, 1, true);
}
void Genesis::InitializeGlobal_harmony_json_parse_with_source() {
diff --git a/test/mjsunit/harmony/set-is-superset-of.js b/test/mjsunit/harmony/set-is-superset-of.js
new file mode 100644
index 0000000..33dc262
--- /dev/null
+++ b/test/mjsunit/harmony/set-is-superset-of.js
@@ -0,0 +1,170 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-set-methods
+
+(function TestIsSupersetOfSetFirstShorter() {
+ const firstSet = new Set();
+ firstSet.add(42);
+
+ const otherSet = new Set();
+ otherSet.add(42);
+ otherSet.add(44);
+
+ assertEquals(firstSet.isSupersetOf(otherSet), false);
+})();
+
+(function TestIsSupersetOfSetSecondShorterIsSuperset() {
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+
+ const otherSet = new Set();
+ otherSet.add(42);
+
+ assertEquals(firstSet.isSupersetOf(otherSet), true);
+})();
+
+(function TestIsSupersetOfSetSecondShorterIsNotSuperset() {
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+
+ const otherSet = new Set();
+ otherSet.add(46);
+
+ assertEquals(firstSet.isSupersetOf(otherSet), false);
+})();
+
+(function TestIsSupersetOfMapFirstShorter() {
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+
+ const other = new Map();
+ other.set(42);
+ other.set(43);
+ other.set(47);
+
+ assertEquals(firstSet.isSupersetOf(other), false);
+})();
+
+(function TestIsSupersetOfMapSecondShorterIsSuperset() {
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+
+ const other = new Map();
+ other.set(42);
+
+ assertEquals(firstSet.isSupersetOf(other), true);
+})();
+
+(function TestIsSupersetOfMapSecondShorterIsNotSuperset() {
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+
+ const other = new Map();
+ other.set(44);
+
+ assertEquals(firstSet.isSupersetOf(other), false);
+})();
+
+(function TestIsSupersetOfSetLikeObjectFirstShorter() {
+ const SetLike = {
+ arr: [42, 44, 45],
+ size: 3,
+ keys() {
+ return this.arr[Symbol.iterator]();
+ },
+ has(key) {
+ return this.arr.indexOf(key) != -1;
+ }
+ };
+
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(45);
+
+ assertEquals(firstSet.isSupersetOf(SetLike), false);
+})();
+
+(function TestIsSupersetOfSetLikeObjectFirstShorterIsSuperset() {
+ const SetLike = {
+ arr: [42],
+ size: 1,
+ keys() {
+ return this.arr[Symbol.iterator]();
+ },
+ has(key) {
+ return this.arr.indexOf(key) != -1;
+ }
+ };
+
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+
+ assertEquals(firstSet.isSupersetOf(SetLike), true);
+})();
+
+(function TestIsSupersetOfSetLikeObjectFirstShorterIsNotSuperset() {
+ const SetLike = {
+ arr: [44],
+ size: 1,
+ keys() {
+ return this.arr[Symbol.iterator]();
+ },
+ has(key) {
+ return this.arr.indexOf(key) != -1;
+ }
+ };
+
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+
+ assertEquals(firstSet.isSupersetOf(SetLike), false);
+})();
+
+(function TestIsSupersetOfSetEqualLengthIsSuperset() {
+ const SetLike = {
+ arr: [42, 43, 45],
+ size: 3,
+ keys() {
+ return this.arr[Symbol.iterator]();
+ },
+ has(key) {
+ return this.arr.indexOf(key) != -1;
+ }
+ };
+
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+ firstSet.add(45);
+
+ assertEquals(firstSet.isSupersetOf(SetLike), true);
+})();
+
+(function TestIsSupersetOfSetEqualLengthIsNotSuperset() {
+ const SetLike = {
+ arr: [42, 44, 45],
+ size: 3,
+ keys() {
+ return this.arr[Symbol.iterator]();
+ },
+ has(key) {
+ return this.arr.indexOf(key) != -1;
+ }
+ };
+
+ const firstSet = new Set();
+ firstSet.add(42);
+ firstSet.add(43);
+ firstSet.add(45);
+
+ assertEquals(firstSet.isSupersetOf(SetLike), false);
+})();