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 : 61 : 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 : 61 : }
40 : :
41 : 63 : RawData::~RawData() noexcept {
42 [ + + + - : 63 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
43 : 39 : Bytes::bytes_free(data_, size_);
44 : : }
45 : 63 : }
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 : 10 : 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 [ + + ]: 10 : if VUNLIKELY (bytes.empty()) {
77 : 1 : return false;
78 : : }
79 : :
80 [ + + ]: 9 : if VUNLIKELY (!check_valid(bytes)) {
81 : 2 : return false;
82 : : }
83 : :
84 : 7 : uint32_t wire_version = 0;
85 : 7 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
86 : :
87 [ - + ]: 7 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
88 : 0 : return false;
89 : : }
90 : :
91 [ + + + - : 7 : 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 : 7 : auto* target_ptr = reinterpret_cast<uint8_t*>(this);
104 : :
105 : 7 : 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 : 7 : data_ = const_cast<uint8_t*>(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(RawData));
112 : 7 : is_owner_ = false;
113 : :
114 [ + + ]: 7 : if VUNLIKELY (bytes.size() != get_serialized_size()) {
115 : 1 : clear();
116 : 1 : return false;
117 : : }
118 : :
119 : 6 : return true;
120 : : }
121 : :
122 : 11 : 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 [ + + - + : 11 : if (bytes.empty() || bytes.size() != get_serialized_size()) {
+ + ]
128 : 9 : bytes = Bytes::create(get_serialized_size());
129 : : }
130 : :
131 : 11 : std::memcpy(bytes.data(), &kMagicNumberBegin, kMagicNumberBeginSize);
132 : :
133 : 11 : std::memcpy(bytes.data() + kMagicNumberBeginSize, &kWireVersion, kVersionSize);
134 : :
135 : : // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
136 : 11 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize, this, sizeof(RawData));
137 : :
138 [ + + + - : 11 : if VLIKELY (data_ != nullptr && size_ != 0) {
+ + ]
139 : 10 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(RawData), data_, size_);
140 : : }
141 : :
142 : 11 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(RawData) + size_, &kMagicNumberEnd,
143 : : kMagicNumberEndSize);
144 : :
145 : 11 : return true;
146 : : }
147 : :
148 : 16 : bool RawData::check_valid(const Bytes& bytes) noexcept {
149 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
150 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
151 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
152 : :
153 [ + + ]: 16 : if VUNLIKELY (bytes.size() < kMagicNumberBeginSize + kVersionSize + sizeof(RawData) + kMagicNumberEndSize) {
154 : 2 : return false;
155 : : }
156 : :
157 : 14 : uint32_t check_magic = 0;
158 : :
159 : 14 : std::memcpy(&check_magic, bytes.begin(), kMagicNumberBeginSize);
160 : :
161 [ + + ]: 14 : if VUNLIKELY (check_magic != kMagicNumberBegin) {
162 : 1 : return false;
163 : : }
164 : :
165 : 13 : uint32_t wire_version = 0;
166 : 13 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
167 : :
168 [ + + ]: 13 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
169 : 2 : return false;
170 : : }
171 : :
172 : 11 : std::memcpy(&check_magic, bytes.end() - kMagicNumberEndSize, kMagicNumberEndSize);
173 : :
174 [ + + ]: 11 : if VUNLIKELY (check_magic != kMagicNumberEnd) {
175 : 1 : return false;
176 : : }
177 : :
178 : 10 : return true;
179 : : }
180 : :
181 : 23 : size_t RawData::get_serialized_size() const noexcept {
182 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
183 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
184 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
185 : :
186 : 23 : return kMagicNumberBeginSize + kVersionSize + sizeof(RawData) + size_ + kMagicNumberEndSize;
187 : : }
188 : :
189 [ + + + - ]: 23 : bool RawData::is_valid() const noexcept { return data_ != nullptr && size_ != 0; }
190 : :
191 : 12 : bool RawData::shallow_copy(const RawData& target) noexcept {
192 [ + + ]: 12 : if VUNLIKELY (this == &target) {
193 : 2 : return false;
194 : : }
195 : :
196 [ - + - - : 10 : if (is_owner_ && data_ && size_ != 0) {
- - ]
197 : 0 : Bytes::bytes_free(data_, size_);
198 : : }
199 : :
200 : 10 : header = target.header;
201 : :
202 : 10 : is_owner_ = false;
203 : 10 : reserved_buf_ = target.reserved_buf_;
204 : 10 : data_ = target.data_;
205 : 10 : size_ = target.size_;
206 : :
207 : 10 : return true;
208 : : }
209 : :
210 : 8 : bool RawData::deep_copy(const RawData& target) noexcept {
211 [ + + + - : 8 : if VLIKELY (data_ && is_owner_ && target.data_ && size_ != 0 && size_ == target.size_) {
+ + + - +
+ + - + +
+ - + + ]
212 [ + + ]: 2 : if VUNLIKELY (this == &target) {
213 : 1 : return false;
214 : : }
215 : :
216 : 1 : header = target.header;
217 : 1 : reserved_buf_ = target.reserved_buf_;
218 : :
219 : 1 : std::memcpy(data_, target.data_, size_);
220 : :
221 : 1 : return true;
222 : : }
223 : :
224 [ - + ]: 6 : if VUNLIKELY (!shallow_copy(target)) {
225 : 0 : return false;
226 : : }
227 : :
228 [ + - + - ]: 6 : if (data_ && size_ != 0) {
229 : 6 : data_ = Bytes::bytes_malloc(size_);
230 : :
231 : 6 : std::memcpy(data_, target.data_, size_);
232 : :
233 : 6 : is_owner_ = true;
234 : : }
235 : :
236 : 6 : return true;
237 : : }
238 : :
239 : 4 : bool RawData::move_copy(RawData& target) noexcept {
240 [ + + ]: 4 : if VUNLIKELY (!shallow_copy(target)) {
241 : 1 : return false;
242 : : }
243 : :
244 : 3 : is_owner_ = target.is_owner_;
245 : :
246 : 3 : target.is_owner_ = false;
247 : 3 : target.reserved_buf_ = 0;
248 : 3 : target.data_ = nullptr;
249 : 3 : target.size_ = 0;
250 : :
251 : : #if defined(__GNUC__) && !defined(__clang__)
252 : : #pragma GCC diagnostic push
253 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
254 : : #if __GNUC__ >= 11
255 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
256 : : #endif
257 : : #endif
258 : :
259 : 3 : std::memset(&target.header, 0, sizeof(header));
260 : :
261 : : #if defined(__GNUC__) && !defined(__clang__)
262 : : #pragma GCC diagnostic pop
263 : : #endif
264 : :
265 : 3 : return true;
266 : : }
267 : :
268 : 40 : bool RawData::create(size_t _size) noexcept {
269 [ + + ]: 40 : if VUNLIKELY (_size == 0) {
270 : 1 : return false;
271 : : }
272 : :
273 [ + + + - : 39 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
274 : 2 : Bytes::bytes_free(data_, size_);
275 : : }
276 : :
277 : 39 : size_ = _size;
278 : :
279 : 39 : data_ = Bytes::bytes_malloc(size_);
280 : :
281 : 39 : is_owner_ = true;
282 : :
283 : 39 : return true;
284 : : }
285 : :
286 : 4 : void RawData::clear() noexcept {
287 [ + + + - : 4 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
288 : 3 : Bytes::bytes_free(data_, size_);
289 : : }
290 : :
291 : 4 : is_owner_ = false;
292 : 4 : reserved_buf_ = 0;
293 : 4 : data_ = nullptr;
294 : 4 : size_ = 0;
295 : :
296 : : #if defined(__GNUC__) && !defined(__clang__)
297 : : #pragma GCC diagnostic push
298 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
299 : : #if __GNUC__ >= 11
300 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
301 : : #endif
302 : : #endif
303 : :
304 : 4 : std::memset(&header, 0, sizeof(header));
305 : :
306 : : #if defined(__GNUC__) && !defined(__clang__)
307 : : #pragma GCC diagnostic pop
308 : : #endif
309 : 4 : }
310 : :
311 : 5 : bool RawData::shallow_copy(uint8_t* data, size_t size) noexcept {
312 [ + + + + : 5 : if VUNLIKELY (!data || size == 0) {
+ + ]
313 : 2 : return false;
314 : : }
315 : :
316 [ + + ]: 3 : if VUNLIKELY (data_ == data) {
317 : 1 : return false;
318 : : }
319 : :
320 [ - + - - : 2 : if (is_owner_ && data_ && size_ != 0) {
- - ]
321 : 0 : Bytes::bytes_free(data_, size_);
322 : : }
323 : :
324 : 2 : is_owner_ = false;
325 : :
326 : 2 : data_ = data;
327 : 2 : size_ = size;
328 : :
329 : 2 : return true;
330 : : }
331 : :
332 : 8 : bool RawData::deep_copy(uint8_t* data, size_t size) noexcept {
333 [ + + + + : 8 : if VUNLIKELY (!data || size == 0) {
+ + ]
334 : 4 : return false;
335 : : }
336 : :
337 [ + + ]: 4 : if (is_owner_) {
338 [ - + ]: 2 : if VUNLIKELY (!data_) {
339 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
340 : : }
341 : :
342 [ + + ]: 2 : if VUNLIKELY (data_ == data) {
343 : 1 : return false;
344 : : }
345 : :
346 [ + - ]: 1 : if VUNLIKELY (size_ != size) {
347 : 1 : create(size);
348 : : }
349 : : } else {
350 : 2 : create(size);
351 : : }
352 : :
353 : 3 : std::memcpy(data_, data, size);
354 : :
355 : 3 : return true;
356 : : }
357 : :
358 : 3 : bool RawData::fill_data(uint8_t* data, size_t size) noexcept { return deep_copy(data, size); }
359 : :
360 : 15 : uint16_t& RawData::get_reserved() noexcept { return reserved_buf_; }
361 : :
362 : 54 : const uint8_t* RawData::data() const noexcept { return data_; }
363 : :
364 : 27 : size_t RawData::size() const noexcept { return size_; }
365 : :
366 : 23 : bool RawData::is_owner() const noexcept { return is_owner_; }
367 : :
368 : : } // namespace zerocopy
369 : :
370 : : } // namespace vlink
|