From 6c2ae22feba9116b1f736b701e36e74ab5b5b794 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Sat, 21 Aug 2021 14:39:17 -0700 Subject: Add read/write logic for all ints and floats --- core/src/Utils/IO/DataStream.cpp | 278 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 276 insertions(+), 2 deletions(-) (limited to 'core/src/Utils/IO/DataStream.cpp') diff --git a/core/src/Utils/IO/DataStream.cpp b/core/src/Utils/IO/DataStream.cpp index 0e0a37b..95e0b09 100644 --- a/core/src/Utils/IO/DataStream.cpp +++ b/core/src/Utils/IO/DataStream.cpp @@ -1,6 +1,280 @@ #include "DataStream.hpp" -DataStream::DataStream() - : mEndian{ LittleEndian } +#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."); + +DataStream::DataStream(std::fstream stream) + : mBackend{ std::move(stream) } + , mEndian{ std::endian::big } +{ +} + +DataStream::~DataStream() = default; + +std::endian DataStream::GetEndianness() const +{ + return mEndian; +} + +void DataStream::SetEndianness(std::endian endianness) +{ + mEndian = endianness; +} + +void DataStream::ReadBytes(size_t byteCount, std::byte* buffer) +{ + mBackend.read(reinterpret_cast(buffer), static_cast(byteCount)); +} + +void DataStream::ReadBytes(size_t byteCount, char* buffer) +{ + mBackend.read(reinterpret_cast(buffer), static_cast(byteCount)); +} + +void DataStream::ReadBytes(size_t byteCount, signed char* buffer) +{ + mBackend.read(reinterpret_cast(buffer), static_cast(byteCount)); +} + +void DataStream::ReadBytes(size_t byteCount, unsigned char* buffer) +{ + mBackend.read(reinterpret_cast(buffer), static_cast(byteCount)); +} + +void DataStream::WriteBytes(size_t byteCount, const std::byte* buffer) +{ + mBackend.write(reinterpret_cast(buffer), static_cast(byteCount)); +} + +void DataStream::WriteBytes(size_t byteCount, const char* buffer) +{ + mBackend.write(reinterpret_cast(buffer), static_cast(byteCount)); +} + +void DataStream::WriteBytes(size_t byteCount, const signed char* buffer) +{ + mBackend.write(reinterpret_cast(buffer), static_cast(byteCount)); +} + +void DataStream::WriteBytes(size_t byteCount, const unsigned char* buffer) +{ + mBackend.write(reinterpret_cast(buffer), static_cast(byteCount)); +} + +// Reading/writing signed integer byte-by-byte is fine, since the representation got fixed to 2's complements in C++20 + +uint16_t ByteSwap(uint16_t n) +{ + auto bytes = reinterpret_cast(n); + std::swap(bytes[0], bytes[1]); + return n; +} + +uint32_t ByteSwap(uint32_t n) +{ +#ifdef _MSC_VER + // TODO +#else + return __builtin_bswap32(n); +#endif +} + +uint64_t ByteSwap(uint64_t n) +{ +#ifdef _MSC_VER + // TODO +#else + return __builtin_bswap64(n); +#endif +} + +template +TSigned ByteSwap(TSigned n) +{ + using Unsigned = std::make_unsigned_t; + + auto swapped = ::ByteSwap(std::bit_cast(n)); + return std::bit_cast(swapped); +} + +void DataStream::Write(int8_t n) +{ + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Write(int16_t n) +{ + if (mEndian != std::endian::native) { + n = ::ByteSwap(n); + } + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Write(int32_t n) +{ + if (mEndian != std::endian::native) { + n = ::ByteSwap(n); + } + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Write(int64_t n) +{ + if (mEndian != std::endian::native) { + n = ::ByteSwap(n); + } + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Read(int8_t& n) +{ + // sizeof() of a reference type yields the size of the reference + mBackend.read(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Read(int16_t& n) +{ + int16_t tmp; + mBackend.read(reinterpret_cast(&tmp), sizeof(tmp)); + if (mEndian != std::endian::native) { + n = ::ByteSwap(tmp); + } else { + n = tmp; + } +} + +void DataStream::Read(int32_t& n) +{ + int32_t tmp; + mBackend.read(reinterpret_cast(&tmp), sizeof(tmp)); + if (mEndian != std::endian::native) { + n = ::ByteSwap(tmp); + } else { + n = tmp; + } +} + +void DataStream::Read(int64_t& n) +{ + int64_t tmp; + mBackend.read(reinterpret_cast(&tmp), sizeof(tmp)); + if (mEndian != std::endian::native) { + n = ::ByteSwap(tmp); + } else { + n = tmp; + } +} + +void DataStream::Write(uint8_t n) +{ + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Write(uint16_t n) +{ + if (mEndian != std::endian::native) { + n = ::ByteSwap(n); + } + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Write(uint32_t n) +{ + if (mEndian != std::endian::native) { + n = ::ByteSwap(n); + } + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Write(uint64_t n) { + if (mEndian != std::endian::native) { + n = ::ByteSwap(n); + } + mBackend.write(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Read(uint8_t& n) +{ + mBackend.read(reinterpret_cast(&n), sizeof(n)); +} + +void DataStream::Read(uint16_t& n) +{ + uint16_t tmp; + mBackend.read(reinterpret_cast(&tmp), sizeof(tmp)); + if (mEndian != std::endian::native) { + n = ::ByteSwap(tmp); + } else { + n = tmp; + } +} + +void DataStream::Read(uint32_t& n) +{ + uint32_t tmp; + mBackend.read(reinterpret_cast(&tmp), sizeof(tmp)); + if (mEndian != std::endian::native) { + n = ::ByteSwap(tmp); + } else { + n = tmp; + } +} + +void DataStream::Read(uint64_t& n) +{ + uint64_t tmp; + mBackend.read(reinterpret_cast(&tmp), sizeof(tmp)); + if (mEndian != std::endian::native) { + n = ::ByteSwap(tmp); + } else { + n = tmp; + } +} + +void DataStream::Write(float n) +{ + auto buffer = std::bit_cast(n); + if (mEndian != std::endian::native) { + buffer = ::ByteSwap(buffer); + } + mBackend.read(reinterpret_cast(&buffer), sizeof(buffer)); +} + +void DataStream::Write(double n) +{ + auto buffer = std::bit_cast(n); + if (mEndian != std::endian::native) { + buffer = ::ByteSwap(buffer); + } + mBackend.read(reinterpret_cast(&buffer), sizeof(buffer)); +} + +void DataStream::Read(float& n) +{ + uint32_t buffer; + Read(buffer); + + if (mEndian != std::endian::native) { + buffer = ::ByteSwap(buffer); + } + + n = std::bit_cast(buffer); +} + +void DataStream::Read(double& n) +{ + uint64_t buffer; + Read(buffer); + + if (mEndian != std::endian::native) { + buffer = ::ByteSwap(buffer); + } + + n = std::bit_cast(buffer); } -- cgit v1.2.3-70-g09d2