mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 09:14:58 +00:00
LibJS: Implement Set.prototype.union
This commit is contained in:
parent
8e1df36588
commit
fee65f6453
6 changed files with 76 additions and 0 deletions
|
@ -581,6 +581,7 @@ struct CommonPropertyNames {
|
|||
PropertyKey register_ { "register", PropertyKey::StringMayBeNumber::No };
|
||||
PropertyKey return_ { "return", PropertyKey::StringMayBeNumber::No };
|
||||
PropertyKey throw_ { "throw", PropertyKey::StringMayBeNumber::No };
|
||||
PropertyKey union_ { "union", PropertyKey::StringMayBeNumber::No };
|
||||
PropertyKey xor_ { "xor", PropertyKey::StringMayBeNumber::No };
|
||||
PropertyKey inputAlias { "$_", PropertyKey::StringMayBeNumber::No };
|
||||
PropertyKey lastMatchAlias { "$&", PropertyKey::StringMayBeNumber::No };
|
||||
|
|
|
@ -23,6 +23,18 @@ void Set::initialize(Realm& realm)
|
|||
m_values = Map::create(realm);
|
||||
}
|
||||
|
||||
NonnullGCPtr<Set> Set::copy() const
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
auto& realm = *vm.current_realm();
|
||||
// FIXME: This is very inefficient, but there's no better way to do this at the moment, as the underlying Map
|
||||
// implementation of m_values uses a non-copyable RedBlackTree.
|
||||
auto* result = Set::create(realm);
|
||||
for (auto const& entry : *this)
|
||||
result->set_add(entry.key);
|
||||
return *result;
|
||||
}
|
||||
|
||||
void Set::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
auto begin() { return m_values->begin(); }
|
||||
auto end() const { return m_values->end(); }
|
||||
|
||||
NonnullGCPtr<Set> copy() const;
|
||||
|
||||
private:
|
||||
explicit Set(Object& prototype);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ void SetPrototype::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.forEach, for_each, 1, attr);
|
||||
define_native_function(realm, vm.names.has, has, 1, attr);
|
||||
define_native_function(realm, vm.names.values, values, 0, attr);
|
||||
define_native_function(realm, vm.names.union_, union_, 1, attr);
|
||||
define_native_accessor(realm, vm.names.size, size_getter, {}, Attribute::Configurable);
|
||||
|
||||
define_direct_property(vm.names.keys, get_without_side_effects(vm.names.values), attr);
|
||||
|
@ -184,4 +185,51 @@ static ThrowCompletionOr<Iterator> get_keys_iterator(VM& vm, SetRecord const& se
|
|||
return Iterator { .iterator = &keys_iterator.as_object(), .next_method = next_method, .done = false };
|
||||
}
|
||||
|
||||
// 1 Set.prototype.union ( other ), https://tc39.es/proposal-set-methods/#sec-set.prototype.union
|
||||
JS_DEFINE_NATIVE_FUNCTION(SetPrototype::union_)
|
||||
{
|
||||
// 1. Let O be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(O, [[SetData]]).
|
||||
auto* set = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let otherRec be ? GetSetRecord(other).
|
||||
auto other_record = TRY(get_set_record(vm, vm.argument(0)));
|
||||
|
||||
// 4. Let keysIter be ? GetKeysIterator(otherRec).
|
||||
auto keys_iterator = TRY(get_keys_iterator(vm, other_record));
|
||||
|
||||
// 5. Let resultSetData be a copy of O.[[SetData]].
|
||||
auto result = set->copy();
|
||||
|
||||
// 6. Let next be true.
|
||||
auto next = true;
|
||||
|
||||
// 7. Repeat, while next is not false,
|
||||
while (next) {
|
||||
// a. Set next to ? IteratorStep(keysIter).
|
||||
auto* iterator_result = TRY(iterator_step(vm, keys_iterator));
|
||||
next = iterator_result;
|
||||
|
||||
// b. If next is not false, then
|
||||
if (next) {
|
||||
// i. Let nextValue be ? IteratorValue(next).
|
||||
auto next_value = TRY(iterator_value(vm, *iterator_result));
|
||||
|
||||
// ii. If nextValue is -0𝔽, set nextValue to +0𝔽.
|
||||
if (next_value.is_negative_zero())
|
||||
next_value = Value(0);
|
||||
|
||||
// iii. If SetDataHas(resultSetData, nextValue) is false, then
|
||||
// 1. Append nextValue to resultSetData.
|
||||
result->set_add(next_value);
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
|
||||
// 9. Set result.[[SetData]] to resultSetData.
|
||||
|
||||
// 10. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ private:
|
|||
JS_DECLARE_NATIVE_FUNCTION(for_each);
|
||||
JS_DECLARE_NATIVE_FUNCTION(has);
|
||||
JS_DECLARE_NATIVE_FUNCTION(values);
|
||||
JS_DECLARE_NATIVE_FUNCTION(union_);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(size_getter);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
test("basic functionality", () => {
|
||||
expect(Set.prototype.union).toHaveLength(1);
|
||||
|
||||
const set1 = new Set(["a", "b", "c"]);
|
||||
const set2 = new Set(["b", "c", "d"]);
|
||||
const union1to2 = set1.union(set2);
|
||||
const union2to1 = set2.union(set1);
|
||||
for (const unionSet of [union1to2, union2to1]) {
|
||||
expect(unionSet).toHaveSize(4);
|
||||
["a", "b", "c", "d"].forEach(value => expect(unionSet.has(value)).toBeTrue());
|
||||
}
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue