Coverage Report

Created: 2025-08-28 06:26

/src/serenity/Userland/Libraries/LibJS/Runtime/Set.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibJS/Runtime/KeyedCollections.h>
8
#include <LibJS/Runtime/Set.h>
9
#include <LibJS/Runtime/ValueInlines.h>
10
11
namespace JS {
12
13
JS_DEFINE_ALLOCATOR(Set);
14
15
NonnullGCPtr<Set> Set::create(Realm& realm)
16
0
{
17
0
    return realm.heap().allocate<Set>(realm, realm.intrinsics().set_prototype());
18
0
}
19
20
Set::Set(Object& prototype)
21
0
    : Object(ConstructWithPrototypeTag::Tag, prototype)
22
0
{
23
0
}
24
25
void Set::initialize(Realm& realm)
26
0
{
27
0
    m_values = Map::create(realm);
28
0
}
29
30
NonnullGCPtr<Set> Set::copy() const
31
0
{
32
0
    auto& vm = this->vm();
33
0
    auto& realm = *vm.current_realm();
34
    // FIXME: This is very inefficient, but there's no better way to do this at the moment, as the underlying Map
35
    //  implementation of m_values uses a non-copyable RedBlackTree.
36
0
    auto result = Set::create(realm);
37
0
    for (auto const& entry : *this)
38
0
        result->set_add(entry.key);
39
0
    return *result;
40
0
}
41
42
void Set::visit_edges(Cell::Visitor& visitor)
43
0
{
44
0
    Base::visit_edges(visitor);
45
0
    visitor.visit(m_values);
46
0
}
47
48
// 24.2.1.2 GetSetRecord ( obj ), https://tc39.es/ecma262/#sec-getsetrecord
49
ThrowCompletionOr<SetRecord> get_set_record(VM& vm, Value value)
50
0
{
51
    // 1. If obj is not an Object, throw a TypeError exception.
52
0
    if (!value.is_object())
53
0
        return vm.throw_completion<TypeError>(ErrorType::NotAnObject, value.to_string_without_side_effects());
54
0
    auto const& object = value.as_object();
55
56
    // 2. Let rawSize be ? Get(obj, "size").
57
0
    auto raw_size = TRY(object.get(vm.names.size));
58
59
    // 3. Let numSize be ? ToNumber(rawSize).
60
0
    auto number_size = TRY(raw_size.to_number(vm));
61
62
    // 4. NOTE: If rawSize is undefined, then numSize will be NaN.
63
    // 5. If numSize is NaN, throw a TypeError exception.
64
0
    if (number_size.is_nan())
65
0
        return vm.throw_completion<TypeError>(ErrorType::NumberIsNaN, "size"sv);
66
67
    // 6. Let intSize be ! ToIntegerOrInfinity(numSize).
68
0
    auto integer_size = MUST(number_size.to_integer_or_infinity(vm));
69
70
    // 7. If intSize < 0, throw a RangeError exception.
71
0
    if (integer_size < 0)
72
0
        return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "size"sv);
73
74
    // 8. Let has be ? Get(obj, "has").
75
0
    auto has = TRY(object.get(vm.names.has));
76
77
    // 9. If IsCallable(has) is false, throw a TypeError exception.
78
0
    if (!has.is_function())
79
0
        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, has.to_string_without_side_effects());
80
81
    // 10. Let keys be ? Get(obj, "keys").
82
0
    auto keys = TRY(object.get(vm.names.keys));
83
84
    // 11. If IsCallable(keys) is false, throw a TypeError exception.
85
0
    if (!keys.is_function())
86
0
        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, keys.to_string_without_side_effects());
87
88
    // 12. Return a new Set Record { [[SetObject]]: obj, [[Size]]: intSize, [[Has]]: has, [[Keys]]: keys }.
89
0
    return SetRecord { .set_object = object, .size = integer_size, .has = has.as_function(), .keys = keys.as_function() };
90
0
}
91
92
// 24.2.1.3 SetDataHas ( setData, value ), https://tc39.es/ecma262/#sec-setdatahas
93
bool set_data_has(NonnullGCPtr<Set> set_data, Value value)
94
0
{
95
    // NOTE: We do not need to implement SetDataIndex, as we do not implement the use of empty slots in Set. But we do
96
    //       need to match its behavior of always canonicalizing the provided value.
97
0
    value = canonicalize_keyed_collection_key(value);
98
99
    // 1. If SetDataIndex(setData, value) is not-found, return false.
100
    // 2. Return true.
101
0
    return set_data->set_has(value);
102
0
}
103
104
}