/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 | | } |