summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/Set.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/Set.js')
-rw-r--r--js/src/builtin/Set.js597
1 files changed, 597 insertions, 0 deletions
diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js
new file mode 100644
index 0000000000..ed52a2c7fc
--- /dev/null
+++ b/js/src/builtin/Set.js
@@ -0,0 +1,597 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// ES2017 draft rev 0e10c9f29fca1385980c08a7d5e7bb3eb775e2e4
+// 23.2.1.1 Set, steps 6-8
+function SetConstructorInit(iterable) {
+ var set = this;
+
+ // Step 6.a.
+ var adder = set.add;
+
+ // Step 6.b.
+ if (!IsCallable(adder)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, typeof adder);
+ }
+
+ // Steps 6.c-8.
+ for (var nextValue of allowContentIter(iterable)) {
+ callContentFunction(adder, set, nextValue);
+ }
+}
+
+#ifdef ENABLE_NEW_SET_METHODS
+// New Set methods proposal
+//
+// Set.prototype.union(iterable)
+// https://tc39.es/proposal-set-methods/#Set.prototype.union
+function SetUnion(iterable) {
+ // Step 1. Let set be the this value.
+ var set = this;
+
+ // Step 2. If Type(set) is not Object, throw a TypeError exception.
+ if (!IsObject(set)) {
+ ThrowTypeError(JSMSG_OBJECT_REQUIRED, set === null ? "null" : typeof set);
+ }
+
+ // Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
+ var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
+
+ // Step 4. Let newSet be ? Construct(Ctr, set).
+ var newSet = constructContentFunction(Ctr, Ctr, set);
+
+ // Step 5. Let adder be ? Get(newSet, "add").
+ var adder = newSet.add;
+
+ // Inlined AddEntryFromIterable Step 1. If IsCallable(adder) is false,
+ // throw a TypeError exception.
+ if (!IsCallable(adder)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "add");
+ }
+
+ // Step 6. Return ? AddEntryFromIterable(newSet, iterable, adder).
+ return AddEntryFromIterable(newSet, iterable, adder);
+}
+
+// New Set methods proposal
+//
+// Set.prototype.intersection(iterable)
+// https://tc39.es/proposal-set-methods/#Set.prototype.intersection
+function SetIntersection(iterable) {
+ // Step 1. Let set be the this value.
+ var set = this;
+
+ // Step 2. If Type(set) is not Object, throw a TypeError exception.
+ if (!IsObject(set)) {
+ ThrowTypeError(JSMSG_OBJECT_REQUIRED, set === null ? "null" : typeof set);
+ }
+
+ // Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
+ var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
+
+ // Step 4. Let newSet be ? Construct(Ctr).
+ var newSet = constructContentFunction(Ctr, Ctr);
+
+ // Step 5. Let hasCheck be ? Get(set, "has").
+ var hasCheck = set.has;
+
+ // Step 6. If IsCallable(hasCheck) is false, throw a TypeError exception.
+ if (!IsCallable(hasCheck)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "has");
+ }
+
+ // Step 7. Let adder be ? Get(newSet, "add").
+ var adder = newSet.add;
+
+ // Step 8. If IsCallable(adder) is false, throw a TypeError exception.
+ if (!IsCallable(adder)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "add");
+ }
+
+ // Step 9. Let iteratorRecord be ? GetIterator(iterable).
+ var iteratorRecord = GetIteratorSync(iterable);
+
+ // Step 10. Repeat,
+ while (true) {
+ // Step a. Let next be ? IteratorStep(iteratorRecord).
+ var next = IteratorStep(iteratorRecord);
+
+ // Step b. If next is false, return newSet.
+ if (!next) {
+ return newSet;
+ }
+
+ // Step c. Let nextValue be ? IteratorValue(next).
+ var nextValue = next.value;
+ var needClose = true;
+ var has;
+ try {
+ // Step d. Let has be Call(hasCheck, set, « nextValue »).
+ has = callContentFunction(hasCheck, set, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step e. If has is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, has).
+ IteratorClose(iteratorRecord);
+ }
+ }
+
+ // Step f. If has.[[Value]] is true,
+ if (has) {
+ needClose = true;
+ try {
+ // Step i. Let status be Call(adder, newSet, « nextValue »).
+ callContentFunction(adder, newSet, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step ii. If status is an abrupt completion, return ?
+ // IteratorClose(iteratorRecord, status).
+ IteratorClose(iteratorRecord);
+ }
+ }
+ }
+ }
+}
+
+// New Set methods proposal
+//
+// Set.prototype.difference(iterable)
+// https://tc39.es/proposal-set-methods/#Set.prototype.difference
+function SetDifference(iterable) {
+ // Step 1. Let set be the this value.
+ var set = this;
+
+ // Step 2. If Type(set) is not Object, throw a TypeError exception.
+ if (!IsObject(set)) {
+ ThrowTypeError(JSMSG_OBJECT_REQUIRED, set === null ? "null" : typeof set);
+ }
+
+ // Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
+ var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
+
+ // Step 4. Let newSet be ? Construct(Ctr, set).
+ var newSet = constructContentFunction(Ctr, Ctr, set);
+
+ // Step 5. Let remover be ? Get(newSet, "delete").
+ var remover = newSet.delete;
+
+ // Step 6. If IsCallable(remover) is false, throw a TypeError exception.
+ if (!IsCallable(remover)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "delete");
+ }
+
+ // Step 7. Let iteratorRecord be ? GetIterator(iterable).
+ var iteratorRecord = GetIteratorSync(iterable);
+
+ // Step 8. Repeat,
+ while (true) {
+ // Step a. Let next be ? IteratorStep(iteratorRecord).
+ var next = IteratorStep(iteratorRecord);
+
+ // Step b. If next is false, return newSet.
+ if (!next) {
+ return newSet;
+ }
+
+ // Step c. Let nextValue be ? IteratorValue(next).
+ var nextValue = next.value;
+ var needClose = true;
+ try {
+ // Step d. Let status be Call(remover, newSet, « nextValue »).
+ callContentFunction(remover, newSet, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step e. If status is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, status).
+ IteratorClose(iteratorRecord);
+ }
+ }
+ }
+}
+
+// New Set methods proposal
+//
+// Set.prototype.symmetricDifference(iterable)
+// https://tc39.es/proposal-set-methods/#Set.prototype.symmetricDifference
+function SetSymmetricDifference(iterable) {
+ // Step 1. Let set be the this value.
+ var set = this;
+
+ // Step 2. If Type(set) is not Object, throw a TypeError exception.
+ if (!IsObject(set)) {
+ ThrowTypeError(JSMSG_OBJECT_REQUIRED, set === null ? "null" : typeof set);
+ }
+
+ // Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
+ var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
+
+ // Step 4. Let newSet be ? Construct(Ctr, set).
+ var newSet = constructContentFunction(Ctr, Ctr, set);
+
+ // Step 5. Let remover be ? Get(newSet, "delete").
+ var remover = newSet.delete;
+
+ // Step 6. If IsCallable(remover) is false, throw a TypeError exception.
+ if (!IsCallable(remover)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "delete");
+ }
+
+ // Step 7. Let adder be ? Get(newSet, "add").
+ var adder = newSet.add;
+
+ // Step 8. If IsCallable(adder) is false, throw a TypeError exception.
+ if (!IsCallable(adder)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "add");
+ }
+
+ // Step 9. Let iteratorRecord be ? GetIterator(iterable).
+ var iteratorRecord = GetIteratorSync(iterable);
+
+ // Step 10. Repeat,
+ while (true) {
+ // Step a. Let next be ? IteratorStep(iteratorRecord).
+ var next = IteratorStep(iteratorRecord);
+
+ // Step b. If next is false, return newSet.
+ if (!next) {
+ return newSet;
+ }
+
+ // Step c. Let nextValue be ? IteratorValue(next).
+ var nextValue = next.value;
+ var needClose = true;
+ var removed;
+ try {
+ // Step d. Let removed be Call(remover, newSet, « nextValue »).
+ removed = callContentFunction(remover, newSet, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step e. If removed is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, removed).
+ IteratorClose(iteratorRecord);
+ }
+ }
+
+ // Step f. If removed.[[Value]] is false,
+ if (!removed) {
+ needClose = true;
+ try {
+ // Step i. Let status be Call(adder, newSet, « nextValue »).
+ callContentFunction(adder, newSet, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step ii. If status is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, status).
+ IteratorClose(iteratorRecord);
+ }
+ }
+ }
+ }
+}
+
+// New Set methods proposal
+//
+// Set.prototype.isSubsetOf(iterable)
+// https://tc39.es/proposal-set-methods/#Set.prototype.isSubsetOf
+function SetIsSubsetOf(iterable) {
+ // Step 1. Let set be the this value.
+ var set = this;
+
+ // Step 2. Let iteratorRecord be ? GetIterator(set).
+ var iteratorRecord = GetIteratorSync(set);
+
+ // Step 3. If Type(iterable) is not Object, throw a TypeError exception.
+ if (!IsObject(iterable)) {
+ ThrowTypeError(JSMSG_OBJECT_REQUIRED, set === null ? "null" : typeof set);
+ }
+
+ // Step 4. Let otherSet be iterable.
+ var otherSet = iterable;
+
+ // Step 5. Let hasCheck be ? Get(otherSet, "has").
+ var hasCheck = otherSet.has;
+
+ // Step 6. If IsCallable(hasCheck) is false,
+ if (!IsCallable(hasCheck)) {
+ // Step a. Let otherSet be ? Construct(%Set%).
+ let set = GetBuiltinConstructor("Set");
+ otherSet = new set();
+
+ // We are not inlining AddEntryFromIterable Step 1 here because we know
+ // std_Set_add is callable Step b. Perform ?
+ // AddEntryFromIterable(otherSet, iterable, %SetProto_add%).
+ AddEntryFromIterable(otherSet, iterable, std_Set_add);
+
+ // Step c. Let hasCheck be %SetProto_has%.
+ hasCheck = std_Set_has;
+ }
+
+ // Step 7. Repeat,
+ while (true) {
+ // Step a. Let next be ? IteratorStep(iteratorRecord).
+ var next = IteratorStep(iteratorRecord);
+
+ // Step b. If next is false, return true.
+ if (!next) {
+ return true;
+ }
+
+ // Step c. Let nextValue be ? IteratorValue(next).
+ var nextValue = next.value;
+ var needClose = true;
+ var has;
+ try {
+ // Step d. Let has be Call(hasCheck, otherSet, « nextValue »).
+ has = callContentFunction(hasCheck, otherSet, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step e. If has is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, has).
+ IteratorClose(iteratorRecord);
+ }
+ }
+
+ // Step f. If has.[[Value]] is false, return false.
+ if (!has) {
+ return false;
+ }
+ }
+}
+
+// New Set methods proposal
+//
+// Set.prototype.isSupersetOf(iterable)
+// https://tc39.es/proposal-set-methods/#Set.prototype.isSupersetOf
+function SetIsSupersetOf(iterable) {
+ // Step 1. Let set be the this value.
+ var set = this;
+
+ // Step 2. If Type(set) is not Object, throw a TypeError exception.
+ if (!IsObject(set)) {
+ ThrowTypeError(JSMSG_OBJECT_REQUIRED, set === null ? "null" : typeof set);
+ }
+
+ // Step 3. Let hasCheck be ? Get(set, "has").
+ var hasCheck = set.has;
+
+ // Step 4. If IsCallable(hasCheck) is false, throw a TypeError exception.
+ if (!IsCallable(hasCheck)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "has");
+ }
+
+ // Step 5. Let iteratorRecord be ? GetIterator(iterable).
+ var iteratorRecord = GetIteratorSync(iterable);
+
+ // Step 6. Repeat,
+ while (true) {
+ // Step a. Let next be ? IteratorStep(iteratorRecord).
+ var next = IteratorStep(iteratorRecord);
+
+ // Step b. If next is false, return true.
+ if (!next) {
+ return true;
+ }
+
+ // Step c. Let nextValue be ? IteratorValue(next).
+ var nextValue = next.value;
+ var needClose = true;
+ var has;
+ try {
+ // Step d. Let has be Call(hasCheck, set, « nextValue »).
+ has = callContentFunction(hasCheck, set, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step e. If has is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, has).
+ IteratorClose(iteratorRecord);
+ }
+ }
+
+ // Step f. If has.[[Value]] is false, return false.
+ if (!has) {
+ return false;
+ }
+ }
+}
+
+// New Set methods proposal
+//
+// Set.prototype.isDisjointFrom(iterable)
+// https://tc39.es/proposal-set-methods/#Set.prototype.isDisjointFrom
+function SetIsDisjointFrom(iterable) {
+ // Step 1. Let set be the this value.
+ var set = this;
+
+ // Step 2. If Type(set) is not Object, throw a TypeError exception.
+ if (!IsObject(set)) {
+ ThrowTypeError(JSMSG_OBJECT_REQUIRED, set === null ? "null" : typeof set);
+ }
+
+ // Step 3. Let hasCheck be ? Get(set, "has").
+ var hasCheck = set.has;
+
+ // Step 4. If IsCallable(hasCheck) is false, throw a TypeError exception.
+ if (!IsCallable(hasCheck)) {
+ ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "has");
+ }
+
+ // Step 5. Let iteratorRecord be ? GetIterator(iterable).
+ var iteratorRecord = GetIteratorSync(iterable);
+
+ // Step 6. Repeat,
+ while (true) {
+ // Step a. Let next be ? IteratorStep(iteratorRecord).
+ var next = IteratorStep(iteratorRecord);
+
+ // Step b. If next is false, return true.
+ if (!next) {
+ return true;
+ }
+
+ // Step c. Let nextValue be ? IteratorValue(next).
+ var nextValue = next.value;
+ var needClose = true;
+ var has;
+ try {
+ // Step d. Let has be Call(hasCheck, set, « nextValue »).
+ has = callContentFunction(hasCheck, set, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step e. If has is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, has).
+ IteratorClose(iteratorRecord);
+ }
+ }
+
+ // Step f. If has.[[Value]] is true, return false.
+ if (has) {
+ return false;
+ }
+ }
+}
+
+// New Set methods proposal
+//
+// AddEntryFromIterable ( target, iterable, adder )
+// https://tc39.es/proposal-set-methods/#AddEntryFromIterable
+function AddEntryFromIterable(target, iterable, adder) {
+ assert(IsCallable(adder), "adder argument is callable");
+
+ // Step 2. Let iteratorRecord be ? GetIterator(iterable).
+ var iteratorRecord = GetIteratorSync(iterable);
+
+ // Step 3. Repeat,
+ while (true) {
+ // Step a. Let next be ? IteratorStep(iteratorRecord).
+ var next = IteratorStep(iteratorRecord);
+
+ // Step b. If next is false, return target.
+ if (!next) {
+ return target;
+ }
+
+ // Step c. Let nextValue be ? IteratorValue(next).
+ var nextValue = next.value;
+ var needClose = true;
+ try {
+ // Step d. Let status be Call(adder, target, « nextValue »).
+ callContentFunction(adder, target, nextValue);
+ needClose = false;
+ } finally {
+ if (needClose) {
+ // Step e. If status is an abrupt completion,
+ // return ? IteratorClose(iteratorRecord, status).
+ IteratorClose(iteratorRecord);
+ }
+ }
+ }
+}
+#endif
+
+// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
+// 23.2.3.6 Set.prototype.forEach ( callbackfn [ , thisArg ] )
+function SetForEach(callbackfn, thisArg = undefined) {
+ // Step 1.
+ var S = this;
+
+ // Steps 2-3.
+ if (!IsObject(S) || (S = GuardToSetObject(S)) === null) {
+ return callFunction(
+ CallSetMethodIfWrapped,
+ this,
+ callbackfn,
+ thisArg,
+ "SetForEach"
+ );
+ }
+
+ // Step 4.
+ if (!IsCallable(callbackfn)) {
+ ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+ }
+
+ // Steps 5-8.
+ var values = callFunction(std_Set_values, S);
+
+ // Inlined: SetIteratorNext
+ var setIterationResult = globalSetIterationResult;
+
+ while (true) {
+ var done = GetNextSetEntryForIterator(values, setIterationResult);
+ if (done) {
+ break;
+ }
+
+ var value = setIterationResult[0];
+ setIterationResult[0] = null;
+
+ callContentFunction(callbackfn, thisArg, value, value, S);
+ }
+}
+
+// ES6 final draft 23.2.2.2.
+// Uncloned functions with `$` prefix are allocated as extended function
+// to store the original name in `SetCanonicalName`.
+function $SetSpecies() {
+ // Step 1.
+ return this;
+}
+SetCanonicalName($SetSpecies, "get [Symbol.species]");
+
+var globalSetIterationResult = CreateSetIterationResult();
+
+function SetIteratorNext() {
+ // Step 1.
+ var O = this;
+
+ // Steps 2-3.
+ if (!IsObject(O) || (O = GuardToSetIterator(O)) === null) {
+ return callFunction(
+ CallSetIteratorMethodIfWrapped,
+ this,
+ "SetIteratorNext"
+ );
+ }
+
+ // Steps 4-5 (implemented in GetNextSetEntryForIterator).
+ // Steps 8-9 (omitted).
+
+ var setIterationResult = globalSetIterationResult;
+
+ var retVal = { value: undefined, done: true };
+
+ // Steps 10.a, 11.
+ var done = GetNextSetEntryForIterator(O, setIterationResult);
+ if (!done) {
+ // Steps 10.b-c (omitted).
+
+ // Step 6.
+ var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND);
+
+ var result;
+ if (itemKind === ITEM_KIND_VALUE) {
+ // Step 10.d.i.
+ result = setIterationResult[0];
+ } else {
+ // Step 10.d.ii.
+ assert(itemKind === ITEM_KIND_KEY_AND_VALUE, itemKind);
+ result = [setIterationResult[0], setIterationResult[0]];
+ }
+
+ setIterationResult[0] = null;
+ retVal.value = result;
+ retVal.done = false;
+ }
+
+ // Steps 7, 10.d, 12.
+ return retVal;
+}