From 4c982b2ffe99f5dee70657424161de9541e00a21 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 29 Oct 2022 16:49:12 +0200 Subject: serialize: use std::bit_cast --- serialize/binary-reader.hpp | 20 +------- serialize/binary-reader.inl | 48 ++++------------- serialize/binary-serializer.cpp | 13 ++--- serialize/binary-serializer.hpp | 7 +++ serialize/binary-writer.hpp | 3 +- serialize/binary-writer.inl | 111 +++++++++++++++------------------------- 6 files changed, 67 insertions(+), 135 deletions(-) (limited to 'serialize') diff --git a/serialize/binary-reader.hpp b/serialize/binary-reader.hpp index 4876e0dc..2d09d51b 100644 --- a/serialize/binary-reader.hpp +++ b/serialize/binary-reader.hpp @@ -5,19 +5,6 @@ namespace floormat::Serialize { -union alignas(alignof(double)) value_u { - 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; @@ -40,13 +27,10 @@ struct binary_reader final { constexpr binary_reader(It begin, It end) noexcept; constexpr void assert_end() noexcept; - template constexpr value_u read_u() noexcept; - template constexpr value_u read_u() noexcept; - template T read() noexcept; + template constexpr T read() noexcept; template constexpr std::array read() noexcept; constexpr std::size_t bytes_read() const noexcept { return num_bytes_read; } - template - auto read_asciiz_string() noexcept; + template constexpr auto read_asciiz_string() noexcept; private: std::size_t num_bytes_read = 0; diff --git a/serialize/binary-reader.inl b/serialize/binary-reader.inl index 0c5b8531..b190f463 100644 --- a/serialize/binary-reader.inl +++ b/serialize/binary-reader.inl @@ -16,24 +16,16 @@ constexpr binary_reader::binary_reader(It begin, It end) noexcept : {} template -template -constexpr value_u binary_reader::read_u() noexcept +template +constexpr T binary_reader::read() noexcept { - value_u buf; - static_assert(sizeof(T) <= sizeof(buf)); - fm_assert(std::distance(it, end) >= sizeof(T)); - num_bytes_read += 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); + constexpr std::size_t N = sizeof(T); + fm_assert((std::ptrdiff_t)N <= std::distance(it, end)); + num_bytes_read += N; + char buf[N]; + for (std::size_t i = 0; i < N; i++) + buf[i] = *it++; + return maybe_byteswap(std::bit_cast(buf)); } template @@ -56,26 +48,6 @@ constexpr void binary_reader::assert_end() 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::ptrdiff_t)sizeof(T) <= std::distance(it, end)); - num_bytes_read += 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; -} - template binary_reader& operator>>(binary_reader& reader, T& x) noexcept { @@ -85,7 +57,7 @@ binary_reader& operator>>(binary_reader& reader, T& x) noexcept template template -auto binary_reader::read_asciiz_string() noexcept +constexpr auto binary_reader::read_asciiz_string() noexcept { static_assert(MAX > 0); diff --git a/serialize/binary-serializer.cpp b/serialize/binary-serializer.cpp index d632febd..682ae2f5 100644 --- a/serialize/binary-serializer.cpp +++ b/serialize/binary-serializer.cpp @@ -34,23 +34,20 @@ template struct byte_array_iterator; [[maybe_unused]] static constexpr bool test1() { - constexpr std::array bytes = { 1, 0, 1, 0 }; + constexpr std::array bytes = { 1, 2, 3, 4 }; 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; + return x.read() == 67305985; } static_assert(test1()); [[maybe_unused]] static constexpr bool test2() { - constexpr std::array bytes = { 1, 0, 1, 0 }; + constexpr std::array bytes = { 4, 3, 2, 1 }; auto r = binary_reader(bytes.cbegin(), bytes.cend()); - const auto x = r.read_u(); + const auto x = r.read(); r.assert_end(); - return x.bytes[0] == 1 && x.bytes[1] == 0 && x.bytes[2] == 1 && x.bytes[3] == 0; + return x == 16909060; } static_assert(test2()); diff --git a/serialize/binary-serializer.hpp b/serialize/binary-serializer.hpp index 43fffea8..66281cc1 100644 --- a/serialize/binary-serializer.hpp +++ b/serialize/binary-serializer.hpp @@ -41,9 +41,16 @@ concept integer = requires(T x) { template concept serializable = requires(T x) { + requires std::same_as>; requires std::floating_point || integer; }; +template +constexpr inline T maybe_byteswap(T x) +{ + return x; +} + template constexpr inline T maybe_byteswap(T x) { diff --git a/serialize/binary-writer.hpp b/serialize/binary-writer.hpp index 02fe427d..13580eb0 100644 --- a/serialize/binary-writer.hpp +++ b/serialize/binary-writer.hpp @@ -8,8 +8,7 @@ namespace floormat::Serialize { template It> struct binary_writer final { explicit constexpr binary_writer(It it) noexcept; - template constexpr void write(T x) noexcept; - template void write(T x) noexcept; + template constexpr void write(T x) noexcept; constexpr void write_asciiz_string(StringView str) noexcept; constexpr std::size_t bytes_written() const noexcept { return _bytes_written; } diff --git a/serialize/binary-writer.inl b/serialize/binary-writer.inl index 5fb4db6d..e5a7ba16 100644 --- a/serialize/binary-writer.inl +++ b/serialize/binary-writer.inl @@ -1,69 +1,42 @@ -#pragma once -#include "binary-writer.hpp" -#include "binary-serializer.hpp" -#include "compat/assert.hpp" -#include -#include - -namespace floormat::Serialize { - -template It> -constexpr binary_writer::binary_writer(It it) noexcept : it{it}, _bytes_written{0} {} - -template It> -template -constexpr void binary_writer::write(T x) noexcept -{ - union { - T datum; - char bytes[sizeof(T)]; - } buf; - - if (std::is_constant_evaluated()) - for (std::size_t i = 0; i < std::size(buf.bytes); i++) - buf.bytes[i] = 0; - _bytes_written += sizeof(T); - if constexpr(sizeof(T) == 1) - buf.bytes[0] = (char)x; - else if (!std::is_constant_evaluated()) - buf.datum = maybe_byteswap(x); - else - for (std::size_t i = 0; i < sizeof(T); x >>= 8, i++) - buf.bytes[i] = (char)(unsigned char)x; - for (std::size_t i = 0; i < sizeof(T); i++) - *it++ = buf.bytes[i]; -} - -template It> -template -void binary_writer::write(T x) noexcept -{ - union { - T datum; - char bytes[sizeof(T)]; - } buf; - _bytes_written += sizeof(T); - buf.datum = maybe_byteswap(x); - for (std::size_t i = 0; i < sizeof(T); i++) - *it++ = buf.bytes[i]; -} - -template It, serializable T> -constexpr binary_writer& operator<<(binary_writer& writer, T x) noexcept -{ - writer.template write(x); - return writer; -} - -template It> -constexpr void binary_writer::write_asciiz_string(StringView str) noexcept -{ - fm_debug_assert(str.flags() & StringViewFlag::NullTerminated); - const auto sz = str.size(); - _bytes_written += sz + 1; - for (std::size_t i = 0; i < sz; i++) - *it++ = str[i]; - *it++ = '\0'; -} - -} // namespace floormat::Serialize +#pragma once +#include "binary-writer.hpp" +#include "binary-serializer.hpp" +#include "compat/assert.hpp" +#include +#include + +namespace floormat::Serialize { + +template It> +constexpr binary_writer::binary_writer(It it) noexcept : it{it}, _bytes_written{0} {} + +template It> +template +constexpr void binary_writer::write(T x) noexcept +{ + _bytes_written += sizeof(T); + constexpr std::size_t N = sizeof(T); + const auto buf = std::bit_cast, T>(maybe_byteswap(x)); + for (std::size_t i = 0; i < N; i++) + *it++ = buf[i]; +} + +template It, serializable T> +constexpr binary_writer& operator<<(binary_writer& writer, T x) noexcept +{ + writer.template write(x); + return writer; +} + +template It> +constexpr void binary_writer::write_asciiz_string(StringView str) noexcept +{ + fm_debug_assert(str.flags() & StringViewFlag::NullTerminated); + const auto sz = str.size(); + _bytes_written += sz + 1; + for (std::size_t i = 0; i < sz; i++) + *it++ = str[i]; + *it++ = '\0'; +} + +} // namespace floormat::Serialize -- cgit v1.2.3