TEC
A lightweight C++ library enabling safe, efficient execution in multithreaded and concurrent systems.
Loading...
Searching...
No Matches
tec_net_data.hpp
Go to the documentation of this file.
1// Time-stamp: <Last changed 2026-02-16 15:42:51 by magnolia>
2/*----------------------------------------------------------------------
3------------------------------------------------------------------------
4Copyright (c) 2020-2026 The Emacs Cat (https://github.com/olddeuteronomy/tec).
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17------------------------------------------------------------------------
18----------------------------------------------------------------------*/
19
27#pragma once
28
29#include <cstddef>
30#include <cstdio>
31#include <string>
32#include <type_traits>
33
34#include "tec/tec_def.hpp" // IWYU pragma: keep
35#include "tec/tec_memfile.hpp"
36#include "tec/tec_container.hpp"
37#include "tec/tec_serialize.hpp"
39
40
41namespace tec {
42
51class NetData: public NdTypes {
52public:
55
56protected:
59
60public:
64 NetData() = default;
65
69 NetData(const NetData&) = delete;
70
74 NetData(NetData&&) = delete;
75
79 virtual ~NetData() = default;
80
85 const Bytes& bytes() const {
86 return data_;
87 }
88
93 const void* data() const {
94 return data_.data();
95 }
96
101 void copy_from(const NetData& src) {
102 header = src.header;
103 data_.copy_from(src.bytes());
104 }
105
111 void move_from(NetData&& src, size_t size_to_shrink = 0) {
112 header = src.header;
113 data_.move_from(std::move(src.bytes()), size_to_shrink);
114 }
115
119 void rewind() {
120 data_.rewind();
121 }
122
127 size_t size() const {
128 return header.size;
129 }
130
135 size_t capacity() const {
136 return data_.capacity();
137 }
138
145 return data_;
146 }
147
148public:
149
150 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
151 *
152 * STORE
153 *
154 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
155
165 template <typename T>
166 NetData& operator << (const T& val) {
167 ElemHeader hdr = get_info<T>(val);
168 if( hdr.tag & Meta::Sequence ) {
169 write_sequence(&hdr, &val);
170 }
171 else if(hdr.tag & Meta::Scalar) {
172 write_scalar(&hdr, &val);
173 }
174 else if(hdr.tag == Tags::Object) {
175 write_object(&hdr, val);
176 }
177 else if(hdr.tag == Tags::Map) {
178 write_map(&hdr, val);
179 }
180 else if(hdr.tag == Tags::Container) {
181 write_container(&hdr, val);
182 }
183
184 header.size = data_.size();
185 return *this;
186 }
187
188protected:
189
197 template <typename TMap>
198 size_t write_map(ElemHeader* hdr, const TMap& map) {
199 if constexpr (is_map_v<TMap>) {
200 ElemHeader* hdr_ptr = (ElemHeader*)data_.ptr(data_.tell());
201 // Write the map header.
202 data_.write(hdr, sizeof(ElemHeader));
203 size_t cur_pos = data_.tell();
204 // Write all elements of a container.
205 for( const auto& [key, value]: map ) {
206 *this << key << value;
207 }
208 // Set actual container size.
209 auto bytes_written = data_.tell() - cur_pos;
210 hdr_ptr->size = bytes_written;
211 return bytes_written;
212 }
213 return 0;
214 }
215
223 template <typename TContainer>
224 size_t write_container(ElemHeader* hdr, const TContainer& container) {
225 if constexpr (is_container_v<TContainer>) {
226 ElemHeader* hdr_ptr = (ElemHeader*)data_.ptr(data_.tell());
227 // Write the container header.
228 data_.write(hdr, sizeof(ElemHeader));
229 size_t cur_pos = data_.tell();
230 // Write all elements of a container.
231 for( const auto& e: container ) {
232 *this << e;
233 }
234 // Set actual container size.
235 auto bytes_written = data_.tell() - cur_pos;
236 hdr_ptr->size = bytes_written;
237 return bytes_written;
238 }
239 return 0;
240 }
241
249 template <typename TObject>
250 size_t write_object(ElemHeader* hdr, const TObject& obj) {
251 if constexpr (is_serializable_v<TObject>) {
252 if constexpr (is_root_v<TObject>) {
253 header.id = obj.id();
254 }
255 ElemHeader* hdr_ptr = (ElemHeader*)data_.ptr(data_.tell());
256 // Write the object header.
257 data_.write(hdr, sizeof(ElemHeader));
258 size_t cur_pos = data_.tell();
259 // Write an object
260 obj.store(std::ref(*this));
261 // Set actual object size.
262 auto bytes_written = data_.tell() - cur_pos;
263 hdr_ptr->size = bytes_written;
264 return bytes_written;
265 }
266 return 0;
267 }
268
275 virtual size_t write_long_double_64(ElemHeader* hdr, const double* d64) {
276 double dst[2]{*d64, 0.0};
277 data_.write(dst, hdr->size);
278 return hdr->size;
279 }
280
287 virtual size_t write_scalar(ElemHeader* hdr, const void* p) {
288 data_.write(hdr, sizeof(ElemHeader));
289 if(sizeof(long double) == 8 && hdr->tag == Tags::F128) {
290 // On Windows, sizeof(long double) == sizeof(double) == 8,
291 // but we always use 16-byte for storing long double.
292 return write_long_double_64(hdr, static_cast<const double*>(p));
293 }
294 data_.write(p, hdr->size);
295 return hdr->size;
296 }
297
304 virtual size_t write_sequence(ElemHeader* hdr, const void* p) {
305 // Write the sequence header.
306 data_.write(hdr, sizeof(ElemHeader));
307 if (hdr->size) {
308 if( hdr->tag == Tags::SChar ) {
309 const std::string* s = static_cast<const std::string*>(p);
310 data_.write(s->data(), hdr->size);
311 }
312 else if( hdr->tag == Tags::SByte ) {
313 const Blob* bs = static_cast<const Blob*>(p);
314 data_.write(bs->data(), hdr->size);
315 }
316 }
317 return hdr->size;
318 }
319
320 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
321 *
322 * LOAD
323 *
324 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
325
326public:
327
334 template <typename T>
336 ElemHeader hdr;
337 data_.read(&hdr, sizeof(ElemHeader));
338 // Object.
339 if (hdr.tag == Tags::Object) {
340 if constexpr(is_serializable_v<T>) {
341 val.load(std::ref(*this));
342 }
343 }
344 // Map.
345 else if (hdr.tag == Tags::Map) {
346 read_map(&hdr, val);
347 }
348 // Container (but not a String!).
349 else if (hdr.tag == Tags::Container) {
350 read_container(&hdr, val);
351 }
352 // Scalar (including sequences).
353 else {
354 read(&hdr, &val);
355 }
356 return *this;
357 }
358
359protected:
360
367 template <typename TMap>
368 void read_map(ElemHeader* hdr, TMap& map) {
369 if constexpr(is_map_v<TMap>) {
370 for( size_t n = 0 ; n < hdr->count ; ++n ) {
371 typename TMap::key_type k;
372 typename TMap::mapped_type e;
373 *this >> k >> e;
374 map[k] = e;
375 }
376 }
377 }
378
385 template <typename TContainer>
386 void read_container(ElemHeader* hdr, TContainer& c) {
387 if constexpr(
388 is_container_v<TContainer> &&
389 !is_map_v<TContainer> &&
390 !std::is_same_v<TContainer, String>
391 ) {
392 for( size_t n = 0 ; n < hdr->count ; ++n ) {
393 typename TContainer::value_type e;
394 *this >> e;
395 c.push_back(e);
396 }
397 }
398 }
399
405 virtual void read(ElemHeader* hdr, void* dst) {
406 if( hdr->tag & Meta::Scalar) {
407 if( hdr->tag & Meta::Sequence ) {
408 read_sequence(hdr, dst);
409 }
410 else {
411 read_scalar(hdr, dst);
412 }
413 }
414 else {
415 // Skip unknown element.
416 data_.seek(hdr->size, SEEK_CUR);
417 }
418 }
419
425 virtual void read_long_double_64(const ElemHeader* hdr, double* d64) {
426 double d[2]{0.0, 0.0};
427 data_.read(d, hdr->size);
428 *d64 = d[0];
429 }
430
436 virtual void read_scalar(const ElemHeader* hdr, void* dst) {
437 if(sizeof(long double) == 8 && hdr->tag == Tags::F128) {
438 // On Windows, sizeof(long double) == sizeof(double) == 8
439 read_long_double_64(hdr, static_cast<double*>(dst));
440 }
441 else {
442 data_.read(dst, hdr->size);
443 }
444 }
445
451 virtual void read_sequence(const ElemHeader* hdr, void* dst) {
452 if (hdr->size) {
453 if( hdr->tag == Tags::SChar ) {
454 std::string* str = static_cast<String*>(dst);
455 str->resize(hdr->size);
456 // To avoid silly GCC warning.
457 data_.read(&str->at(0), hdr->size);
458 }
459 else if( hdr->tag == Tags::SByte ) {
460 Blob* bytes = static_cast<Blob*>(dst);
461 bytes->resize(hdr->size);
462 data_.read(bytes->data(), hdr->size);
463 }
464 }
465 }
466
467public:
468
469 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
470 *
471 * NetData streams
472 *
473 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
474
478 struct StreamIn {
479 NetData* nd;
480
481 StreamIn()
482 : nd{nullptr}
483 {}
484
485 explicit StreamIn(NetData* _nd)
486 : nd{_nd}
487 {}
488 };
489
493 struct StreamOut {
494 NetData* nd;
495
496 StreamOut()
497 : nd{nullptr}
498 {}
499
500 explicit StreamOut(NetData* _nd)
501 : nd{_nd}
502 {}
503 };
504
505
506}; // class NetData
507
508
509} // namespace tec
A byte buffer class with stream-like read/write semantics.
Definition tec_memfile.hpp:50
size_t write(const void *src, size_t len)
Writes data into the buffer at the current position.
Definition tec_memfile.hpp:382
long seek(long offset, int whence)
Moves the read/write position relative to a reference point.
Definition tec_memfile.hpp:343
const char * ptr(long pos) const
Returns a const pointer to a specific position in the buffer.
Definition tec_memfile.hpp:273
const void * data() const
Returns a const pointer to the buffer's data.
Definition tec_memfile.hpp:247
constexpr void rewind() noexcept
Resets the read/write position to the beginning of the buffer.
Definition tec_memfile.hpp:327
size_t capacity() const noexcept
Returns the current capacity of the underlying storage.
Definition tec_memfile.hpp:312
size_t read(void *dst, size_t len)
Reads data from the buffer starting at the current position.
Definition tec_memfile.hpp:404
constexpr long tell() const noexcept
Returns the current read/write position.
Definition tec_memfile.hpp:320
void move_from(MemFile &&src, size_t size_to_shrink=0)
Moves data from another MemFile instance.
Definition tec_memfile.hpp:221
size_t size() const noexcept
Returns the logical size of the data in the buffer.
Definition tec_memfile.hpp:304
void copy_from(const MemFile &src)
Copies data from another MemFile instance.
Definition tec_memfile.hpp:206
Lightweight binary serialization container optimized for network communication.
Definition tec_net_data.hpp:51
virtual void read_sequence(const ElemHeader *hdr, void *dst)
Reads string or blob sequence data.
Definition tec_net_data.hpp:451
void copy_from(const NetData &src)
Performs deep copy of content from another NetData instance.
Definition tec_net_data.hpp:101
virtual ~NetData()=default
Virtual destructor.
void read_container(ElemHeader *hdr, TContainer &c)
Reads sequence container from stream.
Definition tec_net_data.hpp:386
void read_map(ElemHeader *hdr, TMap &map)
Reads map-like container from stream.
Definition tec_net_data.hpp:368
size_t write_map(ElemHeader *hdr, const TMap &map)
Serializes map-like container (std::unordered_map)
Definition tec_net_data.hpp:198
Bytes data_
Internal storage of serialized binary data.
Definition tec_net_data.hpp:58
Bytes & bytes()
Returns mutable reference to internal byte buffer.
Definition tec_net_data.hpp:144
const void * data() const
Returns const pointer to the beginning of serialized data.
Definition tec_net_data.hpp:93
NetData(const NetData &)=delete
Copy constructor – use explicit copy_from()
virtual size_t write_long_double_64(ElemHeader *hdr, const double *d64)
Special handling for long double when sizeof(long double) == 8 (on MS Windows)
Definition tec_net_data.hpp:275
size_t size() const
Returns current logical size of the message (according to header)
Definition tec_net_data.hpp:127
virtual size_t write_scalar(ElemHeader *hdr, const void *p)
Writes single scalar value with its header.
Definition tec_net_data.hpp:287
void rewind()
Resets read position to the beginning of the buffer.
Definition tec_net_data.hpp:119
virtual void read(ElemHeader *hdr, void *dst)
Generic dispatcher for reading scalar/sequence values.
Definition tec_net_data.hpp:405
NetData()=default
Default constructor - creates empty NetData object.
void move_from(NetData &&src, size_t size_to_shrink=0)
Efficiently moves content from another NetData instance.
Definition tec_net_data.hpp:111
virtual void read_scalar(const ElemHeader *hdr, void *dst)
Reads single scalar value.
Definition tec_net_data.hpp:436
virtual void read_long_double_64(const ElemHeader *hdr, double *d64)
Platform-specific reading of MSWindows' long double (64 bit) stored as 128-bit double.
Definition tec_net_data.hpp:425
size_t write_container(ElemHeader *hdr, const TContainer &container)
Serializes sequence container (vector, deque, list, ...)
Definition tec_net_data.hpp:224
size_t write_object(ElemHeader *hdr, const TObject &obj)
Serializes custom object that implements store() method.
Definition tec_net_data.hpp:250
Header header
Global message header.
Definition tec_net_data.hpp:54
const Bytes & bytes() const
Returns const reference to internal byte buffer.
Definition tec_net_data.hpp:85
NetData & operator<<(const T &val)
Serialization operator (stream-like syntax)
Definition tec_net_data.hpp:166
NetData & operator>>(T &val)
Deserialization operator (stream-like syntax)
Definition tec_net_data.hpp:335
virtual size_t write_sequence(ElemHeader *hdr, const void *p)
Writes string or blob sequence (header + raw bytes)
Definition tec_net_data.hpp:304
size_t capacity() const
Returns current capacity of internal buffer.
Definition tec_net_data.hpp:135
NetData(NetData &&)=delete
Disabled – use explicit move_from()
Per-element header describing the following data item.
Definition tec_nd_types.hpp:222
Size size
Payload size in bytes (excluding this header).
Definition tec_nd_types.hpp:224
Count count
Number of elements (for containers/sequences; 1 for scalars).
Definition tec_nd_types.hpp:225
Tag tag
Type and property tag.
Definition tec_nd_types.hpp:223
Global header placed at the start of every serialized buffer.
Definition tec_nd_types.hpp:134
uint16_t id
User-defined root object identifier.
Definition tec_nd_types.hpp:144
uint32_t size
Total size of the serialized payload excluding this header (bytes).
Definition tec_nd_types.hpp:142
Core type definitions and metadata for a lightweight binary serialization format.
Definition tec_nd_types.hpp:56
std::string String
String storage type.
Definition tec_nd_types.hpp:64
Helper type for ADL customization of input operations.
Definition tec_net_data.hpp:478
Helper type for ADL customization of output operations.
Definition tec_net_data.hpp:493
Generic container and map traits.
Common definitions and utilities for the tec namespace.
A byte buffer class with stream-like read/write semantics.
Core type definitions and metadata for a lightweight binary serialization format.
The base interface for serializable objects.