Coverage Report

Created: 2026-10-28 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Runtime/IndexedProperties.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/NonnullOwnPtr.h>
10
#include <LibJS/Runtime/Shape.h>
11
#include <LibJS/Runtime/Value.h>
12
13
namespace JS {
14
15
struct ValueAndAttributes {
16
    Value value;
17
    PropertyAttributes attributes { default_attributes };
18
19
    Optional<u32> property_offset {};
20
};
21
22
class IndexedProperties;
23
class IndexedPropertyIterator;
24
class GenericIndexedPropertyStorage;
25
26
class IndexedPropertyStorage {
27
public:
28
3
    virtual ~IndexedPropertyStorage() = default;
29
30
    enum class IsSimpleStorage {
31
        No,
32
        Yes,
33
    };
34
35
    virtual bool has_index(u32 index) const = 0;
36
    virtual Optional<ValueAndAttributes> get(u32 index) const = 0;
37
    virtual void put(u32 index, Value value, PropertyAttributes attributes = default_attributes) = 0;
38
    virtual void remove(u32 index) = 0;
39
40
    virtual ValueAndAttributes take_first() = 0;
41
    virtual ValueAndAttributes take_last() = 0;
42
43
    virtual size_t size() const = 0;
44
    virtual size_t array_like_size() const = 0;
45
    virtual bool set_array_like_size(size_t new_size) = 0;
46
47
400k
    bool is_simple_storage() const { return m_is_simple_storage; }
48
49
protected:
50
    explicit IndexedPropertyStorage(IsSimpleStorage is_simple_storage)
51
3
        : m_is_simple_storage(is_simple_storage == IsSimpleStorage::Yes)
52
3
    {
53
3
    }
54
55
private:
56
    bool m_is_simple_storage { false };
57
};
58
59
class SimpleIndexedPropertyStorage final : public IndexedPropertyStorage {
60
public:
61
    SimpleIndexedPropertyStorage()
62
3
        : IndexedPropertyStorage(IsSimpleStorage::Yes)
63
3
    {
64
3
    }
65
    explicit SimpleIndexedPropertyStorage(Vector<Value>&& initial_values);
66
67
    virtual bool has_index(u32 index) const override;
68
    virtual Optional<ValueAndAttributes> get(u32 index) const override;
69
    virtual void put(u32 index, Value value, PropertyAttributes attributes = default_attributes) override;
70
    virtual void remove(u32 index) override;
71
72
    virtual ValueAndAttributes take_first() override;
73
    virtual ValueAndAttributes take_last() override;
74
75
0
    virtual size_t size() const override { return m_packed_elements.size(); }
76
400k
    virtual size_t array_like_size() const override { return m_array_size; }
77
    virtual bool set_array_like_size(size_t new_size) override;
78
79
0
    Vector<Value> const& elements() const { return m_packed_elements; }
80
81
    [[nodiscard]] bool inline_has_index(u32 index) const
82
0
    {
83
0
        return index < m_array_size && !m_packed_elements.data()[index].is_empty();
84
0
    }
85
86
    [[nodiscard]] Optional<ValueAndAttributes> inline_get(u32 index) const
87
0
    {
88
0
        if (!inline_has_index(index))
89
0
            return {};
90
0
        return ValueAndAttributes { m_packed_elements.data()[index], default_attributes };
91
0
    }
92
93
private:
94
    friend GenericIndexedPropertyStorage;
95
96
    void grow_storage_if_needed();
97
98
    size_t m_array_size { 0 };
99
    Vector<Value> m_packed_elements;
100
};
101
102
class GenericIndexedPropertyStorage final : public IndexedPropertyStorage {
103
public:
104
    explicit GenericIndexedPropertyStorage(SimpleIndexedPropertyStorage&&);
105
    explicit GenericIndexedPropertyStorage()
106
0
        : IndexedPropertyStorage(IsSimpleStorage::No)
107
0
    {
108
0
    }
109
110
    virtual bool has_index(u32 index) const override;
111
    virtual Optional<ValueAndAttributes> get(u32 index) const override;
112
    virtual void put(u32 index, Value value, PropertyAttributes attributes = default_attributes) override;
113
    virtual void remove(u32 index) override;
114
115
    virtual ValueAndAttributes take_first() override;
116
    virtual ValueAndAttributes take_last() override;
117
118
0
    virtual size_t size() const override { return m_sparse_elements.size(); }
119
0
    virtual size_t array_like_size() const override { return m_array_size; }
120
    virtual bool set_array_like_size(size_t new_size) override;
121
122
0
    HashMap<u32, ValueAndAttributes> const& sparse_elements() const { return m_sparse_elements; }
123
124
private:
125
    size_t m_array_size { 0 };
126
    HashMap<u32, ValueAndAttributes> m_sparse_elements;
127
};
128
129
class IndexedPropertyIterator {
130
public:
131
    IndexedPropertyIterator(IndexedProperties const&, u32 starting_index, bool skip_empty);
132
133
    IndexedPropertyIterator& operator++();
134
    IndexedPropertyIterator& operator*();
135
    bool operator!=(IndexedPropertyIterator const&) const;
136
137
0
    u32 index() const { return m_index; }
138
139
private:
140
    void skip_empty_indices();
141
142
    IndexedProperties const& m_indexed_properties;
143
    Vector<u32> m_cached_indices;
144
    size_t m_next_cached_index { 0 };
145
    u32 m_index { 0 };
146
    bool m_skip_empty { false };
147
};
148
149
class IndexedProperties {
150
public:
151
12.9k
    IndexedProperties() = default;
152
153
    explicit IndexedProperties(Vector<Value> values)
154
0
    {
155
0
        if (!values.is_empty())
156
0
            m_storage = make<SimpleIndexedPropertyStorage>(move(values));
157
0
    }
158
159
0
    bool has_index(u32 index) const { return m_storage ? m_storage->has_index(index) : false; }
160
    Optional<ValueAndAttributes> get(u32 index) const;
161
    void put(u32 index, Value value, PropertyAttributes attributes = default_attributes);
162
    void remove(u32 index);
163
164
0
    void append(Value value, PropertyAttributes attributes = default_attributes) { put(array_like_size(), value, attributes); }
165
166
0
    IndexedPropertyIterator begin(bool skip_empty = true) const { return IndexedPropertyIterator(*this, 0, skip_empty); }
167
0
    IndexedPropertyIterator end() const { return IndexedPropertyIterator(*this, array_like_size(), false); }
168
169
0
    bool is_empty() const { return array_like_size() == 0; }
170
400k
    size_t array_like_size() const { return m_storage ? m_storage->array_like_size() : 0; }
171
    bool set_array_like_size(size_t);
172
173
0
    IndexedPropertyStorage* storage() { return m_storage; }
174
0
    IndexedPropertyStorage const* storage() const { return m_storage; }
175
176
    size_t real_size() const;
177
178
    Vector<u32> indices() const;
179
180
    template<typename Callback>
181
    void for_each_value(Callback callback)
182
0
    {
183
0
        if (!m_storage)
184
0
            return;
185
0
        if (m_storage->is_simple_storage()) {
186
0
            for (auto& value : static_cast<SimpleIndexedPropertyStorage&>(*m_storage).elements())
187
0
                callback(value);
188
0
        } else {
189
0
            for (auto& element : static_cast<GenericIndexedPropertyStorage const&>(*m_storage).sparse_elements())
190
0
                callback(element.value.value);
191
0
        }
192
0
    }
193
194
private:
195
    void switch_to_generic_storage();
196
    void ensure_storage();
197
198
    OwnPtr<IndexedPropertyStorage> m_storage;
199
};
200
201
}