#include "DataStream.hpp" #include #include #include static_assert(std::numeric_limits::is_iec559, "Non IEE754/IEC559 'float' is not supported."); static_assert(std::numeric_limits::is_iec559, "Non IEE754/IEC559 'double' is not supported."); static_assert(std::endian::native == std::endian::little || std::endian::native == std::endian::big, "Mixed endian is not supported."); // Reading/writing signed integer byte-by-byte is fine, since the representation got fixed to 2's complements in C++20 static uint16_t ByteSwap(uint16_t n) { auto bytes = reinterpret_cast(n); std::swap(bytes[0], bytes[1]); return n; } static uint32_t ByteSwap(uint32_t n) { #ifdef _MSC_VER // TODO #else return __builtin_bswap32(n); #endif } static uint64_t ByteSwap(uint64_t n) { #ifdef _MSC_VER // TODO #else return __builtin_bswap64(n); #endif } template static TSigned ByteSwap(TSigned n) { using Unsigned = std::make_unsigned_t; auto swapped = ::ByteSwap(std::bit_cast(n)); return std::bit_cast(swapped); } std::endian BaseDataStream::GetEndianness() const { return mEndian; } void BaseDataStream::SetEndianness(std::endian endianness) { mEndian = endianness; } InputDataStream::InputDataStream(InputFileStream stream) : mBackend{ std::move(stream) } { } void InputDataStream::ReadBytes(size_t byteCount, std::byte* buffer) { mBackend.ReadBytes(static_cast(byteCount),reinterpret_cast(buffer)); } void InputDataStream::ReadBytes(size_t byteCount, char* buffer) { mBackend.ReadBytes(static_cast(byteCount),reinterpret_cast(buffer)); } void InputDataStream::ReadBytes(size_t byteCount, signed char* buffer) { mBackend.ReadBytes(static_cast(byteCount),reinterpret_cast(buffer)); } void InputDataStream::ReadBytes(size_t byteCount, unsigned char* buffer) { mBackend.ReadBytes(static_cast(byteCount),reinterpret_cast(buffer)); } void InputDataStream::Read(int8_t& n) { // sizeof() of a reference type yields the size of the reference mBackend.ReadBytes(sizeof(n),reinterpret_cast(&n)); } void InputDataStream::Read(int16_t& n) { int16_t tmp; mBackend.ReadBytes(sizeof(tmp),reinterpret_cast(&tmp)); if (GetEndianness() != std::endian::native) { n = ::ByteSwap(tmp); } else { n = tmp; } } void InputDataStream::Read(int32_t& n) { int32_t tmp; mBackend.ReadBytes(sizeof(tmp),reinterpret_cast(&tmp)); if (GetEndianness() != std::endian::native) { n = ::ByteSwap(tmp); } else { n = tmp; } } void InputDataStream::Read(int64_t& n) { int64_t tmp; mBackend.ReadBytes(sizeof(tmp),reinterpret_cast(&tmp)); if (GetEndianness() != std::endian::native) { n = ::ByteSwap(tmp); } else { n = tmp; } } void InputDataStream::Read(uint8_t& n) { mBackend.ReadBytes(sizeof(n),reinterpret_cast(&n)); } void InputDataStream::Read(uint16_t& n) { uint16_t tmp; mBackend.ReadBytes(sizeof(tmp),reinterpret_cast(&tmp)); if (GetEndianness() != std::endian::native) { n = ::ByteSwap(tmp); } else { n = tmp; } } void InputDataStream::Read(uint32_t& n) { uint32_t tmp; mBackend.ReadBytes(sizeof(tmp),reinterpret_cast(&tmp)); if (GetEndianness() != std::endian::native) { n = ::ByteSwap(tmp); } else { n = tmp; } } void InputDataStream::Read(uint64_t& n) { uint64_t tmp; mBackend.ReadBytes(sizeof(tmp),reinterpret_cast(&tmp)); if (GetEndianness() != std::endian::native) { n = ::ByteSwap(tmp); } else { n = tmp; } } void InputDataStream::Read(float& n) { uint32_t buffer; Read(buffer); if (GetEndianness() != std::endian::native) { buffer = ::ByteSwap(buffer); } n = std::bit_cast(buffer); } void InputDataStream::Read(double& n) { uint64_t buffer; Read(buffer); if (GetEndianness() != std::endian::native) { buffer = ::ByteSwap(buffer); } n = std::bit_cast(buffer); } OutputDataStream::OutputDataStream(OutputFileStream stream) : mBackend{ std::move(stream) } { } void OutputDataStream::WriteBytes(size_t byteCount, const std::byte* buffer) { mBackend.WriteBytes(static_cast(byteCount), reinterpret_cast(buffer)); } void OutputDataStream::WriteBytes(size_t byteCount, const char* buffer) { mBackend.WriteBytes(static_cast(byteCount), reinterpret_cast(buffer)); } void OutputDataStream::WriteBytes(size_t byteCount, const signed char* buffer) { mBackend.WriteBytes(static_cast(byteCount), reinterpret_cast(buffer)); } void OutputDataStream::WriteBytes(size_t byteCount, const unsigned char* buffer) { mBackend.WriteBytes(static_cast(byteCount), reinterpret_cast(buffer)); } void OutputDataStream::Write(int8_t n) { mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(int16_t n) { if (GetEndianness() != std::endian::native) { n = ::ByteSwap(n); } mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(int32_t n) { if (GetEndianness() != std::endian::native) { n = ::ByteSwap(n); } mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(int64_t n) { if (GetEndianness() != std::endian::native) { n = ::ByteSwap(n); } mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(uint8_t n) { mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(uint16_t n) { if (GetEndianness() != std::endian::native) { n = ::ByteSwap(n); } mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(uint32_t n) { if (GetEndianness() != std::endian::native) { n = ::ByteSwap(n); } mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(uint64_t n) { if (GetEndianness() != std::endian::native) { n = ::ByteSwap(n); } mBackend.WriteBytes(sizeof(n), reinterpret_cast(&n)); } void OutputDataStream::Write(float n) { auto buffer = std::bit_cast(n); if (GetEndianness() != std::endian::native) { buffer = ::ByteSwap(buffer); } mBackend.WriteBytes(sizeof(buffer), reinterpret_cast(&buffer)); } void OutputDataStream::Write(double n) { auto buffer = std::bit_cast(n); if (GetEndianness() != std::endian::native) { buffer = ::ByteSwap(buffer); } mBackend.WriteBytes(sizeof(buffer), reinterpret_cast(&buffer)); }