Binary Serialize
Loading...
Searching...
No Matches
binary_serialize.hpp
1
116#ifndef BINARY_SERIALIZE_HPP_INCLUDED
117#define BINARY_SERIALIZE_HPP_INCLUDED
118
119#include "buffer/shared_buffer.hpp"
121
122#include <cstddef> // std::byte, std::size_t, std::nullptr_t
123#include <cstdint> // std::uint32_t, etc
124#include <optional>
125#include <string>
126#include <string_view>
127#include <cstring> // std::memcpy
128#include <type_traits>
129#include <iterator> // value type of iterator
130#include <array>
131#include <cassert>
132#include <concepts>
133
134#include <iostream> // debugging
135
136namespace chops {
137
138template <typename Ctr>
139concept supports_expandable_buffer =
140 std::same_as<Ctr::value_type, std::byte> &&
141 requires (Ctr ctr) {
142 { ctr.size() } -> std::integral;
143 ctr.resize(std::size_t{});
144 { ctr.data() } -> std::same_as<std::byte*>;
145 }
146
147template <typename Ctr>
148concept supports_endian_expandable_buffer =
149 supports_expandable_buffer<Ctr> &&
150 requires (Ctr ctr) {
151 typename Ctr::endian_type;
152 }
153
154template <supports_expandable_buffer Ctr = chops::mutable_shared_buffer,
155 std::endian Endian = std::endian::little>
156class expandable_buffer {
157private:
158 Ctr m_ctr;
159public:
160 using endian_type = Endian;
161 using value_type = std::byte;
162 Ctr& get_buf() noexcept { return m_ctr; }
163 std::size_t size() noexcept { return m_ctr.size(); }
164 std::byte* data() noexcept { return m_ctr.data(); }
165 void resize(std::size_t sz) noexcept m_ctr.resize(sz); }
166};
167
191/*
192template <typename Cnt, typename Container>
193Container extract_sequence(const std::byte* buf) noexcept(fill in) {
194 Cnt c = extract_val<Cnt>(buf);
195
196}
197*/
198
199
227/*
228template <typename Cnt, typename Iter>
229std::size_t append_sequence(std::byte* buf, Cnt cnt, Iter start, Iter end) noexcept {
230 std::size_t num = 0;
231 append_val(buf, cnt);
232 num += cnt;
233 while (start != end) {
234 num += append_val(buf, *start);
235 ++start;
236 }
237}
238*/
239
251template <std::size_t N>
253public:
258 fixed_size_byte_array() noexcept : m_buf(), m_size(0u) { }
259
267 std::size_t size() const noexcept {
268 return m_size;
269 }
275 void resize(std::size_t sz) noexcept {
276 assert(sz <= N);
277 m_size = sz;
278 }
284 std::byte* data() noexcept {
285 return m_buf.data();
286 }
291 void clear() noexcept {
292 m_size = 0u;
293 }
294
295private:
296 std::array<std::byte, N> m_buf;
297 std::size_t m_size;
298};
299
300
301// add a function parameter to the function overload set so that std::vector<std::byte> and
302// similar can be used for the Buf template parameter
303struct adl_tag { };
304
305
306namespace detail {
307
308template <integral_or_byte CastTypeVal, integral_or_byte T,
309 supports_endian_expandable_buf Buf = expandable_buffer>
310constexpr Buf& serialize_val(Buf& buf, const T& val) {
311 auto old_sz = buf.size();
312 buf.resize(old_sz + sizeof(CastTypeVal));
313 append_val<Buf::endian_type>(buf.data()+old_sz, static_cast<CastTypeVal>(val));
314 return buf;
315}
316
317template <integral_or_byte CastTypeVal, integral_or_byte T,
318 supports_endian_expandable Buf = chops::mutable_shared_buffer>
319constexpr Buf& serialize(Buf& buf, const T& val) {
320 return serialize_val<CastTypeVal> (buf, val);
321}
322
323template <integral_or_byte CastTypeSz, integral_or_byte CastTypeVal,
324 integral_or_byte T,
325 supports_endian_expandable Buf = chops::mutable_shared_buffer>
326constexpr Buf& serialize(Buf& buf, const T* seq, std::size_t sz) {
327 serialize_val<CastTypeSz> (buf, sz);
328 for (int i {0}; i < sz; ++i) {
329 serialize_val<CastTypeVal>(buf, seq[i]);
330 }
331 return buf;
332}
333
334template <integral_or_byte CastTypeSz,
335 supports_endian_expandable Buf = chops::mutable_shared_buffer>
336constexpr Buf& serialize(Buf& buf, const std::string& str) {
337 return serialize<CastTypeSz, std::byte> (buf, str.data(), std.size());
338}
339
340template <integral_or_byte CastTypeBool, integral_or_byte CastTypeVal,
341 integral_or_byte T,
342 supports_endian_expandable Buf = chops::mutable_shared_buffer>
343constexpr Buf& serialize(Buf& buf, const std::optional<T>& val) {
344 if (val)
345 serialize_val<CastTypeBool> (buf, 1);
346 return serialize_val<CastTypeVal> (buf, *val);
347 }
348 serialize_val<CastTypeBool> (buf, 0);
349}
350
351}
352
353
395template <typename CastValType, typename T, typename Buf = chops::mutable_shared_buffer,
396 typename = std::enable_if_t<detail::is_arithmetic_or_byte<T>()> >
397Buf& marshall(Buf& buf, const T& val) {
398 return marshall<CastValType>(buf, val, adl_tag { });
399}
400
401// overloads for specific types
402template <typename CastBoolType, typename Buf = chops::mutable_shared_buffer>
403Buf& marshall(Buf& buf, bool b) {
404 return marshall<CastBoolType>(buf, static_cast<CastBoolType>(b ? 1 : 0));
405}
406
407
408template <typename CastBoolType, typename CastValType, typename T, typename Buf = chops::mutable_shared_buffer>
409Buf& marshall(Buf& buf, const std::optional<T>& val) {
410 marshall<CastBoolType>(buf, val.has_value());
411 if (val.has_value()) {
412 if constexpr (detail::is_arithmetic_or_byte<T>()) {
413 marshall<CastValType>(buf, *val);
414 }
415 else { // *val should be a UDT
416 marshall(buf, *val);
417 }
418 }
419 return buf;
420}
421
422// overload for sequences
423template <typename CastCntType, typename CastValType, typename Iter, typename Buf = chops::mutable_shared_buffer,
424 typename T = typename std::iterator_traits<Iter>::value_type>
425Buf& marshall_seq(Buf& buf, std::size_t num_elems, Iter iter) {
426 marshall<CastCntType>(buf, num_elems);
427 for (std::size_t i = 0u; i < num_elems; ++i) {
428 if constexpr (detail::is_arithmetic_or_byte<T>()) {
429 marshall<CastValType>(buf, *iter);
430 }
431 else {
432 marshall(buf, *iter);
433 }
434 ++iter;
435 }
436 return buf;
437}
438
439// efficiently append a buffer of bytes to the end of the existing buffer
440template <typename Buf = chops::mutable_shared_buffer>
441Buf& marshall_buf(Buf& buf, std::size_t num_bytes, const std::byte* append_buf) {
442 auto old_sz = buf.size();
443 buf.resize(old_sz + num_bytes);
444 std::memcpy (buf.data()+old_sz, append_buf, num_bytes);
445 return buf;
446}
447
448template <typename CastCntType, typename Buf = chops::mutable_shared_buffer>
449Buf& marshall(Buf& buf, std::string_view str) {
450 marshall<CastCntType>(buf, str.size());
451 return marshall_buf(buf, str.size(), cast_ptr_to<std::byte>(str.data()));
452}
453
454template <typename CastCntType, typename Buf = chops::mutable_shared_buffer>
455Buf& marshall(Buf& buf, const std::string& str) {
456 return marshall<CastCntType>(buf, std::string_view(str));
457}
458
459template <typename CastCntType, typename Buf = chops::mutable_shared_buffer>
460Buf& marshall(Buf& buf, const char* str) {
461 return marshall<CastCntType>(buf, std::string_view(str));
462}
463
464} // end namespace
465
466#endif
467
Extract a sequence in network byte order from a std::byte buffer into the provided container.
Definition binary_serialize.hpp:252
fixed_size_byte_array() noexcept
Default construct the @ fixed_size_byte_array.
Definition binary_serialize.hpp:258
std::size_t size() const noexcept
Return the size of the data which has been written into the buffer.
Definition binary_serialize.hpp:267
void clear() noexcept
Logically reset so that new data can be written into the buffer at the beginning.
Definition binary_serialize.hpp:291
void resize(std::size_t sz) noexcept
Increase the logical size, allowing bytes to be appended.
Definition binary_serialize.hpp:275
std::byte * data() noexcept
Return a pointer to the beginning of the buffer.
Definition binary_serialize.hpp:284
Functions to extract arithmetic binary values from a byte buffer (in either endian order) to native f...
Definition binary_serialize.hpp:303