From 4dce8e6aeb770fee1a7190526b04d03f3da69cb0 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 27 Oct 2022 18:28:42 +0200 Subject: wip binary serializer --- serialize/binary-serializer.cpp | 86 +++++++++++++++++++++++++++++++++++++++++ serialize/binary-serializer.hpp | 82 +++++++++++++++++++++++++++++++++++++++ serialize/binary-serializer.inl | 54 ++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 serialize/binary-serializer.cpp create mode 100644 serialize/binary-serializer.hpp create mode 100644 serialize/binary-serializer.inl diff --git a/serialize/binary-serializer.cpp b/serialize/binary-serializer.cpp new file mode 100644 index 00000000..08606768 --- /dev/null +++ b/serialize/binary-serializer.cpp @@ -0,0 +1,86 @@ +#include "binary-serializer.inl" +#include + +namespace floormat::Serialize { + +#if 0 +template +struct byte_array_iterator final +{ + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = char; + using pointer = char*; + using reference = char&; + + constexpr byte_array_iterator(char (&buf)[N]) : buf{&buf}, i{0} {} + constexpr byte_array_iterator(char (&buf)[N], std::size_t i) : buf{&buf}, i{i} {} + + constexpr reference operator*() const { fm_assert(i < N); return (*buf)[i]; } + constexpr pointer operator->() { fm_assert(i < N); return &(*buf)[i]; } + constexpr byte_array_iterator& operator++() noexcept { i++; return *this; } + constexpr byte_array_iterator operator++(int) noexcept { byte_array_iterator tmp = *this; ++(*this); return tmp; } + friend constexpr bool operator==(const byte_array_iterator&& a, const byte_array_iterator&& b) noexcept = default; + +private: + char (*buf)[N]; + std::size_t i; +}; + +template struct byte_array_iterator; +#endif + +struct value_buf final { + value_u value; + std::int8_t len; + + explicit constexpr value_buf(value_u value, std::int8_t len) : value{value}, len{len} {} + constexpr bool operator==(const value_buf& o) const noexcept; + + fm_DECLARE_DEFAULT_MOVE_ASSIGNMENT_(value_buf); + fm_DECLARE_DEFAULT_COPY_ASSIGNMENT(value_buf); +}; + +constexpr bool value_buf::operator==(const value_buf& o) const noexcept +{ + const auto N = len; + if (N != o.len) + return false; + for (std::int8_t i = 0; i < N; i++) + if (value.bytes[i] != o.value.bytes[i]) + return false; + return true; +} + +[[maybe_unused]] +static constexpr bool test1() +{ + constexpr std::array bytes = { 1, 0, 1, 0 }; + auto x = binary_reader(bytes.cbegin(), bytes.cend()); + return x.read_u().bytes[0] == 1 && + x.read_u().bytes[0] == 0 && + x.read_u().bytes[0] == 1 && + x.read_u().bytes[0] == 0; +} +static_assert(test1()); + +[[maybe_unused]] +static constexpr bool test2() +{ + constexpr std::array bytes = { 1, 0, 1, 0 }; + auto r = binary_reader(bytes.cbegin(), bytes.cend()); + const auto x = r.read_u(); + return x.bytes[0] == 1 && x.bytes[1] == 0 && x.bytes[2] == 1 && x.bytes[3] == 0; +} +static_assert(test2()); + +template +[[maybe_unused]] static constexpr T maybe_byteswap(T x) +{ + if constexpr(std::endian::native == std::endian::big) + return std::byteswap(x); + else + return x; +} + +} // namespace floormat::Serialize diff --git a/serialize/binary-serializer.hpp b/serialize/binary-serializer.hpp new file mode 100644 index 00000000..19aa5548 --- /dev/null +++ b/serialize/binary-serializer.hpp @@ -0,0 +1,82 @@ +#pragma once +#include "compat/integer-types.hpp" +#include "compat/defs.hpp" + +#include +#include +#include +#include + +namespace floormat::Serialize { + +static_assert(std::endian::native == std::endian::big || std::endian::native == std::endian::little); + +enum class value_type : std::uint8_t { + none, uc, u8, u16, u32, u64, + f32, f64, + COUNT +}; + +template struct make_integer; +template using make_integer_t = typename make_integer::type; + +#define FM_SERIALIZE_MAKE_INTEGER(T) template<> struct make_integer { using type = T; } +FM_SERIALIZE_MAKE_INTEGER(std::uint8_t); +FM_SERIALIZE_MAKE_INTEGER(std::uint16_t); +FM_SERIALIZE_MAKE_INTEGER(std::uint32_t); +FM_SERIALIZE_MAKE_INTEGER(std::uint64_t); +#undef FN_SERIALIZE_MAKE_INTEGER + +template +concept integer = requires(T x) { + requires std::integral; + requires sizeof(T) == sizeof(make_integer_t); +}; + +union value_u { + alignas(alignof(double)) char bytes[8]; + unsigned char uc; + std::uint8_t u8; + std::uint16_t u16; + std::uint32_t u32; + std::uint64_t u64; + float f32; + double f64; +}; + +static_assert(sizeof(value_u) == 8); + +template +concept char_sequence = requires(T& x, const T& cx) { + requires std::same_as; + requires std::same_as; + requires std::forward_iterator; + requires std::forward_iterator; + requires std::same_as>; + requires std::same_as>; +}; + +template +struct binary_reader final { + fm_DECLARE_DEFAULT_MOVE_COPY_ASSIGNMENTS(binary_reader); + constexpr binary_reader(It begin, It end) noexcept : it{begin}, end{end} {} + template + explicit constexpr binary_reader(const Seq& seq) noexcept : it{std::begin(seq)}, end{std::end(seq)} {} + constexpr ~binary_reader() noexcept; + + template constexpr value_u read_u() noexcept; + template constexpr value_u read_u() noexcept; + template T read() noexcept; + + static_assert(std::is_same_v())>>); + +private: + It it, end; +}; + +template binary_reader(It&& begin, It&& end) -> binary_reader>; + +template +binary_reader(Array&& array) -> binary_reader>; + +} // namespace floormat::Serialize diff --git a/serialize/binary-serializer.inl b/serialize/binary-serializer.inl new file mode 100644 index 00000000..9e7e58fa --- /dev/null +++ b/serialize/binary-serializer.inl @@ -0,0 +1,54 @@ +#pragma once + +#include "binary-serializer.hpp" + +namespace floormat::Serialize { + +template +template +constexpr value_u binary_reader::read_u() noexcept +{ + value_u buf; + static_assert(sizeof(T) <= sizeof(buf)); + fm_assert(std::distance(it, end) >= sizeof(T)); + for (int i = 0; i < sizeof(T); i++) + buf.bytes[i] = *it++; + return buf; +} + +template +template +T binary_reader::read() noexcept +{ + value_u buf = read_u(); + return *reinterpret_cast(buf.bytes); +} + +template +constexpr binary_reader::~binary_reader() noexcept +{ + fm_assert(it == end); +} + +template +template +constexpr value_u binary_reader::read_u() noexcept +{ + value_u buf; + if (std::is_constant_evaluated()) + for (std::size_t i = 0; i < std::size(buf.bytes); i++) + buf.bytes[i] = 0; + static_assert(sizeof(T) <= sizeof(buf)); + fm_assert(std::distance(it, end) >= (std::ptrdiff_t) sizeof(T)); + if constexpr(std::endian::native == std::endian::big) + for (int i = sizeof(T) - 1; i >= 0; i--) + buf.bytes[i] = *it++; + else + for (std::size_t i = 0; i < sizeof(T); i++) + buf.bytes[i] = *it++; + return buf; +} + +} // namespace floormat::Serialize + + -- cgit v1.2.3