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 "./zerocopy/raw_data.h"
25 : :
26 : : namespace vlink {
27 : :
28 : : namespace zerocopy {
29 : :
30 : : // RawData
31 : 66 : RawData::RawData() noexcept {
32 : : #if defined(__arm__) || defined(__x86__) || defined(__i386__)
33 : : #ifndef __ANDROID__
34 : : #warning "[RawData] No support for 32-bit architecture."
35 : : #endif
36 : : #else
37 : : static_assert(sizeof(RawData) == 64, "Sizeof must be 64 bytes.");
38 : : #endif
39 : 66 : }
40 : :
41 : 68 : RawData::~RawData() noexcept {
42 [ + + + - : 68 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
43 : 41 : Bytes::bytes_free(data_, size_);
44 : : }
45 : 68 : }
46 : :
47 : 1 : RawData::RawData(const RawData& target) noexcept { deep_copy(target); }
48 : :
49 : 1 : RawData::RawData(RawData&& target) noexcept { move_copy(target); }
50 : :
51 : 1 : RawData& RawData::operator=(const RawData& target) noexcept {
52 [ - + ]: 1 : if VUNLIKELY (this == &target) {
53 : 0 : return *this;
54 : : }
55 : :
56 : 1 : deep_copy(target);
57 : :
58 : 1 : return *this;
59 : : }
60 : :
61 : 1 : RawData& RawData::operator=(RawData&& target) noexcept {
62 [ - + ]: 1 : if VUNLIKELY (this == &target) {
63 : 0 : return *this;
64 : : }
65 : :
66 : 1 : move_copy(target);
67 : :
68 : 1 : return *this;
69 : : }
70 : :
71 : 12 : bool RawData::operator<<(const Bytes& bytes) noexcept {
72 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
73 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
74 : : // static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
75 : :
76 [ + + ]: 12 : if VUNLIKELY (bytes.empty()) {
77 : 1 : return false;
78 : : }
79 : :
80 [ + + ]: 11 : if VUNLIKELY (!check_valid(bytes)) {
81 : 2 : return false;
82 : : }
83 : :
84 : 9 : uint32_t wire_version = 0;
85 : 9 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
86 : :
87 [ - + ]: 9 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
88 : 0 : return false;
89 : : }
90 : :
91 [ + + + - : 9 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
92 : 1 : Bytes::bytes_free(data_, size_);
93 : : }
94 : :
95 : : #if defined(__GNUC__) && !defined(__clang__)
96 : : #pragma GCC diagnostic push
97 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
98 : : #if __GNUC__ >= 11
99 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
100 : : #endif
101 : : #endif
102 : :
103 : 9 : auto* target_ptr = reinterpret_cast<uint8_t*>(this);
104 : :
105 : 9 : std::memcpy(target_ptr, bytes.data() + kMagicNumberBeginSize + kVersionSize, sizeof(RawData));
106 : :
107 : : #if defined(__GNUC__) && !defined(__clang__)
108 : : #pragma GCC diagnostic pop
109 : : #endif
110 : :
111 : 9 : data_ = const_cast<uint8_t*>(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(RawData));
112 : 9 : is_owner_ = false;
113 : :
114 [ + + ]: 9 : if VUNLIKELY (bytes.size() != get_serialized_size()) {
115 : 1 : clear();
116 : 1 : return false;
117 : : }
118 : :
119 : 8 : return true;
120 : : }
121 : :
122 : 13 : bool RawData::operator>>(Bytes& bytes) const noexcept {
123 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
124 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
125 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
126 : :
127 [ + + - + : 13 : if (bytes.empty() || bytes.size() != get_serialized_size()) {
+ + ]
128 : 11 : bytes = Bytes::create(get_serialized_size());
129 : :
130 [ - + ]: 11 : if VUNLIKELY (bytes.empty()) {
131 : 0 : return false;
132 : : }
133 : : }
134 : :
135 : 13 : std::memcpy(bytes.data(), &kMagicNumberBegin, kMagicNumberBeginSize);
136 : :
137 : 13 : std::memcpy(bytes.data() + kMagicNumberBeginSize, &kWireVersion, kVersionSize);
138 : :
139 : : // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
140 : 13 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize, this, sizeof(RawData));
141 : :
142 : 13 : const auto data_offset = reinterpret_cast<const uint8_t*>(&data_) - reinterpret_cast<const uint8_t*>(this);
143 : 13 : const size_t data_pointer_size = sizeof(data_);
144 : 13 : std::memset(bytes.data() + kMagicNumberBeginSize + kVersionSize + data_offset, 0, data_pointer_size);
145 : :
146 [ + + + - : 13 : if VLIKELY (data_ != nullptr && size_ != 0) {
+ + ]
147 : 12 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(RawData), data_, size_);
148 : : }
149 : :
150 : 13 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(RawData) + size_, &kMagicNumberEnd,
151 : : kMagicNumberEndSize);
152 : :
153 : 13 : return true;
154 : : }
155 : :
156 : 18 : bool RawData::check_valid(const Bytes& bytes) noexcept {
157 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
158 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
159 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
160 : :
161 [ + + ]: 18 : if VUNLIKELY (bytes.size() < kMagicNumberBeginSize + kVersionSize + sizeof(RawData) + kMagicNumberEndSize) {
162 : 2 : return false;
163 : : }
164 : :
165 : 16 : uint32_t check_magic = 0;
166 : :
167 : 16 : std::memcpy(&check_magic, bytes.begin(), kMagicNumberBeginSize);
168 : :
169 [ + + ]: 16 : if VUNLIKELY (check_magic != kMagicNumberBegin) {
170 : 1 : return false;
171 : : }
172 : :
173 : 15 : uint32_t wire_version = 0;
174 : 15 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
175 : :
176 [ + + ]: 15 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
177 : 2 : return false;
178 : : }
179 : :
180 : 13 : std::memcpy(&check_magic, bytes.end() - kMagicNumberEndSize, kMagicNumberEndSize);
181 : :
182 [ + + ]: 13 : if VUNLIKELY (check_magic != kMagicNumberEnd) {
183 : 1 : return false;
184 : : }
185 : :
186 : 12 : return true;
187 : : }
188 : :
189 : 27 : size_t RawData::get_serialized_size() const noexcept {
190 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
191 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
192 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
193 : :
194 : 27 : return kMagicNumberBeginSize + kVersionSize + sizeof(RawData) + size_ + kMagicNumberEndSize;
195 : : }
196 : :
197 [ + + + - ]: 23 : bool RawData::is_valid() const noexcept { return data_ != nullptr && size_ != 0; }
198 : :
199 : 13 : bool RawData::shallow_copy(const RawData& target) noexcept {
200 [ + + ]: 13 : if VUNLIKELY (this == &target) {
201 : 2 : return false;
202 : : }
203 : :
204 [ + + + - : 11 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
205 : 1 : const auto current = reinterpret_cast<uintptr_t>(data_);
206 : 1 : const auto source = reinterpret_cast<uintptr_t>(target.data_);
207 : :
208 [ + - + - : 1 : if VUNLIKELY (source >= current && source - current < size_) {
+ - ]
209 : 1 : return false;
210 : : }
211 : :
212 : 0 : Bytes::bytes_free(data_, size_);
213 : : }
214 : :
215 : 10 : header = target.header;
216 : :
217 : 10 : is_owner_ = false;
218 : 10 : reserved_buf_ = target.reserved_buf_;
219 : 10 : data_ = target.data_;
220 : 10 : size_ = target.size_;
221 : :
222 : 10 : return true;
223 : : }
224 : :
225 : 9 : bool RawData::deep_copy(const RawData& target) noexcept {
226 [ + + + - : 9 : if VLIKELY (data_ && is_owner_ && target.data_ && size_ != 0 && size_ == target.size_) {
+ + + - +
+ + - + +
+ - + + ]
227 : 3 : const auto current = reinterpret_cast<uintptr_t>(data_);
228 : 3 : const auto source = reinterpret_cast<uintptr_t>(target.data_);
229 : :
230 [ + + + - : 3 : if VUNLIKELY (source >= current && source - current < size_) {
+ + ]
231 : 2 : return false;
232 : : }
233 : :
234 : 1 : header = target.header;
235 : 1 : reserved_buf_ = target.reserved_buf_;
236 : :
237 : 1 : std::memcpy(data_, target.data_, size_);
238 : :
239 : 1 : return true;
240 : : }
241 : :
242 [ - + ]: 6 : if VUNLIKELY (!shallow_copy(target)) {
243 : 0 : return false;
244 : : }
245 : :
246 [ + - + - ]: 6 : if (data_ && size_ != 0) {
247 : 6 : auto* target_data = data_;
248 : 6 : data_ = Bytes::bytes_malloc(size_);
249 : :
250 [ - + ]: 6 : if VUNLIKELY (!data_) {
251 : 0 : size_ = 0;
252 : 0 : return false;
253 : : }
254 : :
255 : 6 : std::memcpy(data_, target_data, size_);
256 : 6 : is_owner_ = true;
257 : : }
258 : :
259 : 6 : return true;
260 : : }
261 : :
262 : 4 : bool RawData::move_copy(RawData& target) noexcept {
263 [ + + ]: 4 : if VUNLIKELY (!shallow_copy(target)) {
264 : 1 : return false;
265 : : }
266 : :
267 : 3 : is_owner_ = target.is_owner_;
268 : :
269 : 3 : target.is_owner_ = false;
270 : 3 : target.reserved_buf_ = 0;
271 : 3 : target.data_ = nullptr;
272 : 3 : target.size_ = 0;
273 : :
274 : : #if defined(__GNUC__) && !defined(__clang__)
275 : : #pragma GCC diagnostic push
276 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
277 : : #if __GNUC__ >= 11
278 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
279 : : #endif
280 : : #endif
281 : :
282 : 3 : std::memset(&target.header, 0, sizeof(header));
283 : :
284 : : #if defined(__GNUC__) && !defined(__clang__)
285 : : #pragma GCC diagnostic pop
286 : : #endif
287 : :
288 : 3 : return true;
289 : : }
290 : :
291 : 42 : bool RawData::create(size_t _size) noexcept {
292 [ + + ]: 42 : if VUNLIKELY (_size == 0) {
293 : 1 : return false;
294 : : }
295 : :
296 [ + + + - : 41 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
297 : 2 : Bytes::bytes_free(data_, size_);
298 : : }
299 : :
300 : 41 : data_ = Bytes::bytes_malloc(_size);
301 : :
302 [ - + ]: 41 : if VUNLIKELY (!data_) {
303 : 0 : size_ = 0;
304 : 0 : is_owner_ = false;
305 : 0 : return false;
306 : : }
307 : :
308 : 41 : size_ = _size;
309 : 41 : is_owner_ = true;
310 : :
311 : 41 : return true;
312 : : }
313 : :
314 : 4 : void RawData::clear() noexcept {
315 [ + + + - : 4 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
316 : 3 : Bytes::bytes_free(data_, size_);
317 : : }
318 : :
319 : 4 : is_owner_ = false;
320 : 4 : reserved_buf_ = 0;
321 : 4 : data_ = nullptr;
322 : 4 : size_ = 0;
323 : :
324 : : #if defined(__GNUC__) && !defined(__clang__)
325 : : #pragma GCC diagnostic push
326 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
327 : : #if __GNUC__ >= 11
328 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
329 : : #endif
330 : : #endif
331 : :
332 : 4 : std::memset(&header, 0, sizeof(header));
333 : :
334 : : #if defined(__GNUC__) && !defined(__clang__)
335 : : #pragma GCC diagnostic pop
336 : : #endif
337 : 4 : }
338 : :
339 : 7 : bool RawData::shallow_copy(uint8_t* data, size_t size) noexcept {
340 [ + + + + : 7 : if VUNLIKELY (!data || size == 0) {
+ + ]
341 : 2 : return false;
342 : : }
343 : :
344 [ + + ]: 5 : if VUNLIKELY (data_ == data) {
345 : 1 : return false;
346 : : }
347 : :
348 [ + + + - : 4 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
349 : 1 : const auto current = reinterpret_cast<uintptr_t>(data_);
350 : 1 : const auto source = reinterpret_cast<uintptr_t>(data);
351 : :
352 [ + - + - : 1 : if VUNLIKELY (source >= current && source - current < size_) {
+ - ]
353 : 1 : return false;
354 : : }
355 : :
356 : 0 : Bytes::bytes_free(data_, size_);
357 : : }
358 : :
359 : 3 : is_owner_ = false;
360 : :
361 : 3 : data_ = data;
362 : 3 : size_ = size;
363 : :
364 : 3 : return true;
365 : : }
366 : :
367 : 10 : bool RawData::deep_copy(uint8_t* data, size_t size) noexcept {
368 [ + + + + : 10 : if VUNLIKELY (!data || size == 0) {
+ + ]
369 : 4 : return false;
370 : : }
371 : :
372 [ + + ]: 6 : if (is_owner_) {
373 [ - + ]: 4 : if VUNLIKELY (!data_) {
374 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
375 : : }
376 : :
377 : 4 : const auto current = reinterpret_cast<uintptr_t>(data_);
378 : 4 : const auto source = reinterpret_cast<uintptr_t>(data);
379 : :
380 [ + + + + : 4 : if VUNLIKELY (source >= current && source - current < size_) {
+ + ]
381 : 2 : return false;
382 : : }
383 : :
384 [ + + - + : 2 : if VUNLIKELY (size_ != size && !create(size)) {
- + ]
385 : 0 : return false;
386 : : }
387 [ - + ]: 2 : } else if VUNLIKELY (!create(size)) {
388 : 0 : return false;
389 : : }
390 : :
391 : 4 : std::memcpy(data_, data, size);
392 : :
393 : 4 : return true;
394 : : }
395 : :
396 : 4 : bool RawData::fill_data(uint8_t* data, size_t size) noexcept { return deep_copy(data, size); }
397 : :
398 : 17 : uint16_t& RawData::get_reserved() noexcept { return reserved_buf_; }
399 : :
400 : 59 : const uint8_t* RawData::data() const noexcept { return data_; }
401 : :
402 : 33 : size_t RawData::size() const noexcept { return size_; }
403 : :
404 : 24 : bool RawData::is_owner() const noexcept { return is_owner_; }
405 : :
406 : : } // namespace zerocopy
407 : :
408 : : } // namespace vlink
|