Coverage Report

Created: 2026-09-26 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/ByteBuffer.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#pragma once
9
10
#include <AK/Assertions.h>
11
#include <AK/Error.h>
12
#include <AK/Span.h>
13
#include <AK/Types.h>
14
#include <AK/kmalloc.h>
15
16
#ifdef AK_COMPILER_GCC
17
#    pragma GCC diagnostic push
18
//   GCC incorrectly claims that the size of the ByteBuffer is too small in some cases when UBSan is disabled.
19
#    pragma GCC diagnostic ignored "-Wstringop-overflow"
20
#endif
21
22
namespace AK {
23
namespace Detail {
24
25
template<size_t inline_capacity>
26
class ByteBuffer {
27
public:
28
481M
    ByteBuffer() = default;
AK::Detail::ByteBuffer<32ul>::ByteBuffer()
Line
Count
Source
28
13.0M
    ByteBuffer() = default;
AK::Detail::ByteBuffer<0ul>::ByteBuffer()
Line
Count
Source
28
169k
    ByteBuffer() = default;
AK::Detail::ByteBuffer<256ul>::ByteBuffer()
Line
Count
Source
28
468M
    ByteBuffer() = default;
29
30
    ~ByteBuffer()
31
942M
    {
32
942M
        clear();
33
942M
    }
AK::Detail::ByteBuffer<256ul>::~ByteBuffer()
Line
Count
Source
31
893M
    {
32
893M
        clear();
33
893M
    }
AK::Detail::ByteBuffer<32ul>::~ByteBuffer()
Line
Count
Source
31
37.3M
    {
32
37.3M
        clear();
33
37.3M
    }
AK::Detail::ByteBuffer<0ul>::~ByteBuffer()
Line
Count
Source
31
11.4M
    {
32
11.4M
        clear();
33
11.4M
    }
34
35
    ByteBuffer(ByteBuffer const& other)
36
425M
    {
37
425M
        MUST(try_resize(other.size()));
38
425M
        VERIFY(m_size == other.size());
39
425M
        __builtin_memcpy(data(), other.data(), other.size());
40
425M
    }
AK::Detail::ByteBuffer<32ul>::ByteBuffer(AK::Detail::ByteBuffer<32ul> const&)
Line
Count
Source
36
38.2k
    {
37
38.2k
        MUST(try_resize(other.size()));
38
38.2k
        VERIFY(m_size == other.size());
39
38.2k
        __builtin_memcpy(data(), other.data(), other.size());
40
38.2k
    }
AK::Detail::ByteBuffer<256ul>::ByteBuffer(AK::Detail::ByteBuffer<256ul> const&)
Line
Count
Source
36
425M
    {
37
425M
        MUST(try_resize(other.size()));
38
425M
        VERIFY(m_size == other.size());
39
425M
        __builtin_memcpy(data(), other.data(), other.size());
40
425M
    }
Unexecuted instantiation: AK::Detail::ByteBuffer<0ul>::ByteBuffer(AK::Detail::ByteBuffer<0ul> const&)
41
42
    ByteBuffer(ByteBuffer&& other)
43
35.5M
    {
44
35.5M
        move_from(move(other));
45
35.5M
    }
AK::Detail::ByteBuffer<32ul>::ByteBuffer(AK::Detail::ByteBuffer<32ul>&&)
Line
Count
Source
43
24.2M
    {
44
24.2M
        move_from(move(other));
45
24.2M
    }
AK::Detail::ByteBuffer<0ul>::ByteBuffer(AK::Detail::ByteBuffer<0ul>&&)
Line
Count
Source
43
11.3M
    {
44
11.3M
        move_from(move(other));
45
11.3M
    }
46
47
    ByteBuffer& operator=(ByteBuffer&& other)
48
11.1M
    {
49
11.1M
        if (this != &other) {
50
11.1M
            if (!m_inline)
51
11.7k
                kfree_sized(m_outline_buffer, m_outline_capacity);
52
11.1M
            move_from(move(other));
53
11.1M
        }
54
11.1M
        return *this;
55
11.1M
    }
56
57
    ByteBuffer& operator=(ByteBuffer const& other)
58
5.42M
    {
59
5.42M
        if (this != &other) {
60
5.42M
            if (m_size > other.size()) {
61
471k
                trim(other.size(), true);
62
4.95M
            } else {
63
4.95M
                MUST(try_resize(other.size()));
64
4.95M
            }
65
5.42M
            __builtin_memcpy(data(), other.data(), other.size());
66
5.42M
        }
67
5.42M
        return *this;
68
5.42M
    }
AK::Detail::ByteBuffer<32ul>::operator=(AK::Detail::ByteBuffer<32ul> const&)
Line
Count
Source
58
551
    {
59
551
        if (this != &other) {
60
551
            if (m_size > other.size()) {
61
0
                trim(other.size(), true);
62
551
            } else {
63
551
                MUST(try_resize(other.size()));
64
551
            }
65
551
            __builtin_memcpy(data(), other.data(), other.size());
66
551
        }
67
551
        return *this;
68
551
    }
AK::Detail::ByteBuffer<256ul>::operator=(AK::Detail::ByteBuffer<256ul> const&)
Line
Count
Source
58
5.42M
    {
59
5.42M
        if (this != &other) {
60
5.42M
            if (m_size > other.size()) {
61
471k
                trim(other.size(), true);
62
4.95M
            } else {
63
4.95M
                MUST(try_resize(other.size()));
64
4.95M
            }
65
5.42M
            __builtin_memcpy(data(), other.data(), other.size());
66
5.42M
        }
67
5.42M
        return *this;
68
5.42M
    }
69
70
    [[nodiscard]] static ErrorOr<ByteBuffer> create_uninitialized(size_t size)
71
506k
    {
72
506k
        auto buffer = ByteBuffer();
73
506k
        TRY(buffer.try_resize(size));
74
506k
        return { move(buffer) };
75
506k
    }
AK::Detail::ByteBuffer<32ul>::create_uninitialized(unsigned long)
Line
Count
Source
71
337k
    {
72
337k
        auto buffer = ByteBuffer();
73
337k
        TRY(buffer.try_resize(size));
74
337k
        return { move(buffer) };
75
337k
    }
AK::Detail::ByteBuffer<0ul>::create_uninitialized(unsigned long)
Line
Count
Source
71
169k
    {
72
169k
        auto buffer = ByteBuffer();
73
169k
        TRY(buffer.try_resize(size));
74
169k
        return { move(buffer) };
75
169k
    }
76
77
    [[nodiscard]] static ErrorOr<ByteBuffer> create_zeroed(size_t size)
78
110k
    {
79
110k
        auto buffer = TRY(create_uninitialized(size));
80
81
110k
        buffer.zero_fill();
82
110k
        VERIFY(size == 0 || (buffer[0] == 0 && buffer[size - 1] == 0));
83
110k
        return { move(buffer) };
84
110k
    }
85
86
    [[nodiscard]] static ErrorOr<ByteBuffer> copy(void const* data, size_t size)
87
17.7k
    {
88
17.7k
        auto buffer = TRY(create_uninitialized(size));
89
17.7k
        if (buffer.m_inline && size > inline_capacity)
90
17.7k
            VERIFY_NOT_REACHED();
91
17.7k
        if (size != 0)
92
17.6k
            __builtin_memcpy(buffer.data(), data, size);
93
17.7k
        return { move(buffer) };
94
17.7k
    }
95
96
    [[nodiscard]] static ErrorOr<ByteBuffer> copy(ReadonlyBytes bytes)
97
2.35k
    {
98
2.35k
        return copy(bytes.data(), bytes.size());
99
2.35k
    }
100
101
    [[nodiscard]] static ErrorOr<ByteBuffer> xor_buffers(ReadonlyBytes first, ReadonlyBytes second)
102
0
    {
103
0
        if (first.size() != second.size())
104
0
            return Error::from_errno(EINVAL);
105
106
0
        auto buffer = TRY(create_uninitialized(first.size()));
107
0
        auto buffer_data = buffer.data();
108
0
        auto first_data = first.data();
109
0
        auto second_data = second.data();
110
0
        for (size_t i = 0; i < first.size(); ++i)
111
0
            buffer_data[i] = first_data[i] ^ second_data[i];
112
113
0
        return { move(buffer) };
114
0
    }
115
116
    template<size_t other_inline_capacity>
117
    bool operator==(ByteBuffer<other_inline_capacity> const& other) const
118
0
    {
119
0
        if (size() != other.size())
120
0
            return false;
121
122
        // So they both have data, and the same length.
123
0
        return !__builtin_memcmp(data(), other.data(), size());
124
0
    }
125
126
    [[nodiscard]] u8& operator[](size_t i)
127
967M
    {
128
967M
        VERIFY(i < m_size);
129
967M
        return data()[i];
130
967M
    }
131
132
    [[nodiscard]] u8 const& operator[](size_t i) const
133
2.06G
    {
134
2.06G
        VERIFY(i < m_size);
135
2.06G
        return data()[i];
136
2.06G
    }
137
138
586M
    [[nodiscard]] bool is_empty() const { return m_size == 0; }
AK::Detail::ByteBuffer<32ul>::is_empty() const
Line
Count
Source
138
1.03k
    [[nodiscard]] bool is_empty() const { return m_size == 0; }
AK::Detail::ByteBuffer<256ul>::is_empty() const
Line
Count
Source
138
586M
    [[nodiscard]] bool is_empty() const { return m_size == 0; }
139
15.6G
    [[nodiscard]] size_t size() const { return m_size; }
AK::Detail::ByteBuffer<32ul>::size() const
Line
Count
Source
139
7.62G
    [[nodiscard]] size_t size() const { return m_size; }
AK::Detail::ByteBuffer<256ul>::size() const
Line
Count
Source
139
7.97G
    [[nodiscard]] size_t size() const { return m_size; }
Unexecuted instantiation: AK::Detail::ByteBuffer<0ul>::size() const
140
141
#ifdef AK_COMPILER_GCC
142
#    pragma GCC diagnostic push
143
//   Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109727
144
#    pragma GCC diagnostic ignored "-Warray-bounds"
145
#endif
146
    [[nodiscard]] u8* data()
147
5.31G
    {
148
5.31G
        return m_inline ? m_inline_buffer : m_outline_buffer;
149
5.31G
    }
AK::Detail::ByteBuffer<32ul>::data()
Line
Count
Source
147
1.73G
    {
148
1.73G
        return m_inline ? m_inline_buffer : m_outline_buffer;
149
1.73G
    }
AK::Detail::ByteBuffer<256ul>::data()
Line
Count
Source
147
3.54G
    {
148
3.54G
        return m_inline ? m_inline_buffer : m_outline_buffer;
149
3.54G
    }
AK::Detail::ByteBuffer<0ul>::data()
Line
Count
Source
147
31.6M
    {
148
31.6M
        return m_inline ? m_inline_buffer : m_outline_buffer;
149
31.6M
    }
150
4.04G
    [[nodiscard]] u8 const* data() const { return m_inline ? m_inline_buffer : m_outline_buffer; }
AK::Detail::ByteBuffer<32ul>::data() const
Line
Count
Source
150
3.04G
    [[nodiscard]] u8 const* data() const { return m_inline ? m_inline_buffer : m_outline_buffer; }
AK::Detail::ByteBuffer<256ul>::data() const
Line
Count
Source
150
999M
    [[nodiscard]] u8 const* data() const { return m_inline ? m_inline_buffer : m_outline_buffer; }
Unexecuted instantiation: AK::Detail::ByteBuffer<0ul>::data() const
151
#ifdef AK_COMPILER_GCC
152
#    pragma GCC diagnostic pop
153
#endif
154
155
    [[nodiscard]] Bytes bytes()
156
736k
    {
157
736k
        return { data(), size() };
158
736k
    }
159
489k
    [[nodiscard]] ReadonlyBytes bytes() const { return { data(), size() }; }
160
161
436M
    [[nodiscard]] AK::Bytes span() { return { data(), size() }; }
AK::Detail::ByteBuffer<32ul>::span()
Line
Count
Source
161
436M
    [[nodiscard]] AK::Bytes span() { return { data(), size() }; }
Unexecuted instantiation: AK::Detail::ByteBuffer<0ul>::span()
162
969M
    [[nodiscard]] AK::ReadonlyBytes span() const { return { data(), size() }; }
AK::Detail::ByteBuffer<32ul>::span() const
Line
Count
Source
162
969M
    [[nodiscard]] AK::ReadonlyBytes span() const { return { data(), size() }; }
Unexecuted instantiation: AK::Detail::ByteBuffer<0ul>::span() const
163
164
1.09k
    [[nodiscard]] u8* offset_pointer(size_t offset) { return data() + offset; }
165
0
    [[nodiscard]] u8 const* offset_pointer(size_t offset) const { return data() + offset; }
166
167
    [[nodiscard]] void* end_pointer() { return data() + m_size; }
168
    [[nodiscard]] void const* end_pointer() const { return data() + m_size; }
169
170
    [[nodiscard]] ErrorOr<ByteBuffer> slice(size_t offset, size_t size) const
171
0
    {
172
        // I cannot hand you a slice I don't have
173
0
        VERIFY(offset + size <= this->size());
174
175
0
        return copy(offset_pointer(offset), size);
176
0
    }
177
178
    void clear()
179
1.06G
    {
180
1.06G
        if (!m_inline) {
181
6.89M
            kfree_sized(m_outline_buffer, m_outline_capacity);
182
6.89M
            m_inline = true;
183
6.89M
        }
184
1.06G
        m_size = 0;
185
1.06G
    }
AK::Detail::ByteBuffer<256ul>::clear()
Line
Count
Source
179
1.02G
    {
180
1.02G
        if (!m_inline) {
181
6.53M
            kfree_sized(m_outline_buffer, m_outline_capacity);
182
6.53M
            m_inline = true;
183
6.53M
        }
184
1.02G
        m_size = 0;
185
1.02G
    }
AK::Detail::ByteBuffer<32ul>::clear()
Line
Count
Source
179
37.3M
    {
180
37.3M
        if (!m_inline) {
181
186k
            kfree_sized(m_outline_buffer, m_outline_capacity);
182
186k
            m_inline = true;
183
186k
        }
184
37.3M
        m_size = 0;
185
37.3M
    }
AK::Detail::ByteBuffer<0ul>::clear()
Line
Count
Source
179
11.4M
    {
180
11.4M
        if (!m_inline) {
181
169k
            kfree_sized(m_outline_buffer, m_outline_capacity);
182
169k
            m_inline = true;
183
169k
        }
184
11.4M
        m_size = 0;
185
11.4M
    }
186
187
    enum class ZeroFillNewElements {
188
        No,
189
        Yes,
190
    };
191
192
    ALWAYS_INLINE void resize(size_t new_size, ZeroFillNewElements zero_fill_new_elements = ZeroFillNewElements::No)
193
13.8k
    {
194
13.8k
        MUST(try_resize(new_size, zero_fill_new_elements));
195
13.8k
    }
AK::Detail::ByteBuffer<32ul>::resize(unsigned long, AK::Detail::ByteBuffer<32ul>::ZeroFillNewElements)
Line
Count
Source
193
13.8k
    {
194
13.8k
        MUST(try_resize(new_size, zero_fill_new_elements));
195
13.8k
    }
Unexecuted instantiation: AK::Detail::ByteBuffer<256ul>::resize(unsigned long, AK::Detail::ByteBuffer<256ul>::ZeroFillNewElements)
196
197
    void trim(size_t size, bool may_discard_existing_data)
198
362M
    {
199
362M
        VERIFY(size <= m_size);
200
362M
        if (!m_inline && size <= inline_capacity)
201
135k
            shrink_into_inline_buffer(size, may_discard_existing_data);
202
362M
        m_size = size;
203
362M
    }
AK::Detail::ByteBuffer<32ul>::trim(unsigned long, bool)
Line
Count
Source
198
124k
    {
199
124k
        VERIFY(size <= m_size);
200
124k
        if (!m_inline && size <= inline_capacity)
201
3.44k
            shrink_into_inline_buffer(size, may_discard_existing_data);
202
124k
        m_size = size;
203
124k
    }
AK::Detail::ByteBuffer<256ul>::trim(unsigned long, bool)
Line
Count
Source
198
362M
    {
199
362M
        VERIFY(size <= m_size);
200
362M
        if (!m_inline && size <= inline_capacity)
201
132k
            shrink_into_inline_buffer(size, may_discard_existing_data);
202
362M
        m_size = size;
203
362M
    }
Unexecuted instantiation: AK::Detail::ByteBuffer<0ul>::trim(unsigned long, bool)
204
205
    ALWAYS_INLINE void ensure_capacity(size_t new_capacity)
206
468M
    {
207
468M
        MUST(try_ensure_capacity(new_capacity));
208
468M
    }
AK::Detail::ByteBuffer<32ul>::ensure_capacity(unsigned long)
Line
Count
Source
206
21.3k
    {
207
21.3k
        MUST(try_ensure_capacity(new_capacity));
208
21.3k
    }
AK::Detail::ByteBuffer<256ul>::ensure_capacity(unsigned long)
Line
Count
Source
206
468M
    {
207
468M
        MUST(try_ensure_capacity(new_capacity));
208
468M
    }
209
210
    ErrorOr<void> try_resize(size_t new_size, ZeroFillNewElements zero_fill_new_elements = ZeroFillNewElements::No)
211
3.58G
    {
212
3.58G
        if (new_size <= m_size) {
213
362M
            trim(new_size, false);
214
362M
            return {};
215
362M
        }
216
3.58G
        TRY(try_ensure_capacity(new_size));
217
218
3.21G
        if (zero_fill_new_elements == ZeroFillNewElements::Yes) {
219
0
            __builtin_memset(data() + m_size, 0, new_size - m_size);
220
0
        }
221
222
3.21G
        m_size = new_size;
223
3.21G
        return {};
224
3.21G
    }
AK::Detail::ByteBuffer<32ul>::try_resize(unsigned long, AK::Detail::ByteBuffer<32ul>::ZeroFillNewElements)
Line
Count
Source
211
40.6M
    {
212
40.6M
        if (new_size <= m_size) {
213
124k
            trim(new_size, false);
214
124k
            return {};
215
124k
        }
216
40.6M
        TRY(try_ensure_capacity(new_size));
217
218
40.4M
        if (zero_fill_new_elements == ZeroFillNewElements::Yes) {
219
0
            __builtin_memset(data() + m_size, 0, new_size - m_size);
220
0
        }
221
222
40.4M
        m_size = new_size;
223
40.4M
        return {};
224
40.4M
    }
AK::Detail::ByteBuffer<256ul>::try_resize(unsigned long, AK::Detail::ByteBuffer<256ul>::ZeroFillNewElements)
Line
Count
Source
211
3.54G
    {
212
3.54G
        if (new_size <= m_size) {
213
362M
            trim(new_size, false);
214
362M
            return {};
215
362M
        }
216
3.54G
        TRY(try_ensure_capacity(new_size));
217
218
3.17G
        if (zero_fill_new_elements == ZeroFillNewElements::Yes) {
219
0
            __builtin_memset(data() + m_size, 0, new_size - m_size);
220
0
        }
221
222
3.17G
        m_size = new_size;
223
3.17G
        return {};
224
3.17G
    }
AK::Detail::ByteBuffer<0ul>::try_resize(unsigned long, AK::Detail::ByteBuffer<0ul>::ZeroFillNewElements)
Line
Count
Source
211
169k
    {
212
169k
        if (new_size <= m_size) {
213
0
            trim(new_size, false);
214
0
            return {};
215
0
        }
216
169k
        TRY(try_ensure_capacity(new_size));
217
218
169k
        if (zero_fill_new_elements == ZeroFillNewElements::Yes) {
219
0
            __builtin_memset(data() + m_size, 0, new_size - m_size);
220
0
        }
221
222
169k
        m_size = new_size;
223
169k
        return {};
224
169k
    }
225
226
    ErrorOr<void> try_ensure_capacity(size_t new_capacity)
227
3.69G
    {
228
3.69G
        if (new_capacity <= capacity())
229
3.68G
            return {};
230
7.36M
        return try_ensure_capacity_slowpath(new_capacity);
231
3.69G
    }
AK::Detail::ByteBuffer<32ul>::try_ensure_capacity(unsigned long)
Line
Count
Source
227
40.5M
    {
228
40.5M
        if (new_capacity <= capacity())
229
40.2M
            return {};
230
249k
        return try_ensure_capacity_slowpath(new_capacity);
231
40.5M
    }
AK::Detail::ByteBuffer<256ul>::try_ensure_capacity(unsigned long)
Line
Count
Source
227
3.65G
    {
228
3.65G
        if (new_capacity <= capacity())
229
3.64G
            return {};
230
6.95M
        return try_ensure_capacity_slowpath(new_capacity);
231
3.65G
    }
AK::Detail::ByteBuffer<0ul>::try_ensure_capacity(unsigned long)
Line
Count
Source
227
169k
    {
228
169k
        if (new_capacity <= capacity())
229
0
            return {};
230
169k
        return try_ensure_capacity_slowpath(new_capacity);
231
169k
    }
232
233
    /// Return a span of bytes past the end of this ByteBuffer for writing.
234
    /// Ensures that the required space is available.
235
    ErrorOr<Bytes> get_bytes_for_writing(size_t length)
236
3.48M
    {
237
3.48M
        auto const old_size = size();
238
3.48M
        TRY(try_resize(old_size + length));
239
3.48M
        return Bytes { data() + old_size, length };
240
3.48M
    }
241
242
    /// Like get_bytes_for_writing, but crashes if allocation fails.
243
    Bytes must_get_bytes_for_writing(size_t length)
244
    {
245
        return MUST(get_bytes_for_writing(length));
246
    }
247
248
    void append(u8 byte)
249
456M
    {
250
456M
        MUST(try_append(byte));
251
456M
    }
Unexecuted instantiation: AK::Detail::ByteBuffer<32ul>::append(unsigned char)
AK::Detail::ByteBuffer<256ul>::append(unsigned char)
Line
Count
Source
249
456M
    {
250
456M
        MUST(try_append(byte));
251
456M
    }
252
253
    void append(ReadonlyBytes bytes)
254
33.3M
    {
255
33.3M
        MUST(try_append(bytes));
256
33.3M
    }
257
258
0
    void append(void const* data, size_t data_size) { append({ data, data_size }); }
259
260
    ErrorOr<void> try_append(u8 byte)
261
2.89G
    {
262
2.89G
        auto old_size = size();
263
2.89G
        auto new_size = old_size + 1;
264
2.89G
        VERIFY(new_size > old_size);
265
2.89G
        TRY(try_resize(new_size));
266
2.89G
        data()[old_size] = byte;
267
2.89G
        return {};
268
2.89G
    }
AK::Detail::ByteBuffer<32ul>::try_append(unsigned char)
Line
Count
Source
261
17.4M
    {
262
17.4M
        auto old_size = size();
263
17.4M
        auto new_size = old_size + 1;
264
17.4M
        VERIFY(new_size > old_size);
265
17.4M
        TRY(try_resize(new_size));
266
17.4M
        data()[old_size] = byte;
267
17.4M
        return {};
268
17.4M
    }
AK::Detail::ByteBuffer<256ul>::try_append(unsigned char)
Line
Count
Source
261
2.87G
    {
262
2.87G
        auto old_size = size();
263
2.87G
        auto new_size = old_size + 1;
264
2.87G
        VERIFY(new_size > old_size);
265
2.87G
        TRY(try_resize(new_size));
266
2.87G
        data()[old_size] = byte;
267
2.87G
        return {};
268
2.87G
    }
269
270
    ErrorOr<void> try_append(ReadonlyBytes bytes)
271
40.0M
    {
272
40.0M
        return try_append(bytes.data(), bytes.size());
273
40.0M
    }
274
275
    ErrorOr<void> try_append(void const* data, size_t data_size)
276
275M
    {
277
275M
        if (data_size == 0)
278
22.1M
            return {};
279
253M
        VERIFY(data != nullptr);
280
253M
        auto old_size = size();
281
253M
        TRY(try_resize(size() + data_size));
282
253M
        __builtin_memcpy(this->data() + old_size, data, data_size);
283
253M
        return {};
284
253M
    }
AK::Detail::ByteBuffer<32ul>::try_append(void const*, unsigned long)
Line
Count
Source
276
41.4M
    {
277
41.4M
        if (data_size == 0)
278
22.1M
            return {};
279
19.2M
        VERIFY(data != nullptr);
280
19.2M
        auto old_size = size();
281
19.2M
        TRY(try_resize(size() + data_size));
282
19.2M
        __builtin_memcpy(this->data() + old_size, data, data_size);
283
19.2M
        return {};
284
19.2M
    }
AK::Detail::ByteBuffer<256ul>::try_append(void const*, unsigned long)
Line
Count
Source
276
234M
    {
277
234M
        if (data_size == 0)
278
0
            return {};
279
234M
        VERIFY(data != nullptr);
280
234M
        auto old_size = size();
281
234M
        TRY(try_resize(size() + data_size));
282
234M
        __builtin_memcpy(this->data() + old_size, data, data_size);
283
234M
        return {};
284
234M
    }
285
286
    void operator+=(ByteBuffer const& other)
287
1.92k
    {
288
1.92k
        MUST(try_append(other.data(), other.size()));
289
1.92k
    }
290
291
    void overwrite(size_t offset, void const* data, size_t data_size)
292
46.9k
    {
293
        // make sure we're not told to write past the end
294
46.9k
        VERIFY(offset + data_size <= size());
295
46.9k
        __builtin_memmove(this->data() + offset, data, data_size);
296
46.9k
    }
297
298
    void zero_fill()
299
110k
    {
300
110k
        __builtin_memset(data(), 0, m_size);
301
110k
    }
302
303
276k
    operator Bytes() { return bytes(); }
304
488k
    operator ReadonlyBytes() const { return bytes(); }
305
306
6.45G
    ALWAYS_INLINE size_t capacity() const { return m_inline ? inline_capacity : m_outline_capacity; }
AK::Detail::ByteBuffer<32ul>::capacity() const
Line
Count
Source
306
40.7M
    ALWAYS_INLINE size_t capacity() const { return m_inline ? inline_capacity : m_outline_capacity; }
AK::Detail::ByteBuffer<256ul>::capacity() const
Line
Count
Source
306
6.41G
    ALWAYS_INLINE size_t capacity() const { return m_inline ? inline_capacity : m_outline_capacity; }
AK::Detail::ByteBuffer<0ul>::capacity() const
Line
Count
Source
306
338k
    ALWAYS_INLINE size_t capacity() const { return m_inline ? inline_capacity : m_outline_capacity; }
307
308
private:
309
    void move_from(ByteBuffer&& other)
310
46.7M
    {
311
46.7M
        m_size = other.m_size;
312
46.7M
        m_inline = other.m_inline;
313
46.7M
        if (!other.m_inline) {
314
11.8M
            m_outline_buffer = other.m_outline_buffer;
315
11.8M
            m_outline_capacity = other.m_outline_capacity;
316
34.9M
        } else {
317
34.9M
            VERIFY(other.m_size <= inline_capacity);
318
34.9M
            __builtin_memcpy(m_inline_buffer, other.m_inline_buffer, other.m_size);
319
34.9M
        }
320
46.7M
        other.m_size = 0;
321
46.7M
        other.m_inline = true;
322
46.7M
    }
AK::Detail::ByteBuffer<32ul>::move_from(AK::Detail::ByteBuffer<32ul>&&)
Line
Count
Source
310
35.4M
    {
311
35.4M
        m_size = other.m_size;
312
35.4M
        m_inline = other.m_inline;
313
35.4M
        if (!other.m_inline) {
314
536k
            m_outline_buffer = other.m_outline_buffer;
315
536k
            m_outline_capacity = other.m_outline_capacity;
316
34.9M
        } else {
317
34.9M
            VERIFY(other.m_size <= inline_capacity);
318
34.9M
            __builtin_memcpy(m_inline_buffer, other.m_inline_buffer, other.m_size);
319
34.9M
        }
320
35.4M
        other.m_size = 0;
321
35.4M
        other.m_inline = true;
322
35.4M
    }
AK::Detail::ByteBuffer<0ul>::move_from(AK::Detail::ByteBuffer<0ul>&&)
Line
Count
Source
310
11.3M
    {
311
11.3M
        m_size = other.m_size;
312
11.3M
        m_inline = other.m_inline;
313
11.3M
        if (!other.m_inline) {
314
11.3M
            m_outline_buffer = other.m_outline_buffer;
315
11.3M
            m_outline_capacity = other.m_outline_capacity;
316
11.3M
        } else {
317
0
            VERIFY(other.m_size <= inline_capacity);
318
0
            __builtin_memcpy(m_inline_buffer, other.m_inline_buffer, other.m_size);
319
0
        }
320
11.3M
        other.m_size = 0;
321
11.3M
        other.m_inline = true;
322
11.3M
    }
323
324
    NEVER_INLINE void shrink_into_inline_buffer(size_t size, bool may_discard_existing_data)
325
135k
    {
326
        // m_inline_buffer and m_outline_buffer are part of a union, so save the pointer
327
135k
        auto* outline_buffer = m_outline_buffer;
328
135k
        auto outline_capacity = m_outline_capacity;
329
135k
        if (!may_discard_existing_data)
330
3.44k
            __builtin_memcpy(m_inline_buffer, outline_buffer, size);
331
135k
        kfree_sized(outline_buffer, outline_capacity);
332
135k
        m_inline = true;
333
135k
    }
AK::Detail::ByteBuffer<32ul>::shrink_into_inline_buffer(unsigned long, bool)
Line
Count
Source
325
3.44k
    {
326
        // m_inline_buffer and m_outline_buffer are part of a union, so save the pointer
327
3.44k
        auto* outline_buffer = m_outline_buffer;
328
3.44k
        auto outline_capacity = m_outline_capacity;
329
3.44k
        if (!may_discard_existing_data)
330
3.44k
            __builtin_memcpy(m_inline_buffer, outline_buffer, size);
331
3.44k
        kfree_sized(outline_buffer, outline_capacity);
332
3.44k
        m_inline = true;
333
3.44k
    }
AK::Detail::ByteBuffer<256ul>::shrink_into_inline_buffer(unsigned long, bool)
Line
Count
Source
325
132k
    {
326
        // m_inline_buffer and m_outline_buffer are part of a union, so save the pointer
327
132k
        auto* outline_buffer = m_outline_buffer;
328
132k
        auto outline_capacity = m_outline_capacity;
329
132k
        if (!may_discard_existing_data)
330
0
            __builtin_memcpy(m_inline_buffer, outline_buffer, size);
331
132k
        kfree_sized(outline_buffer, outline_capacity);
332
132k
        m_inline = true;
333
132k
    }
Unexecuted instantiation: AK::Detail::ByteBuffer<0ul>::shrink_into_inline_buffer(unsigned long, bool)
334
335
    NEVER_INLINE ErrorOr<void> try_ensure_capacity_slowpath(size_t new_capacity)
336
7.36M
    {
337
        // When we are asked to raise the capacity by very small amounts,
338
        // the caller is perhaps appending very little data in many calls.
339
        // To avoid copying the entire ByteBuffer every single time,
340
        // we raise the capacity exponentially, by a factor of roughly 1.5.
341
        // This is most noticeable in Lagom, where kmalloc_good_size is just a no-op.
342
7.36M
        new_capacity = max(new_capacity, (capacity() * 3) / 2);
343
7.36M
        new_capacity = kmalloc_good_size(new_capacity);
344
7.36M
        auto* new_buffer = static_cast<u8*>(kmalloc(new_capacity));
345
7.36M
        if (!new_buffer)
346
0
            return Error::from_errno(ENOMEM);
347
348
7.36M
        if (m_inline) {
349
7.04M
            __builtin_memcpy(new_buffer, data(), m_size);
350
7.04M
        } else if (m_outline_buffer) {
351
327k
            __builtin_memcpy(new_buffer, m_outline_buffer, min(new_capacity, m_outline_capacity));
352
327k
            kfree_sized(m_outline_buffer, m_outline_capacity);
353
327k
        }
354
355
7.36M
        m_outline_buffer = new_buffer;
356
7.36M
        m_outline_capacity = new_capacity;
357
7.36M
        m_inline = false;
358
7.36M
        return {};
359
7.36M
    }
AK::Detail::ByteBuffer<32ul>::try_ensure_capacity_slowpath(unsigned long)
Line
Count
Source
336
249k
    {
337
        // When we are asked to raise the capacity by very small amounts,
338
        // the caller is perhaps appending very little data in many calls.
339
        // To avoid copying the entire ByteBuffer every single time,
340
        // we raise the capacity exponentially, by a factor of roughly 1.5.
341
        // This is most noticeable in Lagom, where kmalloc_good_size is just a no-op.
342
249k
        new_capacity = max(new_capacity, (capacity() * 3) / 2);
343
249k
        new_capacity = kmalloc_good_size(new_capacity);
344
249k
        auto* new_buffer = static_cast<u8*>(kmalloc(new_capacity));
345
249k
        if (!new_buffer)
346
0
            return Error::from_errno(ENOMEM);
347
348
249k
        if (m_inline) {
349
201k
            __builtin_memcpy(new_buffer, data(), m_size);
350
201k
        } else if (m_outline_buffer) {
351
47.0k
            __builtin_memcpy(new_buffer, m_outline_buffer, min(new_capacity, m_outline_capacity));
352
47.0k
            kfree_sized(m_outline_buffer, m_outline_capacity);
353
47.0k
        }
354
355
249k
        m_outline_buffer = new_buffer;
356
249k
        m_outline_capacity = new_capacity;
357
249k
        m_inline = false;
358
249k
        return {};
359
249k
    }
AK::Detail::ByteBuffer<256ul>::try_ensure_capacity_slowpath(unsigned long)
Line
Count
Source
336
6.95M
    {
337
        // When we are asked to raise the capacity by very small amounts,
338
        // the caller is perhaps appending very little data in many calls.
339
        // To avoid copying the entire ByteBuffer every single time,
340
        // we raise the capacity exponentially, by a factor of roughly 1.5.
341
        // This is most noticeable in Lagom, where kmalloc_good_size is just a no-op.
342
6.95M
        new_capacity = max(new_capacity, (capacity() * 3) / 2);
343
6.95M
        new_capacity = kmalloc_good_size(new_capacity);
344
6.95M
        auto* new_buffer = static_cast<u8*>(kmalloc(new_capacity));
345
6.95M
        if (!new_buffer)
346
0
            return Error::from_errno(ENOMEM);
347
348
6.95M
        if (m_inline) {
349
6.67M
            __builtin_memcpy(new_buffer, data(), m_size);
350
6.67M
        } else if (m_outline_buffer) {
351
279k
            __builtin_memcpy(new_buffer, m_outline_buffer, min(new_capacity, m_outline_capacity));
352
279k
            kfree_sized(m_outline_buffer, m_outline_capacity);
353
279k
        }
354
355
6.95M
        m_outline_buffer = new_buffer;
356
6.95M
        m_outline_capacity = new_capacity;
357
6.95M
        m_inline = false;
358
6.95M
        return {};
359
6.95M
    }
AK::Detail::ByteBuffer<0ul>::try_ensure_capacity_slowpath(unsigned long)
Line
Count
Source
336
169k
    {
337
        // When we are asked to raise the capacity by very small amounts,
338
        // the caller is perhaps appending very little data in many calls.
339
        // To avoid copying the entire ByteBuffer every single time,
340
        // we raise the capacity exponentially, by a factor of roughly 1.5.
341
        // This is most noticeable in Lagom, where kmalloc_good_size is just a no-op.
342
169k
        new_capacity = max(new_capacity, (capacity() * 3) / 2);
343
169k
        new_capacity = kmalloc_good_size(new_capacity);
344
169k
        auto* new_buffer = static_cast<u8*>(kmalloc(new_capacity));
345
169k
        if (!new_buffer)
346
0
            return Error::from_errno(ENOMEM);
347
348
169k
        if (m_inline) {
349
169k
            __builtin_memcpy(new_buffer, data(), m_size);
350
169k
        } else if (m_outline_buffer) {
351
0
            __builtin_memcpy(new_buffer, m_outline_buffer, min(new_capacity, m_outline_capacity));
352
0
            kfree_sized(m_outline_buffer, m_outline_capacity);
353
0
        }
354
355
169k
        m_outline_buffer = new_buffer;
356
169k
        m_outline_capacity = new_capacity;
357
169k
        m_inline = false;
358
169k
        return {};
359
169k
    }
360
361
    union {
362
        u8 m_inline_buffer[inline_capacity];
363
        struct {
364
            u8* m_outline_buffer;
365
            size_t m_outline_capacity;
366
        };
367
    };
368
    size_t m_size { 0 };
369
    bool m_inline { true };
370
};
371
372
}
373
374
template<>
375
struct Traits<ByteBuffer> : public DefaultTraits<ByteBuffer> {
376
    static unsigned hash(ByteBuffer const& byte_buffer)
377
0
    {
378
0
        return Traits<ReadonlyBytes>::hash(byte_buffer.span());
379
0
    }
380
    static bool equals(ByteBuffer const& byte_buffer, Bytes const& other)
381
0
    {
382
0
        return byte_buffer.bytes() == other;
383
0
    }
384
    static bool equals(ByteBuffer const& byte_buffer, ReadonlyBytes const& other)
385
0
    {
386
0
        return byte_buffer.bytes() == other;
387
0
    }
388
};
389
390
#ifdef AK_COMPILER_GCC
391
#    pragma GCC diagnostic pop
392
#endif
393
394
}