#pragma once #include "binary-serializer.hpp" #include "compat/assert.hpp" namespace floormat::Serialize { template template constexpr binary_reader::binary_reader(const Seq& seq) noexcept : it{std::begin(seq)}, end{std::end(seq)} {} template constexpr binary_reader::binary_reader(It begin, It end) noexcept : it{begin}, end{end} {} 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; } template constexpr inline T maybe_byteswap(T x) { if constexpr(std::endian::native == std::endian::big) return std::byteswap(x); else return x; } 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 binary_reader& operator>>(binary_reader& reader, T& x) noexcept { value_u u = reader.template read(); x = *reinterpret_cast(&u.bytes[0]); return reader; } 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_assert_debug(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