diff options
Diffstat (limited to 'js/src/builtin/Set.js')
-rw-r--r-- | js/src/builtin/Set.js | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js new file mode 100644 index 0000000000..d1d877ba44 --- /dev/null +++ b/js/src/builtin/Set.js @@ -0,0 +1,567 @@ +/* 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); + } +} + +// 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; +} + +#ifdef NIGHTLY_BUILD +// GetSetRecord ( obj ) +// +// https://tc39.es/proposal-set-methods/#sec-getsetrecord +function GetSetRecord(obj) { + // Step 1. + if (!IsObject(obj)) { + ThrowTypeError(JSMSG_OBJECT_REQUIRED, obj === null ? "null" : typeof obj); + } + + // Step 2. + var rawSize = obj.size; + + // Step 3. + var numSize = +rawSize; + + // Steps 4-5. + if (numSize !== numSize) { + if (rawSize === undefined) { + ThrowTypeError(JSMSG_UNEXPECTED_TYPE, "size", "undefined"); + } else { + ThrowTypeError(JSMSG_UNEXPECTED_TYPE, "size", "NaN"); + } + } + + // Step 6. + var intSize = ToInteger(numSize); + + // Step 7. + if (intSize < 0) { + ThrowRangeError(JSMSG_SET_NEGATIVE_SIZE); + } + + // Step 8. + var has = obj.has; + + // Step 9. + if (!IsCallable(has)) { + ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "has"); + } + + // Step 10. + var keys = obj.keys; + + // Step 11. + if (!IsCallable(keys)) { + ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "keys"); + } + + // Step 12. + return { set: obj, size: intSize, has, keys }; +} + +// 7.4.2 GetIteratorFromMethod ( obj, method ) +// +// ES2024 draft rev a103b287cd19bdc51c7a3d8d7c1431b1506a74e2 +function GetIteratorFromMethod(setRec) { + // Step 1. + var keysIter = callContentFunction(setRec.keys, setRec.set); + + // Step 2. + if (!IsObject(keysIter)) { + ThrowTypeError( + JSMSG_OBJECT_REQUIRED, + keysIter === null ? "null" : typeof keysIter + ); + } + + // Step 3. (Implemented in caller.) + + // Step 4. + return keysIter; +} + +// Set.prototype.union ( other ) +// +// https://tc39.es/proposal-set-methods/#sec-set.prototype.union +function SetUnion(other) { + // Step 1. + var O = this; + + // Step 2. + if (!IsObject(O) || (O = GuardToSetObject(O)) === null) { + return callFunction(CallSetMethodIfWrapped, this, other, "SetUnion"); + } + + // Step 3. + var otherRec = GetSetRecord(other); + + // Step 4. + var keysIter = GetIteratorFromMethod(otherRec); + var keysIterNext = keysIter.next; + + // Steps 5 and 8-9. (Reordered) + var result = SetCopy(O); + + // Steps 6-7. + for (var nextValue of allowContentIterWithNext(keysIter, keysIterNext)) { + // Step 7.a and 7.b.i. (Implicit through for-of loop) + + // Steps 7.b.ii-iii. (Implicit through std_Set_add) + + // Step 7.b.iii.1. + callFunction(std_Set_add, result, nextValue); + } + + // Step 10. + return result; +} + +// Set.prototype.intersection ( other ) +// +// https://tc39.es/proposal-set-methods/#sec-set.prototype.intersection +function SetIntersection(other) { + // Step 1. + var O = this; + + // Step 2. + if (!IsObject(O) || (O = GuardToSetObject(O)) === null) { + return callFunction(CallSetMethodIfWrapped, this, other, "SetIntersection"); + } + + // Step 3. + var otherRec = GetSetRecord(other); + + // Steps 4 and 8-9. (Reordered) + var Set = GetBuiltinConstructor("Set"); + var result = new Set(); + + // Step 5. + var thisSize = callFunction(std_Set_size, O); + + // Steps 6-7. + if (thisSize <= otherRec.size) { + // Steps 6.a-b. + var values = callFunction(std_Set_values, O); + var setIterationResult = globalSetIterationResult; + while (true) { + var done = GetNextSetEntryForIterator(values, setIterationResult); + if (done) { + break; + } + + var value = setIterationResult[0]; + setIterationResult[0] = null; + + // Steps 6.b.i-ii. (Implicit through SetIterator) + + // Steps 6.b.iii.1-2. + if (callContentFunction(otherRec.has, otherRec.set, value)) { + // Steps 6.b.iii.2.a-b. (Implicit through std_Set_add) + + // Step 6.b.iii.2.c.i. + callFunction(std_Set_add, result, value); + } + + // Steps 6.b.iii.3-4. (Implicit through SetIterator) + } + } else { + // Step 7.a. + var keysIter = GetIteratorFromMethod(otherRec); + + // Steps 7.b-c. + for (var nextValue of allowContentIterWithNext(keysIter, keysIter.next)) { + // Step 7.c.i and 7.c.ii.1. (Implicit through for-of loop) + + // Steps 7.c.ii.2-4. (Implicit through std_Set_add) + + // Steps 7.c.ii.5-6. + if (callFunction(std_Set_has, O, nextValue)) { + callFunction(std_Set_add, result, nextValue); + } + } + } + + // Step 10. + return result; +} + +// Set.prototype.difference ( other ) +// +// https://tc39.es/proposal-set-methods/#sec-set.prototype.difference +function SetDifference(other) { + // Step 1. + var O = this; + + // Step 2. + if (!IsObject(O) || (O = GuardToSetObject(O)) === null) { + return callFunction(CallSetMethodIfWrapped, this, other, "SetDifference"); + } + + // Step 3. + var otherRec = GetSetRecord(other); + + // Steps 4 and 8-9. (Reordered) + var result = SetCopy(O); + + // Step 5. + var thisSize = callFunction(std_Set_size, O); + + // Steps 6-7. + if (thisSize <= otherRec.size) { + // Steps 6.a-b. + var values = callFunction(std_Set_values, result); + var setIterationResult = globalSetIterationResult; + while (true) { + var done = GetNextSetEntryForIterator(values, setIterationResult); + if (done) { + break; + } + + var value = setIterationResult[0]; + setIterationResult[0] = null; + + // Steps 6.b.i-ii. (Implicit through SetIterator) + + // Steps 6.b.iii.1-2. + if (callContentFunction(otherRec.has, otherRec.set, value)) { + callFunction(std_Set_delete, result, value); + } + } + } else { + // Step 7.a. + var keysIter = GetIteratorFromMethod(otherRec); + + // Steps 7.b-c. + for (var nextValue of allowContentIterWithNext(keysIter, keysIter.next)) { + // Step 7.c.i and 7.c.ii.1. (Implicit through for-of loop) + + // Steps 7.c.ii.2-3. + callFunction(std_Set_delete, result, nextValue); + } + } + + // Step 10. + return result; +} + +// Set.prototype.symmetricDifference ( other ) +// +// https://tc39.es/proposal-set-methods/#sec-set.prototype.symmetricdifference +function SetSymmetricDifference(other) { + // Step 1. + var O = this; + + // Step 2. + if (!IsObject(O) || (O = GuardToSetObject(O)) === null) { + return callFunction( + CallSetMethodIfWrapped, + this, + other, + "SetSymmetricDifference" + ); + } + + // Step 3. + var otherRec = GetSetRecord(other); + + // Step 4. + var keysIter = GetIteratorFromMethod(otherRec); + var keysIterNext = keysIter.next; + + // Steps 5 and 8-9. (Reordered) + var result = SetCopy(O); + + // Steps 6-7. + for (var nextValue of allowContentIterWithNext(keysIter, keysIterNext)) { + // Step 7.a and 7.b.i. (Implicit through for-of loop) + + // Steps 7.b.ii-iii. (Implicit through std_Set_has) + + // Steps 7.b.iv-v. + if (callFunction(std_Set_has, O, nextValue)) { + // Step 7.b.iv.1. + callFunction(std_Set_delete, result, nextValue); + } else { + // Step 7.b.v.1. + callFunction(std_Set_add, result, nextValue); + } + } + + // Step 10. + return result; +} + +// Set.prototype.isSubsetOf ( other ) +// +// https://tc39.es/proposal-set-methods/#sec-set.prototype.issubsetof +function SetIsSubsetOf(other) { + // Step 1. + var O = this; + + // Step 2. + if (!IsObject(O) || (O = GuardToSetObject(O)) === null) { + return callFunction(CallSetMethodIfWrapped, this, other, "SetIsSubsetOf"); + } + + // Step 3. + var otherRec = GetSetRecord(other); + + // Step 4. + var thisSize = callFunction(std_Set_size, O); + + // Step 5. + if (thisSize > otherRec.size) { + return false; + } + + // Steps 6-7. + var values = callFunction(std_Set_values, O); + var setIterationResult = globalSetIterationResult; + while (true) { + var done = GetNextSetEntryForIterator(values, setIterationResult); + if (done) { + break; + } + + var value = setIterationResult[0]; + setIterationResult[0] = null; + + // Steps 7.a-b. (Implicit through SetIterator) + + // Steps 7.c-d. + if (!callContentFunction(otherRec.has, otherRec.set, value)) { + return false; + } + + // Steps 7.e-f. (Implicit through SetIterator) + } + + // Step 7. + return true; +} + +// Set.prototype.isSupersetOf ( other ) +// +// https://tc39.es/proposal-set-methods/#sec-set.prototype.issupersetof +function SetIsSupersetOf(other) { + // Step 1. + var O = this; + + // Step 2. + if (!IsObject(O) || (O = GuardToSetObject(O)) === null) { + return callFunction(CallSetMethodIfWrapped, this, other, "SetIsSupersetOf"); + } + + // Step 3. + var otherRec = GetSetRecord(other); + + // Step 4. + var thisSize = callFunction(std_Set_size, O); + + // Step 5. + if (thisSize < otherRec.size) { + return false; + } + + // Step 6. + var keysIter = GetIteratorFromMethod(otherRec); + + // Steps 7-8. + for (var nextValue of allowContentIterWithNext(keysIter, keysIter.next)) { + // Step 8.a and 8.b.i. (Implicit through for-of loop) + + // Step 8.b.ii. + if (!callFunction(std_Set_has, O, nextValue)) { + // Step 8.b.ii.1. (Implicit through for-of loop) + + // Step 8.b.ii.2. + return false; + } + } + + // Step 9. + return true; +} + +// Set.prototype.isDisjointFrom ( other ) +// +// https://tc39.es/proposal-set-methods/#sec-set.prototype.isdisjointfrom +function SetIsDisjointFrom(other) { + // Step 1. + var O = this; + + // Step 2. + if (!IsObject(O) || (O = GuardToSetObject(O)) === null) { + return callFunction( + CallSetMethodIfWrapped, + this, + other, + "SetIsDisjointFrom" + ); + } + + // Step 3. + var otherRec = GetSetRecord(other); + + // Step 4. + var thisSize = callFunction(std_Set_size, O); + + // Steps 5-6. + if (thisSize <= otherRec.size) { + // Steps 5.a-b. + var values = callFunction(std_Set_values, O); + var setIterationResult = globalSetIterationResult; + while (true) { + var done = GetNextSetEntryForIterator(values, setIterationResult); + if (done) { + break; + } + + var value = setIterationResult[0]; + setIterationResult[0] = null; + + // Step 5.b.i-ii. (Implicit through SetIterator) + + // Steps 5.b.iii.1-2. + if (callContentFunction(otherRec.has, otherRec.set, value)) { + return false; + } + + // Steps 5.b.iii.3-4. (Implicit through SetIterator) + } + } else { + // Step 6.a. + var keysIter = GetIteratorFromMethod(otherRec); + + // Steps 6.b-c. + for (var nextValue of allowContentIterWithNext(keysIter, keysIter.next)) { + // Step 6.c.i and 6.c.ii.1. (Implicit through for-of loop) + + // Step 6.c.ii.2. + if (callFunction(std_Set_has, O, nextValue)) { + // Step 6.c.ii.2.a. (Implicit through for-of loop) + + // Step 6.c.ii.2.b. + return false; + } + } + } + + // Step 7. + return true; +} +#endif |