SetPrototype.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * Copyright (c) 2021-2022, Idan Horowitz <idan.horowitz@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/HashTable.h>
  7. #include <AK/TypeCasts.h>
  8. #include <LibJS/Runtime/AbstractOperations.h>
  9. #include <LibJS/Runtime/FunctionObject.h>
  10. #include <LibJS/Runtime/Iterator.h>
  11. #include <LibJS/Runtime/KeyedCollections.h>
  12. #include <LibJS/Runtime/SetIterator.h>
  13. #include <LibJS/Runtime/SetPrototype.h>
  14. #include <LibJS/Runtime/ValueInlines.h>
  15. namespace JS {
  16. GC_DEFINE_ALLOCATOR(SetPrototype);
  17. SetPrototype::SetPrototype(Realm& realm)
  18. : PrototypeObject(realm.intrinsics().object_prototype())
  19. {
  20. }
  21. void SetPrototype::initialize(Realm& realm)
  22. {
  23. auto& vm = this->vm();
  24. Base::initialize(realm);
  25. u8 attr = Attribute::Writable | Attribute::Configurable;
  26. define_native_function(realm, vm.names.add, add, 1, attr);
  27. define_native_function(realm, vm.names.clear, clear, 0, attr);
  28. define_native_function(realm, vm.names.delete_, delete_, 1, attr);
  29. define_native_function(realm, vm.names.difference, difference, 1, attr);
  30. define_native_function(realm, vm.names.entries, entries, 0, attr);
  31. define_native_function(realm, vm.names.forEach, for_each, 1, attr);
  32. define_native_function(realm, vm.names.has, has, 1, attr);
  33. define_native_function(realm, vm.names.intersection, intersection, 1, attr);
  34. define_native_function(realm, vm.names.isDisjointFrom, is_disjoint_from, 1, attr);
  35. define_native_function(realm, vm.names.isSubsetOf, is_subset_of, 1, attr);
  36. define_native_function(realm, vm.names.isSupersetOf, is_superset_of, 1, attr);
  37. define_native_accessor(realm, vm.names.size, size_getter, {}, Attribute::Configurable);
  38. define_native_function(realm, vm.names.symmetricDifference, symmetric_difference, 1, attr);
  39. define_native_function(realm, vm.names.union_, union_, 1, attr);
  40. define_native_function(realm, vm.names.values, values, 0, attr);
  41. define_direct_property(vm.names.keys, get_without_side_effects(vm.names.values), attr);
  42. // 24.2.3.18 Set.prototype [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-set.prototype-@@iterator
  43. define_direct_property(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.values), attr);
  44. // 24.2.3.19 Set.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-set.prototype-@@tostringtag
  45. define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, vm.names.Set.as_string()), Attribute::Configurable);
  46. }
  47. // 24.2.3.1 Set.prototype.add ( value ), https://tc39.es/ecma262/#sec-set.prototype.add
  48. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::add)
  49. {
  50. auto value = vm.argument(0);
  51. // 1. Let S be the this value.
  52. // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
  53. auto set = TRY(typed_this_object(vm));
  54. // 3. Set value to CanonicalizeKeyedCollectionKey(value).
  55. value = canonicalize_keyed_collection_key(value);
  56. // 4. For each element e of S.[[SetData]], do
  57. // a. If e is not empty and SameValue(e, value) is true, then
  58. // i. Return S.
  59. // 5. Append value to S.[[SetData]].
  60. set->set_add(value);
  61. // 6. Return S.
  62. return set;
  63. }
  64. // 24.2.3.2 Set.prototype.clear ( ), https://tc39.es/ecma262/#sec-set.prototype.clear
  65. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::clear)
  66. {
  67. // 1. Let S be the this value.
  68. // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
  69. auto set = TRY(typed_this_object(vm));
  70. // 3. For each element e of S.[[SetData]], do
  71. // a. Replace the element of S.[[SetData]] whose value is e with an element whose value is empty.
  72. set->set_clear();
  73. // 4. Return undefined.
  74. return js_undefined();
  75. }
  76. // 24.2.3.4 Set.prototype.delete ( value ), https://tc39.es/ecma262/#sec-set.prototype.delete
  77. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::delete_)
  78. {
  79. auto value = vm.argument(0);
  80. // 1. Let S be the this value.
  81. // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
  82. auto set = TRY(typed_this_object(vm));
  83. // 3. Set value to CanonicalizeKeyedCollectionKey(value).
  84. value = canonicalize_keyed_collection_key(value);
  85. // 4. For each element e of S.[[SetData]], do
  86. // a. If e is not empty and SameValue(e, value) is true, then
  87. // i. Replace the element of S.[[SetData]] whose value is e with an element whose value is empty.
  88. // ii. Return true.
  89. // 5. Return false.
  90. return Value(set->set_remove(value));
  91. }
  92. // 24.2.4.5 Set.prototype.difference ( other ), https://tc39.es/ecma262/#sec-set.prototype.difference
  93. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::difference)
  94. {
  95. // 1. Let O be the this value.
  96. // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
  97. auto set = TRY(typed_this_object(vm));
  98. // 3. Let otherRec be ? GetSetRecord(other).
  99. auto other_record = TRY(get_set_record(vm, vm.argument(0)));
  100. // 4. Let resultSetData be a copy of O.[[SetData]].
  101. auto result = set->copy();
  102. // 5. If SetDataSize(O.[[SetData]]) ≤ otherRec.[[Size]], then
  103. if (set->set_size() <= other_record.size) {
  104. // a. Let thisSize be the number of elements in O.[[SetData]].
  105. // b. Let index be 0.
  106. // c. Repeat, while index < thisSize,
  107. for (auto const& element : *set) {
  108. // i. Let e be resultSetData[index].
  109. // ii. If e is not EMPTY, then
  110. // 1. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
  111. auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
  112. // 2. If inOther is true, then
  113. if (in_other) {
  114. // a. Set resultSetData[index] to EMPTY.
  115. result->set_remove(element.key);
  116. }
  117. // iii. Set index to index + 1.
  118. }
  119. }
  120. // 6. Else,
  121. else {
  122. // a. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
  123. auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
  124. // b. Let next be NOT-STARTED.
  125. Optional<Value> next;
  126. // c. Repeat, while next is not DONE,
  127. do {
  128. // i. Set next to ? IteratorStepValue(keysIter).
  129. next = TRY(iterator_step_value(vm, keys_iterator));
  130. // ii. If next is not DONE, then
  131. if (next.has_value()) {
  132. // 1. Set next to CanonicalizeKeyedCollectionKey(next).
  133. next = canonicalize_keyed_collection_key(*next);
  134. // 2. Let valueIndex be SetDataIndex(resultSetData, next).
  135. // 3. If valueIndex is not NOT-FOUND, then
  136. if (result->set_has(*next)) {
  137. // a. Set resultSetData[valueIndex] to EMPTY.
  138. result->set_remove(*next);
  139. }
  140. }
  141. } while (next.has_value());
  142. }
  143. // 7. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
  144. // 8. Set result.[[SetData]] to resultSetData.
  145. // 9. Return result.
  146. return result;
  147. }
  148. // 24.2.3.6 Set.prototype.entries ( ), https://tc39.es/ecma262/#sec-set.prototype.entries
  149. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::entries)
  150. {
  151. auto& realm = *vm.current_realm();
  152. // 1. Let S be the this value.
  153. auto set = TRY(typed_this_object(vm));
  154. // 2. Return ? CreateSetIterator(S, key+value).
  155. return SetIterator::create(realm, set, Object::PropertyKind::KeyAndValue);
  156. }
  157. // 24.2.3.7 Set.prototype.forEach ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-set.prototype.foreach
  158. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::for_each)
  159. {
  160. auto callback_fn = vm.argument(0);
  161. auto this_arg = vm.argument(1);
  162. // 1. Let S be the this value.
  163. // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
  164. auto set = TRY(typed_this_object(vm));
  165. // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
  166. if (!callback_fn.is_function())
  167. return vm.throw_completion<TypeError>(ErrorType::NotAFunction, vm.argument(0).to_string_without_side_effects());
  168. // 4. Let entries be S.[[SetData]].
  169. // 5. Let numEntries be the number of elements in entries.
  170. // 6. Let index be 0.
  171. // 7. Repeat, while index < numEntries,
  172. for (auto& entry : *set) {
  173. // a. Let e be entries[index].
  174. // b. Set index to index + 1.
  175. // c. If e is not empty, then
  176. // NOTE: This is handled in Map::IteratorImpl.
  177. // i. Perform ? Call(callbackfn, thisArg, « e, e, S »).
  178. TRY(call(vm, callback_fn.as_function(), this_arg, entry.key, entry.key, set));
  179. // ii. NOTE: The number of elements in entries may have increased during execution of callbackfn.
  180. // iii. Set numEntries to the number of elements in entries.
  181. // NOTE: This is handled in Map::IteratorImpl.
  182. }
  183. // 8. Return undefined.
  184. return js_undefined();
  185. }
  186. // 24.2.3.8 Set.prototype.has ( value ), https://tc39.es/ecma262/#sec-set.prototype.has
  187. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::has)
  188. {
  189. auto value = vm.argument(0);
  190. // 1. Let S be the this value.
  191. // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
  192. auto set = TRY(typed_this_object(vm));
  193. // 3. Set value to CanonicalizeKeyedCollectionKey(value).
  194. value = canonicalize_keyed_collection_key(value);
  195. // 4. For each element e of S.[[SetData]], do
  196. // a. If e is not empty and SameValue(e, value) is true, return true.
  197. // 5. Return false.
  198. return Value(set->set_has(value));
  199. }
  200. // 24.2.4.9 Set.prototype.intersection ( other ), https://tc39.es/ecma262/#sec-set.prototype.intersection
  201. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::intersection)
  202. {
  203. auto& realm = *vm.current_realm();
  204. // 1. Let O be the this value.
  205. // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
  206. auto set = TRY(typed_this_object(vm));
  207. // 3. Let otherRec be ? GetSetRecord(other).
  208. auto other_record = TRY(get_set_record(vm, vm.argument(0)));
  209. // 4. Let resultSetData be a new empty List.
  210. auto result = Set::create(realm);
  211. // 5. If SetDataSize(O.[[SetData]]) ≤ otherRec.[[Size]], then
  212. if (set->set_size() <= other_record.size) {
  213. // a. Let thisSize be the number of elements in O.[[SetData]].
  214. // b. Let index be 0.
  215. // c. Repeat, while index < thisSize,
  216. for (auto const& element : *set) {
  217. // i. Let e be O.[[SetData]][index].
  218. // ii. Set index to index + 1.
  219. // iii. If e is not empty, then
  220. // 1. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
  221. auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
  222. // 2. If inOther is true, then
  223. if (in_other) {
  224. // a. NOTE: It is possible for earlier calls to otherRec.[[Has]] to remove and re-add an element of O.[[SetData]], which can cause the same element to be visited twice during this iteration.
  225. // b. If SetDataHas(resultSetData, e) is false, then
  226. if (!set_data_has(result, element.key)) {
  227. // i. Append e to resultSetData.
  228. result->set_add(element.key);
  229. }
  230. }
  231. // 3. NOTE: The number of elements in O.[[SetData]] may have increased during execution of otherRec.[[Has]].
  232. // 4. Set thisSize to the number of elements in O.[[SetData]].
  233. }
  234. }
  235. // 6. Else,
  236. else {
  237. // a. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
  238. auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
  239. // b. Let next be NOT-STARTED.
  240. Optional<Value> next;
  241. // c. Repeat, while next is not DONE,
  242. do {
  243. // i. Set next to ? IteratorStepValue(keysIter).
  244. next = TRY(iterator_step_value(vm, keys_iterator));
  245. // ii. If next is not DONE, then
  246. if (next.has_value()) {
  247. // 1. Set next to CanonicalizeKeyedCollectionKey(next).
  248. next = canonicalize_keyed_collection_key(*next);
  249. // 2. Let inThis be SetDataHas(O.[[SetData]], next).
  250. auto in_this = set_data_has(set, *next);
  251. // 3. If inThis is true, then
  252. if (in_this) {
  253. // a. NOTE: Because other is an arbitrary object, it is possible for its "keys" iterator to produce the same value more than once.
  254. // b. If SetDataHas(resultSetData, next) is false, then
  255. if (!set_data_has(result, *next)) {
  256. // i. Append next to resultSetData.
  257. result->set_add(*next);
  258. }
  259. }
  260. }
  261. } while (next.has_value());
  262. }
  263. // 7. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
  264. // 8. Set result.[[SetData]] to resultSetData.
  265. // 9. Return result.
  266. return result;
  267. }
  268. // 24.2.4.10 Set.prototype.isDisjointFrom ( other ), https://tc39.es/ecma262/#sec-set.prototype.isdisjointfrom
  269. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::is_disjoint_from)
  270. {
  271. // 1. Let O be the this value.
  272. // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
  273. auto set = TRY(typed_this_object(vm));
  274. // 3. Let otherRec be ? GetSetRecord(other).
  275. auto other_record = TRY(get_set_record(vm, vm.argument(0)));
  276. // 4. If SetDataSize(O.[[SetData]]) ≤ otherRec.[[Size]], then
  277. if (set->set_size() <= other_record.size) {
  278. // a. Let thisSize be the number of elements in O.[[SetData]].
  279. // b. Let index be 0.
  280. // c. Repeat, while index < thisSize,
  281. for (auto const& element : *set) {
  282. // i. Let e be O.[[SetData]][index].
  283. // ii. Set index to index + 1.
  284. // iii. If e is not empty, then
  285. // 1. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
  286. auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
  287. // 2. If inOther is true, return false.
  288. if (in_other)
  289. return false;
  290. // 3. NOTE: The number of elements in O.[[SetData]] may have increased during execution of otherRec.[[Has]].
  291. // 4. Set thisSize to the number of elements in O.[[SetData]].
  292. }
  293. }
  294. // 5. Else,
  295. else {
  296. // a. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
  297. auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
  298. // b. Let next be NOT-STARTED.
  299. Optional<Value> next;
  300. // c. Repeat, while next is not DONE,
  301. do {
  302. // i. Set next to ? IteratorStepValue(keysIter).
  303. next = TRY(iterator_step_value(vm, keys_iterator));
  304. // ii. If next is not DONE, then
  305. if (next.has_value()) {
  306. // 1. If SetDataHas(O.[[SetData]], next) is true, then
  307. if (set_data_has(set, *next)) {
  308. // a. Perform ? IteratorClose(keysIter, NormalCompletion(UNUSED)).
  309. TRY(iterator_close(vm, keys_iterator, normal_completion({})));
  310. // b. Return false.
  311. return false;
  312. }
  313. }
  314. } while (next.has_value());
  315. }
  316. // 6. Return true.
  317. return true;
  318. }
  319. // 24.2.4.11 Set.prototype.isSubsetOf ( other ), https://tc39.es/ecma262/#sec-set.prototype.issubsetof
  320. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::is_subset_of)
  321. {
  322. // 1. Let O be the this value.
  323. // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
  324. auto set = TRY(typed_this_object(vm));
  325. // 3. Let otherRec be ? GetSetRecord(other).
  326. auto other_record = TRY(get_set_record(vm, vm.argument(0)));
  327. // 4. If SetDataSize(O.[[SetData]]) > otherRec.[[Size]], return false.
  328. if (set->set_size() > other_record.size)
  329. return false;
  330. // 5. Let thisSize be the number of elements in O.[[SetData]].
  331. // 6. Let index be 0.
  332. // 7. Repeat, while index < thisSize,
  333. for (auto const& element : *set) {
  334. // a. Let e be O.[[SetData]][index].
  335. // b. Set index to index + 1.
  336. // c. If e is not empty, then
  337. // i. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
  338. auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
  339. // ii. If inOther is false, return false.
  340. if (!in_other)
  341. return false;
  342. // iii. NOTE: The number of elements in O.[[SetData]] may have increased during execution of otherRec.[[Has]].
  343. // iv. Set thisSize to the number of elements in O.[[SetData]].
  344. }
  345. // 8. Return true.
  346. return true;
  347. }
  348. // 24.2.4.12 Set.prototype.isSupersetOf ( other ), https://tc39.es/ecma262/#sec-set.prototype.issupersetof
  349. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::is_superset_of)
  350. {
  351. // 1. Let O be the this value.
  352. // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
  353. auto set = TRY(typed_this_object(vm));
  354. // 3. Let otherRec be ? GetSetRecord(other).
  355. auto other_record = TRY(get_set_record(vm, vm.argument(0)));
  356. // 4. If SetDataSize(O.[[SetData]]) < otherRec.[[Size]], return false.
  357. if (set->set_size() < other_record.size)
  358. return false;
  359. // 5. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
  360. auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
  361. // 6. Let next be NOT-STARTED.
  362. Optional<Value> next;
  363. // 7. Repeat, while next is not DONE,
  364. do {
  365. // a. Set next to ? IteratorStepValue(keysIter).
  366. next = TRY(iterator_step_value(vm, keys_iterator));
  367. // b. If next is not DONE, then
  368. if (next.has_value()) {
  369. // i. If SetDataHas(O.[[SetData]], next) is false, then
  370. if (!set_data_has(set, *next)) {
  371. // 1. Perform ? IteratorClose(keysIter, NormalCompletion(UNUSED)).
  372. TRY(iterator_close(vm, keys_iterator, normal_completion({})));
  373. // 2. Return false.
  374. return false;
  375. }
  376. }
  377. } while (next.has_value());
  378. // 8. Return true.
  379. return true;
  380. }
  381. // 24.2.3.14 get Set.prototype.size, https://tc39.es/ecma262/#sec-get-set.prototype.size
  382. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::size_getter)
  383. {
  384. // 1. Let S be the this value.
  385. // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
  386. auto set = TRY(typed_this_object(vm));
  387. // 3. Let count be 0.
  388. // 4. For each element e of S.[[SetData]], do
  389. // a. If e is not empty, set count to count + 1.
  390. auto count = set->set_size();
  391. // 5. Return 𝔽(count).
  392. return Value(count);
  393. }
  394. // 24.2.4.15 Set.prototype.symmetricDifference ( other ), https://tc39.es/ecma262/#sec-set.prototype.symmetricdifference
  395. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::symmetric_difference)
  396. {
  397. // 1. Let O be the this value.
  398. // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
  399. auto set = TRY(typed_this_object(vm));
  400. // 3. Let otherRec be ? GetSetRecord(other).
  401. auto other_record = TRY(get_set_record(vm, vm.argument(0)));
  402. // 4. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
  403. auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
  404. // 5. Let resultSetData be a copy of O.[[SetData]].
  405. auto result = set->copy();
  406. // 6. Let next be NOT-STARTED.
  407. Optional<Value> next;
  408. // 7. Repeat, while next is not DONE,
  409. do {
  410. // a. Set next to ? IteratorStepValue(keysIter).
  411. next = TRY(iterator_step_value(vm, keys_iterator));
  412. // b. If next is not DONE, then
  413. if (next.has_value()) {
  414. // i. Set next to CanonicalizeKeyedCollectionKey(next).
  415. next = canonicalize_keyed_collection_key(*next);
  416. // ii. Let resultIndex be SetDataIndex(resultSetData, next).
  417. // iii. If resultIndex is not-found, let alreadyInResult be false. Otherwise let alreadyInResult be true.
  418. auto already_in_result = result->set_has(*next);
  419. // iv. If SetDataHas(O.[[SetData]], next) is true, then
  420. if (set_data_has(set, *next)) {
  421. // 1. If alreadyInResult is true, set resultSetData[resultIndex] to empty.
  422. if (already_in_result)
  423. result->set_remove(*next);
  424. }
  425. // v. Else,
  426. else {
  427. // 1. If alreadyInResult is false, append next to resultSetData.
  428. if (!already_in_result)
  429. result->set_add(*next);
  430. }
  431. }
  432. } while (next.has_value());
  433. // 8. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
  434. // 9. Set result.[[SetData]] to resultSetData.
  435. // 10. Return result.
  436. return result;
  437. }
  438. // 24.2.4.16 Set.prototype.union ( other ), https://tc39.es/ecma262/#sec-set.prototype.union
  439. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::union_)
  440. {
  441. // 1. Let O be the this value.
  442. // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
  443. auto set = TRY(typed_this_object(vm));
  444. // 3. Let otherRec be ? GetSetRecord(other).
  445. auto other_record = TRY(get_set_record(vm, vm.argument(0)));
  446. // 4. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
  447. auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
  448. // 5. Let resultSetData be a copy of O.[[SetData]].
  449. auto result = set->copy();
  450. // 6. Let next be NOT-STARTED.
  451. Optional<Value> next;
  452. // 7. Repeat, while next is not DONE,
  453. do {
  454. // a. Set next to ? IteratorStepValue(keysIter).
  455. next = TRY(iterator_step_value(vm, keys_iterator));
  456. // b. If next is not DONE, then
  457. if (next.has_value()) {
  458. // i. Set next to CanonicalizeKeyedCollectionKey(next).
  459. next = canonicalize_keyed_collection_key(*next);
  460. // ii. If SetDataHas(resultSetData, next) is false, then
  461. if (!set_data_has(result, *next)) {
  462. // 1. Append next to resultSetData.
  463. result->set_add(*next);
  464. }
  465. }
  466. } while (next.has_value());
  467. // 8. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
  468. // 9. Set result.[[SetData]] to resultSetData.
  469. // 10. Return result.
  470. return result;
  471. }
  472. // 24.2.3.17 Set.prototype.values ( ), https://tc39.es/ecma262/#sec-set.prototype.values
  473. JS_DEFINE_NATIVE_FUNCTION(SetPrototype::values)
  474. {
  475. auto& realm = *vm.current_realm();
  476. // 1. Let S be the this value.
  477. // NOTE: CreateSetIterator checks the presence of a [[SetData]] slot, so we can do this here.
  478. auto set = TRY(typed_this_object(vm));
  479. // 2. Return ? CreateSetIterator(S, value).
  480. return SetIterator::create(realm, set, Object::PropertyKind::Value);
  481. }
  482. }