aboutsummaryrefslogtreecommitdiff
path: root/app/source/Cplt/Utils/IO/DataStream.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-06-30 21:38:53 -0700
committerrtk0c <[email protected]>2022-06-30 21:38:53 -0700
commit7fe47a9d5b1727a61dc724523b530762f6d6ba19 (patch)
treee95be6e66db504ed06d00b72c579565bab873277 /app/source/Cplt/Utils/IO/DataStream.cpp
parent2cf952088d375ac8b2f45b144462af0953436cff (diff)
Restructure project
Diffstat (limited to 'app/source/Cplt/Utils/IO/DataStream.cpp')
-rw-r--r--app/source/Cplt/Utils/IO/DataStream.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/app/source/Cplt/Utils/IO/DataStream.cpp b/app/source/Cplt/Utils/IO/DataStream.cpp
new file mode 100644
index 0000000..c0797e3
--- /dev/null
+++ b/app/source/Cplt/Utils/IO/DataStream.cpp
@@ -0,0 +1,283 @@
+#include "DataStream.hpp"
+
+#include <bit>
+#include <limits>
+#include <utility>
+
+static_assert(std::numeric_limits<float>::is_iec559, "Non IEE754/IEC559 'float' is not supported.");
+static_assert(std::numeric_limits<double>::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<std::byte*>(n);
+ std::swap(bytes[0], bytes[1]);
+ return n;
+}
+
+static uint32_t ByteSwap(uint32_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_ulong(n);
+#else
+ return __builtin_bswap32(n);
+#endif
+}
+
+static uint64_t ByteSwap(uint64_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_uint64(n);
+#else
+ return __builtin_bswap64(n);
+#endif
+}
+
+template <class TSigned>
+static TSigned ByteSwap(TSigned n)
+{
+ using Unsigned = std::make_unsigned_t<TSigned>;
+
+ auto swapped = ::ByteSwap(std::bit_cast<Unsigned>(n));
+ return std::bit_cast<TSigned>(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<std::streamsize>(byteCount), reinterpret_cast<std::byte*>(buffer));
+}
+
+void InputDataStream::ReadBytes(size_t byteCount, char* buffer)
+{
+ mBackend.ReadBytes(static_cast<std::streamsize>(byteCount), reinterpret_cast<std::byte*>(buffer));
+}
+
+void InputDataStream::ReadBytes(size_t byteCount, signed char* buffer)
+{
+ mBackend.ReadBytes(static_cast<std::streamsize>(byteCount), reinterpret_cast<std::byte*>(buffer));
+}
+
+void InputDataStream::ReadBytes(size_t byteCount, unsigned char* buffer)
+{
+ mBackend.ReadBytes(static_cast<std::streamsize>(byteCount), reinterpret_cast<std::byte*>(buffer));
+}
+
+void InputDataStream::Read(int8_t& n)
+{
+ // sizeof() of a reference type yields the size of the reference
+ mBackend.ReadBytes(sizeof(n), reinterpret_cast<std::byte*>(&n));
+}
+
+void InputDataStream::Read(int16_t& n)
+{
+ int16_t tmp;
+ mBackend.ReadBytes(sizeof(tmp), reinterpret_cast<std::byte*>(&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<std::byte*>(&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<std::byte*>(&tmp));
+ if (GetEndianness() != std::endian::native) {
+ n = ::ByteSwap(tmp);
+ } else {
+ n = tmp;
+ }
+}
+
+void InputDataStream::Read(uint8_t& n)
+{
+ mBackend.ReadBytes(sizeof(n), reinterpret_cast<std::byte*>(&n));
+}
+
+void InputDataStream::Read(uint16_t& n)
+{
+ uint16_t tmp;
+ mBackend.ReadBytes(sizeof(tmp), reinterpret_cast<std::byte*>(&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<std::byte*>(&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<std::byte*>(&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<float>(buffer);
+}
+
+void InputDataStream::Read(double& n)
+{
+ uint64_t buffer;
+ Read(buffer);
+
+ if (GetEndianness() != std::endian::native) {
+ buffer = ::ByteSwap(buffer);
+ }
+
+ n = std::bit_cast<double>(buffer);
+}
+
+OutputDataStream::OutputDataStream(OutputFileStream stream)
+ : mBackend{ std::move(stream) }
+{
+}
+
+void OutputDataStream::WriteBytes(size_t byteCount, const std::byte* buffer)
+{
+ mBackend.WriteBytes(static_cast<std::streamsize>(byteCount), reinterpret_cast<const std::byte*>(buffer));
+}
+
+void OutputDataStream::WriteBytes(size_t byteCount, const char* buffer)
+{
+ mBackend.WriteBytes(static_cast<std::streamsize>(byteCount), reinterpret_cast<const std::byte*>(buffer));
+}
+
+void OutputDataStream::WriteBytes(size_t byteCount, const signed char* buffer)
+{
+ mBackend.WriteBytes(static_cast<std::streamsize>(byteCount), reinterpret_cast<const std::byte*>(buffer));
+}
+
+void OutputDataStream::WriteBytes(size_t byteCount, const unsigned char* buffer)
+{
+ mBackend.WriteBytes(static_cast<std::streamsize>(byteCount), reinterpret_cast<const std::byte*>(buffer));
+}
+
+void OutputDataStream::Write(int8_t n)
+{
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(int16_t n)
+{
+ if (GetEndianness() != std::endian::native) {
+ n = ::ByteSwap(n);
+ }
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(int32_t n)
+{
+ if (GetEndianness() != std::endian::native) {
+ n = ::ByteSwap(n);
+ }
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(int64_t n)
+{
+ if (GetEndianness() != std::endian::native) {
+ n = ::ByteSwap(n);
+ }
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(uint8_t n)
+{
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(uint16_t n)
+{
+ if (GetEndianness() != std::endian::native) {
+ n = ::ByteSwap(n);
+ }
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(uint32_t n)
+{
+ if (GetEndianness() != std::endian::native) {
+ n = ::ByteSwap(n);
+ }
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(uint64_t n)
+{
+ if (GetEndianness() != std::endian::native) {
+ n = ::ByteSwap(n);
+ }
+ mBackend.WriteBytes(sizeof(n), reinterpret_cast<const std::byte*>(&n));
+}
+
+void OutputDataStream::Write(float n)
+{
+ auto buffer = std::bit_cast<uint32_t>(n);
+ if (GetEndianness() != std::endian::native) {
+ buffer = ::ByteSwap(buffer);
+ }
+ mBackend.WriteBytes(sizeof(buffer), reinterpret_cast<const std::byte*>(&buffer));
+}
+
+void OutputDataStream::Write(double n)
+{
+ auto buffer = std::bit_cast<uint64_t>(n);
+ if (GetEndianness() != std::endian::native) {
+ buffer = ::ByteSwap(buffer);
+ }
+ mBackend.WriteBytes(sizeof(buffer), reinterpret_cast<const std::byte*>(&buffer));
+}