Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 : : * Author: Thun Lu <thun.lu@zohomail.cn>
4 : : * Repo: https://github.com/thun-res/vlink
5 : : * _ __ __ _ __
6 : : * | | / / / / (_) ____ / /__
7 : : * | | / / / / / / / __ \ / //_/
8 : : * | |/ / / /___ / / / / / / / ,<
9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 : : *
11 : : * Licensed under the Apache License, Version 2.0 (the "License");
12 : : * you may not use this file except in compliance with the License.
13 : : * You may obtain a copy of the License at
14 : : *
15 : : * http://www.apache.org/licenses/LICENSE-2.0
16 : : *
17 : : * Unless required by applicable law or agreed to in writing, software
18 : : * distributed under the License is distributed on an "AS IS" BASIS,
19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 : : * See the License for the specific language governing permissions and
21 : : * limitations under the License.
22 : : */
23 : :
24 : : #include "./base/bytes.h"
25 : :
26 : : #include <lzav/lzav.h>
27 : :
28 : : #include <array>
29 : : #include <charconv>
30 : : #include <limits>
31 : : #include <sstream>
32 : : #include <string>
33 : : #include <utility>
34 : : #include <vector>
35 : :
36 : : #include "./base/logger.h"
37 : : #include "./base/memory_pool.h"
38 : :
39 : : #define VLINK_BYTES_MEM_RESET 0
40 : :
41 : : namespace vlink {
42 : :
43 : : static constexpr uint32_t kCrc32Polynomial = 0xEDB88320U;
44 : :
45 : : static constexpr uint64_t kCrc64Polynomial = 0x42F0E1EBA9EA3693ULL;
46 : :
47 : : static constexpr const char kBase64Table[] =
48 : : "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
49 : : "abcdefghijklmnopqrstuvwxyz"
50 : : "0123456789+/";
51 : :
52 : : static constexpr const char* kHexTable[256] = {
53 : : "00 ", "01 ", "02 ", "03 ", "04 ", "05 ", "06 ", "07 ", "08 ", "09 ", "0A ", "0B ", "0C ", "0D ", "0E ", "0F ",
54 : : "10 ", "11 ", "12 ", "13 ", "14 ", "15 ", "16 ", "17 ", "18 ", "19 ", "1A ", "1B ", "1C ", "1D ", "1E ", "1F ",
55 : : "20 ", "21 ", "22 ", "23 ", "24 ", "25 ", "26 ", "27 ", "28 ", "29 ", "2A ", "2B ", "2C ", "2D ", "2E ", "2F ",
56 : : "30 ", "31 ", "32 ", "33 ", "34 ", "35 ", "36 ", "37 ", "38 ", "39 ", "3A ", "3B ", "3C ", "3D ", "3E ", "3F ",
57 : : "40 ", "41 ", "42 ", "43 ", "44 ", "45 ", "46 ", "47 ", "48 ", "49 ", "4A ", "4B ", "4C ", "4D ", "4E ", "4F ",
58 : : "50 ", "51 ", "52 ", "53 ", "54 ", "55 ", "56 ", "57 ", "58 ", "59 ", "5A ", "5B ", "5C ", "5D ", "5E ", "5F ",
59 : : "60 ", "61 ", "62 ", "63 ", "64 ", "65 ", "66 ", "67 ", "68 ", "69 ", "6A ", "6B ", "6C ", "6D ", "6E ", "6F ",
60 : : "70 ", "71 ", "72 ", "73 ", "74 ", "75 ", "76 ", "77 ", "78 ", "79 ", "7A ", "7B ", "7C ", "7D ", "7E ", "7F ",
61 : : "80 ", "81 ", "82 ", "83 ", "84 ", "85 ", "86 ", "87 ", "88 ", "89 ", "8A ", "8B ", "8C ", "8D ", "8E ", "8F ",
62 : : "90 ", "91 ", "92 ", "93 ", "94 ", "95 ", "96 ", "97 ", "98 ", "99 ", "9A ", "9B ", "9C ", "9D ", "9E ", "9F ",
63 : : "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ", "A6 ", "A7 ", "A8 ", "A9 ", "AA ", "AB ", "AC ", "AD ", "AE ", "AF ",
64 : : "B0 ", "B1 ", "B2 ", "B3 ", "B4 ", "B5 ", "B6 ", "B7 ", "B8 ", "B9 ", "BA ", "BB ", "BC ", "BD ", "BE ", "BF ",
65 : : "C0 ", "C1 ", "C2 ", "C3 ", "C4 ", "C5 ", "C6 ", "C7 ", "C8 ", "C9 ", "CA ", "CB ", "CC ", "CD ", "CE ", "CF ",
66 : : "D0 ", "D1 ", "D2 ", "D3 ", "D4 ", "D5 ", "D6 ", "D7 ", "D8 ", "D9 ", "DA ", "DB ", "DC ", "DD ", "DE ", "DF ",
67 : : "E0 ", "E1 ", "E2 ", "E3 ", "E4 ", "E5 ", "E6 ", "E7 ", "E8 ", "E9 ", "EA ", "EB ", "EC ", "ED ", "EE ", "EF ",
68 : : "F0 ", "F1 ", "F2 ", "F3 ", "F4 ", "F5 ", "F6 ", "F7 ", "F8 ", "F9 ", "FA ", "FB ", "FC ", "FD ", "FE ", "FF "};
69 : :
70 : : static constexpr uint8_t kCompressHeaderMagic[4] = {
71 : : 0x17,
72 : : 0x49,
73 : : 0xB2,
74 : : 0x6F,
75 : : };
76 : :
77 : : static constexpr uint8_t kCompressFooterMagic[4] = {
78 : : 0xA7,
79 : : 0x05,
80 : : 0xED,
81 : : 0x71,
82 : : };
83 : :
84 : : static constexpr size_t kCompressCacheSize = 1024UL * 1024UL;
85 : :
86 : : static constexpr size_t kMaxCompressionDataSize = 256UL * 1024UL * 1024UL;
87 : :
88 : 86 : static constexpr auto check_magic(const uint8_t* data, const uint8_t* magic, size_t len) noexcept {
89 [ + + ]: 354 : for (size_t i = 0; i < len; ++i) {
90 [ + + ]: 287 : if (data[i] != magic[i]) {
91 : 19 : return false;
92 : : }
93 : : }
94 : :
95 : 67 : return true;
96 : : }
97 : :
98 : 24 : static auto& bytes_compress_cache() noexcept {
99 [ + + ]: 24 : thread_local std::vector<uint8_t> compress_cache(kCompressCacheSize);
100 : :
101 : 24 : return compress_cache;
102 : : }
103 : :
104 : : // Bytes
105 : 1617 : uint8_t* Bytes::bytes_malloc(size_t size) noexcept {
106 : 1617 : return static_cast<uint8_t*>(MemoryPool::global_instance().allocate(size));
107 : : }
108 : :
109 : 1617 : void Bytes::bytes_free(uint8_t* ptr, size_t size) noexcept { MemoryPool::global_instance().deallocate(ptr, size); }
110 : :
111 : 2276 : void Bytes::init_memory_pool() noexcept { (void)MemoryPool::global_instance(); }
112 : :
113 : 1 : void Bytes::release_memory_pool() noexcept { MemoryPool::global_instance().clear(); }
114 : :
115 : 10854 : Bytes Bytes::create(size_t size, uint8_t offset) noexcept {
116 : : #if defined(__arm__) || defined(__x86__) || defined(__i386__)
117 : : #ifndef __ANDROID__
118 : : #warning "Bytes No support for 32-bit architecture."
119 : : #endif
120 : : #else
121 : : static_assert(sizeof(Bytes) == 128, "Sizeof must be 128 bytes.");
122 : : #endif
123 : :
124 : 10854 : return Bytes(kCreate, nullptr, size, offset, false);
125 : : }
126 : :
127 : 535 : Bytes Bytes::shallow_copy(uint8_t* data, size_t size) noexcept {
128 [ + + + + : 535 : if VUNLIKELY (!data && size > 0) {
+ + ]
129 : 2 : VLOG_E("Bytes: Cannot shallow copy null data with a non-zero size.");
130 : 1 : return {};
131 : : }
132 : :
133 [ + + ]: 534 : return Bytes(kShallowCopy, size == 0 ? nullptr : data, size, 0, false);
134 : : }
135 : :
136 : 1052 : Bytes Bytes::shallow_copy(const uint8_t* data, size_t size) noexcept {
137 [ + + + + : 1052 : if VUNLIKELY (!data && size > 0) {
+ + ]
138 : 2 : VLOG_E("Bytes: Cannot shallow copy null data with a non-zero size.");
139 : 1 : return {};
140 : : }
141 : :
142 [ + + ]: 1051 : return Bytes(kShallowCopy, size == 0 ? nullptr : const_cast<uint8_t*>(data), size, 0, false);
143 : : }
144 : :
145 : 3 : Bytes Bytes::shallow_copy_ptr(void* data) noexcept {
146 : 3 : return Bytes(kShallowCopy, static_cast<uint8_t*>(data), 0, 0, false);
147 : : }
148 : :
149 : 19 : Bytes Bytes::deep_copy(uint8_t* data, size_t size, uint8_t offset) noexcept {
150 [ + + + - : 19 : if VUNLIKELY (!data && size > 0) {
+ + ]
151 : 2 : VLOG_E("Bytes: Cannot deep copy null data with a non-zero size.");
152 : 1 : return {};
153 : : }
154 : :
155 [ + - ]: 18 : return Bytes(kDeepCopy, size == 0 ? nullptr : data, size, offset, false);
156 : : }
157 : :
158 : 1217 : Bytes Bytes::deep_copy(const uint8_t* data, size_t size, uint8_t offset) noexcept {
159 [ + + + + : 1217 : if VUNLIKELY (!data && size > 0) {
+ + ]
160 : 2 : VLOG_E("Bytes: Cannot deep copy null data with a non-zero size.");
161 : 1 : return {};
162 : : }
163 : :
164 [ + + ]: 1216 : return Bytes(kDeepCopy, size == 0 ? nullptr : const_cast<uint8_t*>(data), size, offset, false);
165 : : }
166 : :
167 : 83 : Bytes Bytes::loan_internal(uint8_t* data, size_t size) noexcept {
168 [ + + + - : 83 : if VUNLIKELY (!data && size > 0) {
+ + ]
169 : 2 : VLOG_E("Bytes: Cannot loan null data with a non-zero size.");
170 : 1 : return {};
171 : : }
172 : :
173 [ + + ]: 82 : return Bytes(kShallowCopy, size == 0 ? nullptr : data, size, 0, true);
174 : : }
175 : :
176 : 2 : Bytes Bytes::loan_internal(const uint8_t* data, size_t size) noexcept {
177 [ + + + - : 2 : if VUNLIKELY (!data && size > 0) {
+ + ]
178 : 2 : VLOG_E("Bytes: Cannot loan null data with a non-zero size.");
179 : 1 : return {};
180 : : }
181 : :
182 [ + - ]: 1 : return Bytes(kShallowCopy, size == 0 ? nullptr : const_cast<uint8_t*>(data), size, 0, true);
183 : : }
184 : :
185 : 469 : Bytes Bytes::from_string(const std::string& str, uint8_t offset) noexcept {
186 [ + + ]: 469 : if (str.empty()) {
187 : 25 : return Bytes(kDeepCopy, nullptr, 0, offset, false);
188 : : }
189 : :
190 : 444 : return Bytes(kDeepCopy, reinterpret_cast<uint8_t*>(const_cast<char*>(str.data())), str.size(), offset, false);
191 : : }
192 : :
193 : 17 : Bytes Bytes::from_user_input(const std::string& str, bool* ok) noexcept {
194 [ + + ]: 17 : if (str.empty()) {
195 [ + + ]: 2 : if (ok) {
196 : 1 : *ok = false;
197 : : }
198 : :
199 : 2 : return Bytes();
200 : : }
201 : :
202 : 15 : std::vector<uint8_t> vec;
203 : 15 : vec.reserve((str.size() + 1) / 2);
204 : :
205 [ + + ]: 15 : thread_local std::istringstream ss;
206 : 15 : ss.clear();
207 : 15 : ss.str(str);
208 : :
209 : 15 : std::string byte_str;
210 : :
211 : 31 : auto parse_byte = [&vec, ok](std::string_view token) -> bool {
212 [ - + ]: 14 : if (token.empty()) {
213 : : if (ok) { // LCOV_EXCL_LINE GCOVR_EXCL_LINE
214 : : *ok = false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
215 : : }
216 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
217 : : }
218 : :
219 : 14 : uint32_t parsed_value = 0;
220 [ + - ]: 14 : auto [p, error] = std::from_chars(token.data(), token.data() + token.size(), parsed_value, 16);
221 : :
222 [ + + + + : 14 : if VUNLIKELY (error != std::errc() || p != token.data() + token.size() || parsed_value > 0xFF) {
+ + - + +
+ ]
223 [ + + ]: 4 : if (ok) {
224 : 3 : *ok = false;
225 : : }
226 : 4 : return false;
227 : : }
228 : :
229 [ + - ]: 10 : vec.emplace_back(static_cast<uint8_t>(parsed_value));
230 : 10 : return true;
231 : 15 : };
232 : :
233 [ + + ]: 23 : while (ss >> std::skipws >> byte_str) {
234 : 19 : std::string_view token(byte_str);
235 : :
236 [ + - + + : 19 : if (token.size() >= 2 && token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) {
+ + + + +
+ ]
237 : 6 : token.remove_prefix(2);
238 : : }
239 : :
240 [ + + + + : 19 : if VUNLIKELY (token.empty() || (token.size() > 2 && (token.size() % 2) != 0)) {
+ + + + +
+ ]
241 [ + + ]: 7 : if (ok) {
242 : 4 : *ok = false;
243 : : }
244 : :
245 : 11 : return Bytes();
246 : : }
247 : :
248 [ + + ]: 12 : if (token.size() <= 2) {
249 [ + + ]: 10 : if VUNLIKELY (!parse_byte(token)) {
250 : 3 : return Bytes();
251 : : }
252 : 7 : continue;
253 : : }
254 : :
255 [ + + ]: 5 : for (size_t index = 0; index < token.size(); index += 2) {
256 [ + + ]: 4 : if VUNLIKELY (!parse_byte(token.substr(index, 2))) {
257 : 1 : return Bytes();
258 : : }
259 : : }
260 : : }
261 : :
262 [ + + ]: 4 : if (ok) {
263 : 3 : *ok = true;
264 : : }
265 : :
266 : 4 : return Bytes(vec);
267 : 15 : }
268 : :
269 : 6 : std::string Bytes::convert_to_hex_str(const uint8_t* value, size_t size) noexcept {
270 : 6 : std::string str;
271 : :
272 [ + + + + ]: 6 : if (!value || size == 0) {
273 : 3 : str = "{}";
274 : 3 : return str;
275 : : }
276 : :
277 : : static constexpr uint8_t kCount = 3;
278 : :
279 : 3 : str.resize(size * kCount);
280 : :
281 [ + + ]: 12 : for (size_t i = 0; i < size; ++i) {
282 : 9 : std::memcpy(&str[(i * kCount)], kHexTable[value[i]], kCount);
283 : : }
284 : :
285 : 3 : str.pop_back();
286 : :
287 : 3 : return str;
288 : : }
289 : :
290 : 3 : Bytes Bytes::reverse_order(const Bytes& target) noexcept {
291 [ + + ]: 3 : if (target.empty()) {
292 : 1 : return Bytes();
293 : : }
294 : :
295 : 2 : size_t size = target.size();
296 : :
297 : 2 : Bytes result = Bytes::create(size);
298 : :
299 [ - + ]: 2 : if VUNLIKELY (result.empty()) {
300 : : return result; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
301 : : }
302 : :
303 [ + + ]: 7 : for (size_t i = 0; i < size; ++i) {
304 : 5 : result[i] = target[size - 1 - i];
305 : : }
306 : :
307 : 2 : return result;
308 : 2 : }
309 : :
310 : 6 : std::string Bytes::encode_to_base64(const Bytes& target) noexcept {
311 [ + + ]: 6 : if (target.empty()) {
312 : 1 : return std::string();
313 : : }
314 : :
315 : 5 : std::string encoded;
316 : :
317 : 5 : uint32_t val = 0;
318 : 5 : int valb = -6;
319 : :
320 [ + + ]: 63 : for (auto c : target) {
321 : 58 : val = (val << 8) + c;
322 : 58 : valb += 8;
323 : :
324 [ + + ]: 134 : while (valb >= 0) {
325 : 76 : encoded.push_back(kBase64Table[(val >> valb) & 0x3F]);
326 : 76 : valb -= 6;
327 : : }
328 : : }
329 : :
330 [ + + ]: 5 : if (valb > -6) {
331 : 3 : encoded.push_back(kBase64Table[((val << 8) >> (valb + 8)) & 0x3F]);
332 : : }
333 : :
334 : 5 : size_t padding = (4 - (encoded.size() % 4)) % 4;
335 : 5 : encoded.append(padding, '=');
336 : :
337 : 5 : return encoded;
338 : 5 : }
339 : :
340 : 10 : Bytes Bytes::decode_from_base64(const std::string& target) noexcept {
341 [ + + ]: 10 : if (target.size() % 4 != 0) {
342 : 1 : return Bytes();
343 : : }
344 : :
345 : 9 : size_t padding = 0;
346 : 9 : size_t first_padding = target.find('=');
347 : :
348 [ + + ]: 9 : if (first_padding != std::string::npos) {
349 : 5 : padding = target.size() - first_padding;
350 : :
351 [ + + ]: 5 : if VUNLIKELY (padding > 2) {
352 : 1 : return Bytes();
353 : : }
354 : :
355 [ + + ]: 10 : for (size_t i = first_padding; i < target.size(); ++i) {
356 [ + + ]: 7 : if VUNLIKELY (target[i] != '=') {
357 : 1 : return Bytes();
358 : : }
359 : : }
360 : : }
361 : :
362 : 7 : std::vector<uint8_t> buffer;
363 : 7 : buffer.reserve((target.size() * 3) / 4);
364 : :
365 : 1 : static const auto kTable = [] {
366 : 1 : std::array<int, 256> tbl{};
367 [ + - ]: 1 : tbl.fill(-1);
368 : :
369 [ + + ]: 65 : for (size_t i = 0; i < sizeof(kBase64Table) - 1; ++i) {
370 : 64 : tbl[static_cast<unsigned char>(kBase64Table[i])] = i;
371 : : }
372 : :
373 : 1 : return tbl;
374 [ + + + - ]: 7 : }();
375 : :
376 : 7 : uint32_t val = 0;
377 : 7 : int valb = -8;
378 : :
379 [ + + ]: 7 : const size_t decode_size = first_padding == std::string::npos ? target.size() : first_padding;
380 : :
381 [ + + ]: 86 : for (size_t i = 0; i < decode_size; ++i) {
382 : 80 : auto c = target[i];
383 : :
384 : 80 : int idx = kTable[static_cast<unsigned char>(c)];
385 : :
386 [ + + ]: 80 : if VUNLIKELY (idx == -1) {
387 : 1 : return Bytes();
388 : : }
389 : :
390 : 79 : val = (val << 6) + idx;
391 : 79 : valb += 6;
392 : :
393 [ + + ]: 79 : if (valb >= 0) {
394 : 58 : buffer.emplace_back(static_cast<uint8_t>((val >> valb) & 0xFF));
395 : 58 : valb -= 8;
396 : : }
397 : : }
398 : :
399 : 6 : return Bytes(buffer);
400 : 7 : }
401 : :
402 : 9 : uint32_t Bytes::get_crc_32(const Bytes& target) noexcept {
403 : 9 : uint32_t crc = 0xFFFFFFFFU;
404 : :
405 : : static constexpr auto kCrc32Table = []() {
406 : : std::array<uint32_t, 256> table{};
407 : :
408 : : for (uint32_t i = 0; i < 256; ++i) {
409 : : uint32_t crc = i;
410 : :
411 : : for (uint32_t bit = 0; bit < 8; ++bit) {
412 : : crc = (crc & 1U) ? (kCrc32Polynomial ^ (crc >> 1U)) : (crc >> 1U);
413 : : }
414 : :
415 : : table[i] = crc;
416 : : }
417 : :
418 : : return table;
419 : : }();
420 : :
421 [ + + ]: 77 : for (auto u : target) {
422 : 68 : crc = kCrc32Table[(crc ^ u) & 0xFFU] ^ (crc >> 8U);
423 : : }
424 : :
425 : 9 : return crc ^ 0xFFFFFFFFU;
426 : : }
427 : :
428 : 6 : uint64_t Bytes::get_crc_64(const Bytes& target) noexcept {
429 : 6 : uint64_t crc = 0x0000000000000000ULL;
430 : :
431 : : static constexpr auto kCrc64Table = []() {
432 : : std::array<uint64_t, 256> table{};
433 : :
434 : : for (uint64_t i = 0; i < 256; ++i) {
435 : : uint64_t crc = i << 56U;
436 : :
437 : : for (uint64_t bit = 0; bit < 8; ++bit) {
438 : : crc = (crc & 0x8000000000000000ULL) ? (kCrc64Polynomial ^ (crc << 1U)) : (crc << 1U);
439 : : }
440 : :
441 : : table[i] = crc;
442 : : }
443 : :
444 : : return table;
445 : : }();
446 : :
447 [ + + ]: 27 : for (auto u : target) {
448 : 21 : crc = kCrc64Table[((crc >> 56U) ^ u) & 0xFFU] ^ (crc << 8U);
449 : : }
450 : :
451 : 6 : return crc ^ 0x0000000000000000ULL;
452 : : }
453 : :
454 : 38342 : Bytes::Bytes() noexcept = default;
455 : :
456 : 3989 : Bytes::Bytes(const Bytes& target) noexcept {
457 [ - + ]: 3989 : if VUNLIKELY (this == &target) {
458 : : return; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
459 : : }
460 : :
461 [ + + + - ]: 3989 : if (target.offset_ > 0 && target.data_) {
462 : 1 : process_type(kCreate, nullptr, target.size_, target.offset_, false);
463 : :
464 [ + - ]: 1 : if VLIKELY (data_) {
465 : 1 : std::memcpy(data_, target.data_, target.size_ + target.offset_);
466 : : }
467 : : } else {
468 : 3988 : process_type(kDeepCopy, target.data_, target.size_, target.offset_, false);
469 : : }
470 : : }
471 : :
472 : 3193 : Bytes::Bytes(Bytes&& target) noexcept {
473 [ - + ]: 3193 : if VUNLIKELY (this == &target) {
474 : : return; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
475 : : }
476 : :
477 : 3193 : process_type(kMove, target.data_, target.size_, target.offset_, target.is_loaned_, &target);
478 : : }
479 : :
480 : 158 : Bytes::Bytes(const std::initializer_list<uint8_t>& list) noexcept {
481 : 158 : process_type(kCreate, nullptr, list.size(), 0, false);
482 : :
483 [ + - ]: 158 : if VLIKELY (data_) {
484 : 158 : size_t index = 0;
485 : :
486 [ + + ]: 489 : for (const auto& value : list) {
487 : 331 : data_[index] = value;
488 : 331 : ++index;
489 : : }
490 : : }
491 : 158 : }
492 : :
493 : 17 : Bytes::Bytes(const std::vector<uint8_t>& data) noexcept {
494 [ + + ]: 17 : process_type(kDeepCopy, data.empty() ? nullptr : const_cast<uint8_t*>(data.data()), data.size(), 0, false);
495 : 17 : }
496 : :
497 : 59928 : Bytes::~Bytes() noexcept {
498 [ + + + + : 59928 : if (data_ && data_ != stack_data_ && is_owner_ && capacity_ + offset_ > kStackSize) {
+ + + - ]
499 : 1120 : bytes_free(data_, capacity_ + offset_);
500 : : }
501 : 59928 : }
502 : :
503 : 360 : Bytes& Bytes::operator=(const Bytes& target) noexcept {
504 [ + + ]: 360 : if VUNLIKELY (this == &target) {
505 : 79 : return *this;
506 : : }
507 : :
508 [ + + + - ]: 281 : if (target.offset_ > 0 && target.data_) {
509 : 17 : Bytes tmp;
510 : 17 : tmp.process_type(kCreate, nullptr, target.size_, target.offset_, false);
511 : :
512 [ + - ]: 17 : if VLIKELY (tmp.data_) {
513 : 17 : std::memcpy(tmp.data_, target.data_, target.size_ + target.offset_);
514 : : }
515 : :
516 : 17 : *this = std::move(tmp);
517 : 17 : } else {
518 : 264 : process_type(kDeepCopy, target.data_, target.size_, target.offset_, false);
519 : : }
520 : :
521 : 281 : return *this;
522 : : }
523 : :
524 : 24376 : Bytes& Bytes::operator=(Bytes&& target) noexcept {
525 [ + + ]: 24376 : if VUNLIKELY (this == &target) {
526 : 1 : return *this;
527 : : }
528 : :
529 : 24375 : process_type(kMove, target.data_, target.size_, target.offset_, target.is_loaned_, &target);
530 : :
531 : 24369 : return *this;
532 : : }
533 : :
534 : 1 : Bytes& Bytes::operator=(const std::vector<uint8_t>& data) noexcept {
535 [ - + ]: 1 : process_type(kDeepCopy, data.empty() ? nullptr : const_cast<uint8_t*>(data.data()), data.size(), 0, false);
536 : :
537 : 1 : return *this;
538 : : }
539 : :
540 : 42 : bool Bytes::operator==(const Bytes& target) const noexcept {
541 [ + + ]: 42 : if VUNLIKELY (this == &target) {
542 : 1 : return true;
543 : : }
544 : :
545 [ + + ]: 41 : if (size_ != target.size_) {
546 : 6 : return false;
547 : : }
548 : :
549 [ + + ]: 35 : const uint8_t* this_data = data_ ? (data_ + offset_) : nullptr;
550 [ + + ]: 35 : const uint8_t* target_data = target.data_ ? (target.data_ + target.offset_) : nullptr;
551 : :
552 [ + + ]: 35 : if (this_data == target_data) {
553 : 4 : return true;
554 : : }
555 : :
556 [ + - - + ]: 31 : if (!this_data || !target_data) {
557 : : return size_ == 0; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
558 : : }
559 : :
560 : 31 : return std::memcmp(this_data, target_data, size_) == 0;
561 : : }
562 : :
563 : 8 : bool Bytes::operator!=(const Bytes& target) const noexcept { return !(*this == target); }
564 : :
565 : 9 : bool Bytes::operator==(const std::vector<uint8_t>& data) const noexcept {
566 [ + + ]: 9 : if (size_ != data.size()) {
567 : 2 : return false;
568 : : }
569 : :
570 [ + + ]: 7 : const uint8_t* this_data = data_ ? (data_ + offset_) : nullptr;
571 : :
572 [ + + ]: 7 : if (!this_data) {
573 : 1 : return data.empty();
574 : : }
575 : :
576 [ + + ]: 6 : if (this_data == data.data()) {
577 : 2 : return true;
578 : : }
579 : :
580 : 4 : return std::memcmp(this_data, data.data(), size_) == 0;
581 : : }
582 : :
583 : 3 : bool Bytes::operator!=(const std::vector<uint8_t>& data) const noexcept { return !(*this == data); }
584 : :
585 : 3 : std::vector<uint8_t> Bytes::to_raw_data() const noexcept {
586 [ + + + + : 3 : if VUNLIKELY (empty() || is_ptr() || !data_) {
+ + - + +
+ ]
587 : 2 : return std::vector<uint8_t>();
588 : : }
589 : :
590 : 1 : return std::vector<uint8_t>(data_ + offset_, data_ + offset_ + size_);
591 : : }
592 : :
593 : 307 : std::string Bytes::to_string() const noexcept {
594 [ + + + + : 307 : if VUNLIKELY (empty() || is_ptr() || !data_) {
+ + - + +
+ ]
595 : 3 : return std::string();
596 : : }
597 : :
598 : 304 : return std::string(reinterpret_cast<const char*>(data_ + offset_), size_);
599 : : }
600 : :
601 : 4 : std::string_view Bytes::to_string_view() const noexcept {
602 [ + + + + : 4 : if VUNLIKELY (empty() || is_ptr() || !data_) {
+ + - + +
+ ]
603 : 2 : return std::string_view();
604 : : }
605 : :
606 : 2 : return std::string_view(reinterpret_cast<const char*>(data_ + offset_), size_);
607 : : }
608 : :
609 : 56 : bool Bytes::is_compress_data(const uint8_t* data, size_t size) noexcept {
610 [ + + ]: 56 : if VUNLIKELY (!data) {
611 : 1 : return false;
612 : : }
613 : :
614 [ + + ]: 55 : if (size < 12 + 1) {
615 : 3 : return false;
616 : : }
617 : :
618 [ + + ]: 52 : if (!check_magic(data, kCompressHeaderMagic, sizeof(kCompressHeaderMagic))) {
619 : 18 : return false;
620 : : }
621 : :
622 [ + + ]: 34 : if (!check_magic(data + size - sizeof(kCompressFooterMagic), kCompressFooterMagic, sizeof(kCompressFooterMagic))) {
623 : 1 : return false;
624 : : }
625 : :
626 : 33 : return true;
627 : : }
628 : :
629 : 27 : Bytes Bytes::compress_data(const uint8_t* data, size_t size, bool high_ratio) noexcept {
630 : 27 : Bytes target_bytes;
631 : :
632 [ + + + + : 27 : if VUNLIKELY (!data || size == 0 || size > kMaxCompressionDataSize) {
+ + + + +
+ ]
633 : 3 : return target_bytes;
634 : : }
635 : :
636 : 24 : const auto source_size = static_cast<int>(size);
637 : : const int max_compressed_size =
638 [ + + ]: 48 : high_ratio ? lzav::lzav_compress_bound_hi(source_size) : lzav::lzav_compress_bound(source_size);
639 : :
640 [ - + ]: 24 : if VUNLIKELY (max_compressed_size <= 0) {
641 : 0 : return target_bytes;
642 : : }
643 : :
644 : 48 : target_bytes = Bytes::create(sizeof(kCompressHeaderMagic) + 4 + static_cast<size_t>(max_compressed_size) +
645 : 24 : sizeof(kCompressFooterMagic));
646 : :
647 [ - + ]: 24 : if VUNLIKELY (target_bytes.empty()) {
648 : : return target_bytes; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
649 : : }
650 : :
651 : 24 : std::memcpy(target_bytes.data(), kCompressHeaderMagic, sizeof(kCompressHeaderMagic));
652 : :
653 : 24 : target_bytes[4] = static_cast<uint8_t>((size >> 24) & 0xFF);
654 : 24 : target_bytes[5] = static_cast<uint8_t>((size >> 16) & 0xFF);
655 : 24 : target_bytes[6] = static_cast<uint8_t>((size >> 8) & 0xFF);
656 : 24 : target_bytes[7] = static_cast<uint8_t>((size) & 0xFF); // NOLINT(readability-redundant-parentheses)
657 : :
658 : 24 : int result = 0;
659 : :
660 [ + + ]: 24 : if (high_ratio) {
661 : 12 : result = lzav::lzav_compress_hi(data, target_bytes.data() + sizeof(kCompressHeaderMagic) + 4, source_size,
662 : : max_compressed_size);
663 : : } else {
664 [ + + ]: 12 : if (size < lzav::LZAV_MR5_THR) {
665 : 11 : result = lzav::lzav_compress_mref5(data, target_bytes.data() + sizeof(kCompressHeaderMagic) + 4, source_size,
666 : 11 : max_compressed_size, bytes_compress_cache().data(),
667 : 11 : static_cast<int>(bytes_compress_cache().size()));
668 : : } else {
669 : 1 : result = lzav::lzav_compress_mref6(data, target_bytes.data() + sizeof(kCompressHeaderMagic) + 4, source_size,
670 : 1 : max_compressed_size, bytes_compress_cache().data(),
671 : 1 : static_cast<int>(bytes_compress_cache().size()));
672 : : }
673 : : }
674 : :
675 [ - + ]: 24 : if VUNLIKELY (result <= 0) {
676 : : target_bytes.clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
677 : : return target_bytes; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
678 : : }
679 : :
680 : 24 : size_t final_size = sizeof(kCompressHeaderMagic) + 4 + static_cast<size_t>(result) + sizeof(kCompressFooterMagic);
681 : :
682 [ - + ]: 24 : if VUNLIKELY (!target_bytes.resize(final_size)) {
683 : : target_bytes.clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
684 : : return target_bytes; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
685 : : }
686 : :
687 : 24 : std::memcpy(&target_bytes[sizeof(kCompressHeaderMagic) + 4 + result], kCompressFooterMagic,
688 : : sizeof(kCompressFooterMagic));
689 : :
690 : 24 : return target_bytes;
691 : : }
692 : :
693 : 21 : Bytes Bytes::uncompress_data(const uint8_t* data, size_t size, bool check_valid) noexcept {
694 : 21 : Bytes target_bytes;
695 : :
696 : : static constexpr size_t kMinCompressedSize = sizeof(kCompressHeaderMagic) + 4 + sizeof(kCompressFooterMagic);
697 : :
698 [ + + + + : 21 : if VUNLIKELY (!data || size < kMinCompressedSize) {
+ + ]
699 : 2 : return target_bytes;
700 : : }
701 : :
702 [ + + ]: 19 : if (check_valid) {
703 [ + + ]: 6 : if VUNLIKELY (!is_compress_data(data, size)) {
704 : 1 : return target_bytes;
705 : : }
706 : : }
707 : :
708 : 18 : uint32_t target_size = (static_cast<uint32_t>(data[4]) << 24) | (static_cast<uint32_t>(data[5]) << 16) |
709 : 18 : (static_cast<uint32_t>(data[6]) << 8) | (static_cast<uint32_t>(data[7]));
710 : :
711 [ + - + + : 18 : if VUNLIKELY (target_size == 0 || target_size > kMaxCompressionDataSize) {
+ + ]
712 : 2 : CLOG_E("Bytes: Invalid uncompressed size: %u.", target_size);
713 : :
714 : 1 : return target_bytes;
715 : : }
716 : :
717 : 17 : const size_t compressed_size = size - sizeof(kCompressHeaderMagic) - 4 - sizeof(kCompressFooterMagic);
718 : :
719 [ + + ]: 17 : if VUNLIKELY (compressed_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
720 : 1 : return target_bytes;
721 : : }
722 : :
723 : 16 : target_bytes = Bytes::create(target_size);
724 : :
725 [ - + ]: 16 : if VUNLIKELY (target_bytes.empty()) {
726 : : return target_bytes; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
727 : : }
728 : :
729 [ - + ]: 16 : int result = lzav::lzav_decompress(data + sizeof(kCompressHeaderMagic) + 4, target_bytes.data(),
730 : : static_cast<int>(compressed_size), static_cast<int>(target_size));
731 : :
732 [ + + ]: 16 : if VUNLIKELY (result != static_cast<int>(target_size)) {
733 : 1 : target_bytes.clear();
734 : : }
735 : :
736 : 16 : return target_bytes;
737 : : }
738 : :
739 : 2769 : void Bytes::clear() noexcept {
740 [ + + + + : 2769 : if (data_ && data_ != stack_data_ && is_owner_ && capacity_ + offset_ > kStackSize) {
+ + + - ]
741 : 1 : bytes_free(data_, capacity_ + offset_);
742 : : }
743 : :
744 : : #if VLINK_BYTES_MEM_RESET
745 : : std::memset(stack_data_, 0, kStackSize);
746 : : #endif
747 : :
748 : 2769 : data_ = nullptr;
749 : 2769 : size_ = 0;
750 : 2769 : capacity_ = 0;
751 : 2769 : offset_ = 0;
752 : 2769 : is_owner_ = false;
753 : 2769 : is_loaned_ = false;
754 : 2769 : }
755 : :
756 : 3 : bool Bytes::shrink_to(size_t size) noexcept {
757 [ + + ]: 3 : if VUNLIKELY (!is_owner_) {
758 : 2 : VLOG_E("Bytes: Cannot shrink_to on non-owned Bytes.");
759 : 1 : return false;
760 : : }
761 : :
762 [ + + ]: 2 : if VUNLIKELY (size > size_) {
763 : 2 : VLOG_E("Bytes: Cannot shrink_to a size larger than current size.");
764 : 1 : return false;
765 : : }
766 : :
767 [ - + ]: 1 : if VUNLIKELY (size > capacity_) {
768 : : VLOG_E("Bytes: Cannot shrink_to a size larger than capacity."); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
769 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
770 : : }
771 : :
772 : 1 : size_ = size;
773 : :
774 : 1 : return true;
775 : : }
776 : :
777 : 6 : bool Bytes::reserve(size_t new_capacity) noexcept {
778 [ + + ]: 6 : if VUNLIKELY (!is_owner_) {
779 : 2 : VLOG_E("Bytes: Cannot reserve on non-owned Bytes.");
780 : 1 : return false;
781 : : }
782 : :
783 [ + + ]: 5 : if (new_capacity <= capacity_) {
784 : 1 : return true;
785 : : }
786 : :
787 [ + + ]: 4 : if VUNLIKELY (new_capacity > std::numeric_limits<size_t>::max() - offset_) {
788 : 2 : VLOG_E("Bytes: Cannot reserve due to size overflow.");
789 : 1 : return false;
790 : : }
791 : :
792 : 3 : size_t total_new_size = new_capacity + offset_;
793 : 3 : size_t total_old_size = capacity_ + offset_;
794 : :
795 : 3 : uint8_t* new_data = nullptr;
796 : :
797 [ + + ]: 3 : if (total_new_size > kStackSize) {
798 : 2 : new_data = bytes_malloc(total_new_size);
799 : :
800 [ - + ]: 2 : if VUNLIKELY (!new_data) {
801 : : VLOG_E("Bytes: Failed to reserve memory."); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
802 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
803 : : }
804 : :
805 : : #if VLINK_BYTES_MEM_RESET
806 : : std::memset(new_data, 0, total_new_size);
807 : : #endif
808 : : } else {
809 : 1 : new_data = stack_data_;
810 : : }
811 : :
812 [ + + + - : 3 : if (new_data != data_ && data_ && (size_ + offset_) > 0) {
+ - ]
813 : 2 : std::memcpy(new_data, data_, size_ + offset_);
814 : : }
815 : :
816 [ + - + + : 3 : if (data_ && data_ != stack_data_ && total_old_size > kStackSize) {
+ - ]
817 : 1 : bytes_free(data_, total_old_size);
818 : : }
819 : :
820 : 3 : data_ = new_data;
821 : 3 : capacity_ = new_capacity;
822 : :
823 : 3 : return true;
824 : : }
825 : :
826 : 75 : bool Bytes::resize(size_t size) noexcept {
827 [ + + ]: 75 : if VUNLIKELY (!is_owner_) {
828 : 2 : VLOG_E("Bytes: Cannot resize on non-owned Bytes.");
829 : 1 : return false;
830 : : }
831 : :
832 [ + + ]: 74 : if (size <= capacity_) {
833 : : #if VLINK_BYTES_MEM_RESET
834 : :
835 : : if (size > size_ && data_) {
836 : : size_t available_space = capacity_;
837 : : size_t new_end_offset = size;
838 : :
839 : : if (new_end_offset <= available_space) {
840 : : std::memset(data_ + offset_ + size_, 0, size - size_);
841 : : } else {
842 : : VLOG_E("Bytes: Resize would exceed allocated memory.");
843 : : return false;
844 : : }
845 : : }
846 : : #endif
847 : 73 : size_ = size;
848 : :
849 : 73 : return true;
850 : : }
851 : :
852 [ - + ]: 1 : if VUNLIKELY (!reserve(size)) {
853 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
854 : : }
855 : :
856 : 1 : size_ = size;
857 : :
858 : 1 : return true;
859 : : }
860 : :
861 : 271 : Bytes& Bytes::shallow_copy(const Bytes& bytes) noexcept {
862 : 271 : process_type(kShallowCopy, bytes.data_, bytes.size_, bytes.offset_, false);
863 : :
864 : 271 : return *this;
865 : : }
866 : :
867 : 6 : Bytes& Bytes::deep_copy(const Bytes& bytes) noexcept {
868 [ + + ]: 6 : if VUNLIKELY (this == &bytes) {
869 : 1 : return deep_copy_self();
870 : : }
871 : :
872 : 5 : return operator=(bytes);
873 : : }
874 : :
875 : 5 : Bytes& Bytes::deep_copy_self() noexcept {
876 [ + + ]: 5 : if VUNLIKELY (is_owner_) {
877 : 2 : return *this;
878 : : }
879 : :
880 [ + + - + : 3 : if VUNLIKELY (!data_ || size_ == 0) {
+ + ]
881 : 1 : clear();
882 : 1 : return *this;
883 : : }
884 : :
885 [ + + ]: 2 : if (offset_ > 0) {
886 : 1 : uint8_t* old_data = data_;
887 : 1 : size_t total_size = size_ + offset_;
888 : :
889 : 1 : process_type(kCreate, nullptr, size_, offset_, false);
890 : :
891 [ + - ]: 1 : if VLIKELY (data_) {
892 : 1 : std::memcpy(data_, old_data, total_size);
893 : : }
894 : : } else {
895 : 1 : process_type(kDeepCopy, data_ + offset_, size_, 0, false);
896 : : }
897 : :
898 : 2 : return *this;
899 : : }
900 : :
901 : 14228 : Bytes::Bytes(Type type, uint8_t* data, size_t size, uint8_t offset, bool loaned) noexcept {
902 : 14228 : process_type(type, data, size, offset, loaned);
903 : 14221 : }
904 : :
905 : 46510 : void Bytes::process_type(Type type, uint8_t* data, size_t size, uint8_t offset, bool loaned, Bytes* tmp) noexcept {
906 [ + + + + : 46510 : switch (type) {
+ ]
907 : 11031 : case kCreate: {
908 : : // VLOG_W("kCreate");
909 : :
910 [ + + ]: 11031 : if VUNLIKELY (size > std::numeric_limits<size_t>::max() - offset) {
911 : 3 : VLOG_E("Bytes: Cannot create due to size overflow.");
912 : 1 : clear();
913 : 1 : return;
914 : : }
915 : :
916 : 11029 : size_t total_size = size + offset;
917 : 11029 : uint8_t* new_data = nullptr;
918 : :
919 [ + + ]: 11029 : if (total_size > kStackSize) {
920 : 917 : new_data = bytes_malloc(total_size);
921 : :
922 [ # + ]: 917 : if VUNLIKELY (!new_data) {
923 : : VLOG_E("Bytes: Failed to allocate memory."); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
924 : : clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
925 : : return; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
926 : : }
927 : : #if VLINK_BYTES_MEM_RESET
928 : : std::memset(new_data, 0, total_size);
929 : : #endif
930 [ + + ]: 10112 : } else if (total_size != 0) {
931 : 10110 : new_data = stack_data_;
932 : : }
933 : :
934 [ - + - - ]: 11030 : if (is_owner_ && data_) {
935 : : if (data_ != stack_data_ && capacity_ + offset_ > kStackSize) { // LCOV_EXCL_LINE GCOVR_EXCL_LINE
936 : : bytes_free(data_, capacity_ + offset_); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
937 : : data_ = nullptr; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
938 : : }
939 : : }
940 : :
941 : 11030 : data_ = new_data;
942 : :
943 : 11030 : size_ = size;
944 : 11030 : capacity_ = size;
945 : 11030 : offset_ = offset;
946 : 11030 : is_owner_ = true;
947 : 11030 : is_loaned_ = false;
948 : :
949 : 11030 : break;
950 : : }
951 : :
952 : 1942 : case kShallowCopy: {
953 : : // VLOG_W("kShallowCopy");
954 : :
955 [ + + + - ]: 1942 : if (is_owner_ && data_) {
956 : 17 : const auto owner_address = reinterpret_cast<uintptr_t>(data_);
957 : 17 : const auto source_address = reinterpret_cast<uintptr_t>(data);
958 : :
959 [ + + + - : 17 : if VUNLIKELY (source_address >= owner_address && source_address - owner_address < capacity_ + offset_) {
+ + ]
960 : 4 : VLOG_E("Bytes: Cannot shallow copy an alias into owned storage.");
961 : 2 : return;
962 : : }
963 : :
964 : : if (data_ != stack_data_ && capacity_ + offset_ > kStackSize) { // LCOV_EXCL_LINE GCOVR_EXCL_LINE
965 : : bytes_free(data_, capacity_ + offset_); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
966 : : }
967 : : }
968 : :
969 : 1940 : data_ = data;
970 : 1940 : size_ = size;
971 : 1940 : capacity_ = 0;
972 : 1940 : offset_ = offset;
973 : 1940 : is_owner_ = false;
974 : 1940 : is_loaned_ = loaned;
975 : :
976 : 1940 : break;
977 : : }
978 : :
979 : 5967 : case kDeepCopy: {
980 : : // VLOG_W("kDeepCopy");
981 : :
982 [ # + ]: 5967 : if VUNLIKELY (size > std::numeric_limits<size_t>::max() - offset) {
983 : 0 : VLOG_E("Bytes: Cannot deep copy due to size overflow.");
984 : : clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
985 : : return; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
986 : : }
987 : :
988 : 5975 : size_t total_size = size + offset;
989 : :
990 : 5975 : uint8_t* deferred_free_buffer = nullptr;
991 : 5975 : size_t deferred_free_size = 0;
992 : :
993 [ + + + - ]: 5975 : if (is_owner_ && data_) {
994 [ - + - - : 23 : if VUNLIKELY (data_ == data && size_ == size && offset_ == offset) {
- + - - -
+ ]
995 : 0 : return;
996 : : }
997 : :
998 : 23 : bool can_reuse =
999 [ + + + - : 23 : (data_ != stack_data_ && capacity_ + offset_ > kStackSize && capacity_ + offset_ == total_size);
+ + ]
1000 : :
1001 [ + + + - ]: 23 : if (can_reuse && data) {
1002 : 4 : uint8_t* dst_start = data_;
1003 : 4 : uint8_t* dst_end = data_ + capacity_ + offset_;
1004 : 4 : const uint8_t* src_start = data;
1005 : 4 : const uint8_t* src_end = data + size;
1006 : :
1007 [ + + - + ]: 4 : if (src_start < dst_end && dst_start < src_end) {
1008 : : can_reuse = false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
1009 : : }
1010 : : }
1011 : :
1012 [ + + + - : 23 : if (data_ != stack_data_ && capacity_ + offset_ > kStackSize && !can_reuse) {
+ + ]
1013 : 1 : deferred_free_buffer = data_;
1014 : 1 : deferred_free_size = capacity_ + offset_;
1015 : 1 : data_ = nullptr;
1016 : 1 : capacity_ = 0;
1017 : 1 : offset_ = 0;
1018 : : }
1019 : : }
1020 : :
1021 [ + + ]: 5975 : if VLIKELY (total_size != 0) {
1022 [ + + ]: 3798 : if (total_size > kStackSize) {
1023 [ + + + + : 228 : if (!is_owner_ || capacity_ + offset_ != total_size || data_ == stack_data_) {
+ + ]
1024 : 225 : data_ = bytes_malloc(total_size);
1025 : :
1026 [ - + ]: 224 : if VUNLIKELY (!data_) {
1027 : : // LCOV_EXCL_START GCOVR_EXCL_START
1028 : : VLOG_E("Bytes: Failed to allocate memory.");
1029 : :
1030 : : if (deferred_free_buffer) {
1031 : : bytes_free(deferred_free_buffer, deferred_free_size);
1032 : : }
1033 : :
1034 : : clear();
1035 : :
1036 : : return;
1037 : : // LCOV_EXCL_STOP GCOVR_EXCL_STOP
1038 : : }
1039 : :
1040 : : #if VLINK_BYTES_MEM_RESET
1041 : : std::memset(data_, 0, total_size);
1042 : : #endif
1043 : : }
1044 : : } else {
1045 : 3570 : data_ = stack_data_;
1046 : : }
1047 : :
1048 [ + + + # : 3797 : if VLIKELY (data && data_) {
+ + ]
1049 [ + - ]: 3791 : if VLIKELY (size > 0) {
1050 : 3791 : std::memmove(data_ + offset, data, size);
1051 : : }
1052 : : }
1053 : :
1054 : 3797 : size_ = size;
1055 : 3797 : capacity_ = size;
1056 : 3797 : offset_ = offset;
1057 : 3797 : is_owner_ = true;
1058 : 3797 : is_loaned_ = false;
1059 : : } else {
1060 : 2177 : data_ = data;
1061 : 2177 : size_ = 0;
1062 : 2177 : capacity_ = 0;
1063 : 2177 : offset_ = 0;
1064 : 2177 : is_owner_ = false;
1065 : 2177 : is_loaned_ = false;
1066 : : }
1067 : :
1068 [ + + ]: 5974 : if (deferred_free_buffer) {
1069 : 1 : bytes_free(deferred_free_buffer, deferred_free_size);
1070 : : }
1071 : :
1072 : 5967 : break;
1073 : : }
1074 : :
1075 : 27566 : case kMove: {
1076 : : // VLOG_W("kMove");
1077 : :
1078 [ - + ]: 27566 : if VUNLIKELY (!tmp) {
1079 : : VLOG_E("Bytes: Reference tmp is empty."); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
1080 : : break; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
1081 : : }
1082 : :
1083 [ + + + - ]: 27566 : if (is_owner_ && data_) {
1084 : 111 : const auto owner_address = reinterpret_cast<uintptr_t>(data_);
1085 : 111 : const auto source_address = reinterpret_cast<uintptr_t>(data);
1086 : :
1087 [ + + + + : 111 : if VUNLIKELY (source_address >= owner_address && source_address - owner_address < capacity_ + offset_) {
+ + ]
1088 : : VLOG_E("Bytes: Cannot move an alias into owned storage."); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
1089 : : return; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
1090 : : }
1091 : :
1092 [ + + + - ]: 110 : if (data_ != stack_data_ && capacity_ + offset_ > kStackSize) {
1093 : 20 : bytes_free(data_, capacity_ + offset_);
1094 : : }
1095 : : }
1096 : :
1097 [ + + + + : 27562 : if (tmp->capacity_ + tmp->offset_ != 0 && tmp->capacity_ + tmp->offset_ <= kStackSize && tmp->is_owner_) {
+ - ]
1098 : 14677 : size_t copy_size = tmp->size_ + tmp->offset_;
1099 : :
1100 [ + + + - : 14677 : if VLIKELY (copy_size > 0 && copy_size <= kStackSize) {
+ + ]
1101 : 14676 : std::memcpy(stack_data_, tmp->stack_data_, copy_size);
1102 : : }
1103 : :
1104 : 14677 : data_ = stack_data_;
1105 : 14677 : } else {
1106 : 12885 : data_ = tmp->data_;
1107 : : }
1108 : :
1109 : 27562 : size_ = tmp->size_;
1110 : 27562 : capacity_ = tmp->capacity_;
1111 : 27562 : offset_ = tmp->offset_;
1112 : 27562 : is_owner_ = tmp->is_owner_;
1113 : 27562 : is_loaned_ = tmp->is_loaned_;
1114 : :
1115 : 27562 : tmp->data_ = nullptr;
1116 : 27562 : tmp->size_ = 0;
1117 : 27562 : tmp->capacity_ = 0;
1118 : 27562 : tmp->offset_ = 0;
1119 : 27562 : tmp->is_owner_ = false;
1120 : 27562 : tmp->is_loaned_ = false;
1121 : :
1122 : : #if VLINK_BYTES_MEM_RESET
1123 : : std::memset(tmp->stack_data_, 0, kStackSize);
1124 : : #endif
1125 : :
1126 : 27562 : break;
1127 : : }
1128 : :
1129 : 4 : default:
1130 : 4 : break;
1131 : : }
1132 : : }
1133 : :
1134 : 4 : std::ostream& operator<<(std::ostream& ostream, const Bytes& target) noexcept {
1135 [ + + ]: 4 : if (target.empty()) {
1136 : 1 : ostream << "{}";
1137 : 1 : return ostream;
1138 : : }
1139 : :
1140 [ + + ]: 3 : if (target.is_ptr()) {
1141 : 1 : ostream << "(ptr)" << static_cast<void*>(target.data_);
1142 : 1 : return ostream;
1143 : : }
1144 : :
1145 [ + + ]: 2 : if (target.offset_ > 0) {
1146 : 1 : ostream << "(offset=" << +target.offset_ << ") ";
1147 : : }
1148 : :
1149 : 2 : ostream << Bytes::convert_to_hex_str(target.data_ + target.offset_, target.size());
1150 : :
1151 : 2 : return ostream;
1152 : : }
1153 : :
1154 : : } // namespace vlink
|