diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 256e3b742..34a22015b 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -2,8 +2,8 @@ add_library(common align.h assert.cpp assert.h - binary_span_reader_writer.cpp - binary_span_reader_writer.h + binary_reader_writer.cpp + binary_reader_writer.h bitfield.h bitutils.h build_timestamp.h diff --git a/src/common/binary_reader_writer.cpp b/src/common/binary_reader_writer.cpp new file mode 100644 index 000000000..9c357876e --- /dev/null +++ b/src/common/binary_reader_writer.cpp @@ -0,0 +1,428 @@ +// SPDX-FileCopyrightText: 2024 Connor McLaughlin +// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) + +#include "binary_reader_writer.h" +#include "assert.h" +#include "error.h" +#include "small_string.h" + +#include "common/file_system.h" + +BinarySpanReader::BinarySpanReader() = default; + +BinarySpanReader::BinarySpanReader(std::span buf) : m_buf(buf) +{ +} + +BinarySpanReader::BinarySpanReader(BinarySpanReader&& move) : m_buf(std::move(move.m_buf)), m_pos(move.m_pos) +{ + move.m_pos = 0; +} + +BinarySpanReader& BinarySpanReader::operator=(BinarySpanReader&& move) +{ + m_buf = std::move(move.m_buf); + m_pos = move.m_pos; + move.m_pos = 0; + return *this; +} + +bool BinarySpanReader::PeekCString(std::string_view* dst) +{ + size_t pos = m_pos; + size_t size = 0; + while (pos < m_buf.size()) + { + if (m_buf[pos] == 0) + break; + + pos++; + size++; + } + + if (pos == m_buf.size()) + return false; + + *dst = std::string_view(reinterpret_cast(&m_buf[m_pos]), size); + return true; +} + +bool BinarySpanReader::PeekSizePrefixedString(std::string_view* dst) +{ + u32 length; + if (!PeekU32(&length) || (m_pos + sizeof(length) + length) > m_buf.size()) [[unlikely]] + return false; + + *dst = std::string_view(reinterpret_cast(&m_buf[m_pos + sizeof(length)]), length); + return true; +} + +std::span BinarySpanReader::GetRemainingSpan(size_t size) const +{ + DebugAssert(size <= GetBufferRemaining()); + return m_buf.subspan(m_pos, size); +} + +std::span BinarySpanReader::GetRemainingSpan() const +{ + return m_buf.subspan(m_pos, m_buf.size() - m_pos); +} + +void BinarySpanReader::IncrementPosition(size_t size) +{ + DebugAssert(size < GetBufferRemaining()); + m_pos += size; +} + +bool BinarySpanReader::ReadCString(std::string* dst) +{ + std::string_view sv; + if (!PeekCString(&sv)) + return false; + + dst->assign(sv); + m_pos += sv.size() + 1; + return true; +} + +bool BinarySpanReader::ReadCString(std::string_view* dst) +{ + if (!PeekCString(dst)) + return false; + + m_pos += dst->size() + 1; + return true; +} + +bool BinarySpanReader::ReadCString(SmallStringBase* dst) +{ + std::string_view sv; + if (!PeekCString(&sv)) + return false; + + dst->assign(sv); + m_pos += sv.size() + 1; + return true; +} + +bool BinarySpanReader::ReadSizePrefixedString(std::string* dst) +{ + std::string_view sv; + if (!PeekSizePrefixedString(&sv)) + return false; + + dst->assign(sv); + m_pos += sizeof(u32) + sv.size(); + return true; +} + +bool BinarySpanReader::ReadSizePrefixedString(std::string_view* dst) +{ + if (!PeekSizePrefixedString(dst)) + return false; + + m_pos += sizeof(u32) + dst->size(); + return true; +} + +bool BinarySpanReader::ReadSizePrefixedString(SmallStringBase* dst) +{ + std::string_view sv; + if (!PeekSizePrefixedString(&sv)) + return false; + + dst->assign(sv); + m_pos += sizeof(u32) + sv.size(); + return true; +} + +std::string_view BinarySpanReader::ReadCString() +{ + std::string_view ret; + if (PeekCString(&ret)) + m_pos += ret.size() + 1; + return ret; +} + +std::string_view BinarySpanReader::ReadSizePrefixedString() +{ + std::string_view ret; + if (PeekSizePrefixedString(&ret)) + m_pos += sizeof(u32) + ret.size(); + return ret; +} + +bool BinarySpanReader::PeekCString(std::string* dst) +{ + std::string_view sv; + if (!PeekCString(&sv)) + return false; + + dst->assign(sv); + return true; +} + +bool BinarySpanReader::PeekCString(SmallStringBase* dst) +{ + std::string_view sv; + if (!PeekCString(&sv)) + return false; + + dst->assign(sv); + return true; +} + +bool BinarySpanReader::PeekSizePrefixedString(std::string* dst) +{ + std::string_view sv; + if (!PeekSizePrefixedString(&sv)) + return false; + + dst->assign(sv); + return true; +} + +bool BinarySpanReader::PeekSizePrefixedString(SmallStringBase* dst) +{ + std::string_view sv; + if (!PeekSizePrefixedString(&sv)) + return false; + + dst->assign(sv); + return true; +} + +BinarySpanWriter::BinarySpanWriter() = default; + +BinarySpanWriter::BinarySpanWriter(std::span buf) : m_buf(buf) +{ +} + +BinarySpanWriter::BinarySpanWriter(BinarySpanWriter&& move) : m_buf(std::move(move.m_buf)), m_pos(move.m_pos) +{ + move.m_pos = 0; +} + +BinarySpanWriter& BinarySpanWriter::operator=(BinarySpanWriter&& move) +{ + m_buf = std::move(move.m_buf); + m_pos = move.m_pos; + move.m_pos = 0; + return *this; +} + +std::span BinarySpanWriter::GetRemainingSpan(size_t size) const +{ + DebugAssert(size <= GetBufferRemaining()); + return m_buf.subspan(m_pos, size); +} + +std::span BinarySpanWriter::GetRemainingSpan() const +{ + return m_buf.subspan(m_pos, m_buf.size() - m_pos); +} + +void BinarySpanWriter::IncrementPosition(size_t size) +{ + DebugAssert(size < GetBufferRemaining()); + m_pos += size; +} + +bool BinarySpanWriter::WriteCString(std::string_view val) +{ + if ((m_pos + val.size() + 1) > m_buf.size()) [[unlikely]] + return false; + + if (!val.empty()) + std::memcpy(&m_buf[m_pos], val.data(), val.size()); + + m_buf[m_pos + val.size()] = 0; + m_pos += val.size() + 1; + return true; +} + +bool BinarySpanWriter::WriteSizePrefixedString(std::string_view val) +{ + if (val.size() > std::numeric_limits::max() || (m_pos + sizeof(u32) + val.size()) > m_buf.size()) [[unlikely]] + return false; + + const u32 usize = static_cast(val.size()); + std::memcpy(&m_buf[m_pos], &usize, sizeof(usize)); + m_pos += sizeof(usize); + if (val.size() > 0) + { + std::memcpy(&m_buf[m_pos], val.data(), val.size()); + m_pos += val.size(); + } + + return true; +} + +BinaryFileReader::BinaryFileReader() : m_fp(nullptr), m_size(0), m_good(false) +{ +} + +BinaryFileReader::BinaryFileReader(std::FILE* fp) + : m_fp(fp), m_size(fp ? FileSystem::FSize64(fp) : 0), m_good(fp != nullptr) +{ +} + +BinaryFileReader::BinaryFileReader(BinaryFileReader&& move) : m_fp(move.m_fp), m_size(move.m_size), m_good(move.m_good) +{ + move.m_fp = nullptr; + move.m_size = 0; + move.m_good = false; +} + +BinaryFileReader& BinaryFileReader::operator=(BinaryFileReader&& move) +{ + m_fp = move.m_fp; + m_size = move.m_size; + m_good = move.m_good; + + move.m_fp = nullptr; + move.m_size = 0; + move.m_good = false; + + return *this; +} + +bool BinaryFileReader::IsAtEnd() +{ + return (FileSystem::FTell64(m_fp) == m_size); +} + +bool BinaryFileReader::ReadCString(std::string* dst) +{ + dst->clear(); + + while (m_good) + { + u8 val; + if ((m_good = std::fread(&val, sizeof(val), 1, m_fp) == 1)) + { + if (val == 0) + break; + else + dst->push_back(static_cast(val)); + } + } + + return m_good; +} + +bool BinaryFileReader::ReadCString(SmallStringBase* dst) +{ + dst->clear(); + + while (m_good) + { + u8 val; + if ((m_good = std::fread(&val, sizeof(val), 1, m_fp) == 1)) + { + if (val == 0) + break; + else + dst->push_back(static_cast(val)); + } + } + + return m_good; +} + +bool BinaryFileReader::ReadSizePrefixedString(std::string* dst) +{ + u32 length; + if (!ReadU32(&length)) [[unlikely]] + return false; + + dst->resize(length); + return (length == 0 || Read(dst->data(), dst->length())); +} + +bool BinaryFileReader::ReadSizePrefixedString(SmallStringBase* dst) +{ + u32 length; + if (!ReadU32(&length)) [[unlikely]] + return false; + + dst->resize(length); + return (length == 0 || Read(dst->data(), dst->length())); +} + +std::string BinaryFileReader::ReadCString() +{ + std::string ret; + if (!ReadCString(&ret)) + ret = {}; + return ret; +} + +std::string BinaryFileReader::ReadSizePrefixedString() +{ + std::string ret; + if (!ReadSizePrefixedString(&ret)) + ret = {}; + return ret; +} + +BinaryFileWriter::BinaryFileWriter() : m_fp(nullptr), m_good(false) +{ +} + +BinaryFileWriter::BinaryFileWriter(std::FILE* fp) : m_fp(fp), m_good(fp != nullptr) +{ +} + +BinaryFileWriter::BinaryFileWriter(BinaryFileWriter&& move) : m_fp(move.m_fp), m_good(move.m_good) +{ + move.m_fp = nullptr; + move.m_good = false; +} + +BinaryFileWriter& BinaryFileWriter::operator=(BinaryFileWriter&& move) +{ + m_fp = move.m_fp; + m_good = move.m_good; + + move.m_fp = nullptr; + move.m_good = false; + + return *this; +} + +bool BinaryFileWriter::WriteCString(std::string_view val) +{ + if (!val.empty() && (!m_good && std::fwrite(val.data(), val.length(), 1, m_fp) != 1)) [[unlikely]] + return false; + + const u8 terminator = 0; + return (m_good = (m_good && std::fwrite(&terminator, 1, 1, m_fp) == 1)); +} + +bool BinaryFileWriter::WriteSizePrefixedString(std::string_view val) +{ + if (val.size() > std::numeric_limits::max()) [[unlikely]] + return false; + + const u32 usize = static_cast(val.size()); + return (m_good = (m_good && std::fwrite(&usize, sizeof(usize), 1, m_fp) == 1 && + (val.empty() || std::fwrite(val.data(), val.size(), 1, m_fp) == 1))); +} + +bool BinaryFileWriter::Flush(Error* error) +{ + if (!m_good) + { + Error::SetStringView(error, "Write error previously occurred."); + return false; + } + + if (!(m_good = (m_good && std::fflush(m_fp) == 0))) + { + Error::SetErrno(error, "fflush() failed: ", errno); + return false; + } + + return true; +} diff --git a/src/common/binary_reader_writer.h b/src/common/binary_reader_writer.h new file mode 100644 index 000000000..9c0c667a1 --- /dev/null +++ b/src/common/binary_reader_writer.h @@ -0,0 +1,367 @@ +// SPDX-FileCopyrightText: 2024 Connor McLaughlin +// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) + +#include "types.h" + +#include +#include +#include +#include +#include + +class Error; +class SmallStringBase; + +class BinarySpanReader +{ +public: + BinarySpanReader(); + BinarySpanReader(std::span buf); + + BinarySpanReader(const BinarySpanReader&) = delete; + BinarySpanReader& operator=(const BinarySpanReader&) = delete; + + BinarySpanReader(BinarySpanReader&& move); + BinarySpanReader& operator=(BinarySpanReader&& move); + + ALWAYS_INLINE const std::span& GetSpan() const { return m_buf; } + ALWAYS_INLINE bool IsValid() const { return !m_buf.empty(); } + ALWAYS_INLINE bool CheckRemaining(size_t size) { return ((m_pos + size) <= m_buf.size()); } + ALWAYS_INLINE size_t GetBufferRemaining() const { return (m_buf.size() - m_pos); } + ALWAYS_INLINE size_t GetBufferConsumed() const { return m_pos; } + + std::span GetRemainingSpan() const; + std::span GetRemainingSpan(size_t size) const; + void IncrementPosition(size_t size); + + // clang-format off + template ALWAYS_INLINE bool ReadT(T* dst) { return Read(dst, sizeof(T)); } + ALWAYS_INLINE bool ReadBool(bool* dst) { u8 val; if (!Read(&val, sizeof(val))) [[unlikely]] { return false; } *dst = (val != 0); return true; } + ALWAYS_INLINE bool ReadS8(s8* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU8(u8* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadS16(s16* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU16(u16* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadS32(s32* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU32(u32* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadS64(s64* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU64(u64* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadFloat(float* dst) { return ReadT(dst); } + bool ReadCString(std::string* dst); + bool ReadCString(std::string_view* dst); + bool ReadCString(SmallStringBase* dst); + bool ReadSizePrefixedString(std::string* dst); + bool ReadSizePrefixedString(std::string_view* dst); + bool ReadSizePrefixedString(SmallStringBase* dst); + + template ALWAYS_INLINE T ReadT() { T ret; if (!Read(&ret, sizeof(ret))) [[unlikely]] { ret = {}; } return ret; } + ALWAYS_INLINE bool ReadBool() { return (ReadT() != 0); } + ALWAYS_INLINE s8 ReadS8() { return ReadT(); } + ALWAYS_INLINE u8 ReadU8() { return ReadT(); } + ALWAYS_INLINE s16 ReadS16() { return ReadT(); } + ALWAYS_INLINE u16 ReadU16() { return ReadT(); } + ALWAYS_INLINE s32 ReadS32() { return ReadT(); } + ALWAYS_INLINE u32 ReadU32() { return ReadT(); } + ALWAYS_INLINE s64 ReadS64() { return ReadT(); } + ALWAYS_INLINE u64 ReadU64() { return ReadT(); } + ALWAYS_INLINE float ReadFloat() { return ReadT(); } + std::string_view ReadCString(); + std::string_view ReadSizePrefixedString(); + + template ALWAYS_INLINE bool PeekT(T* dst) { return Peek(dst, sizeof(T)); } + ALWAYS_INLINE bool PeekBool(bool* dst) { u8 val; if (!Peek(&val, sizeof(val))) [[unlikely]] { return false; } *dst = (val != 0); return true; } + ALWAYS_INLINE bool PeekU8(u8* dst) { return PeekT(dst); } + ALWAYS_INLINE bool PeekU16(u16* dst) { return PeekT(dst); } + ALWAYS_INLINE bool PeekU32(u32* dst) { return PeekT(dst); } + ALWAYS_INLINE bool PeekU64(u64* dst) { return PeekT(dst); } + ALWAYS_INLINE bool PeekFloat(float* dst) { return PeekT(dst); } + bool PeekCString(std::string* dst); + bool PeekCString(std::string_view* dst); + bool PeekCString(SmallStringBase* dst); + bool PeekSizePrefixedString(std::string* dst); + bool PeekSizePrefixedString(std::string_view* dst); + bool PeekSizePrefixedString(SmallStringBase* dst); + + ALWAYS_INLINE BinarySpanReader& operator>>(s8& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(u8& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(s16& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(u16& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(s32& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(u32& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(s64& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(u64& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(float& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinarySpanReader& operator>>(std::string_view val) { val = ReadCString(); return *this; } + // clang-format on + + template + ALWAYS_INLINE bool ReadOptionalT(std::optional* dst) + { + u8 has_value; + if (!ReadT(&has_value)) [[unlikely]] + return false; + + if (has_value == 0) + { + dst->reset(); + return true; + } + + T value; + if (!ReadT(&value)) [[unlikely]] + return false; + + *dst = value; + return true; + } + + ALWAYS_INLINE bool Read(void* buf, size_t size) + { + if ((m_pos + size) <= m_buf.size()) [[likely]] + { + std::memcpy(buf, &m_buf[m_pos], size); + m_pos += size; + return true; + } + + return false; + } + + ALWAYS_INLINE bool Peek(void* buf, size_t size) + { + if ((m_pos + size) <= m_buf.size()) [[likely]] + { + std::memcpy(buf, &m_buf[m_pos], size); + return true; + } + + return false; + } + +private: + std::span m_buf; + size_t m_pos = 0; +}; + +class BinarySpanWriter +{ +public: + BinarySpanWriter(); + BinarySpanWriter(std::span buf); + + BinarySpanWriter(const BinarySpanWriter&) = delete; + BinarySpanWriter& operator=(const BinarySpanWriter&) = delete; + + BinarySpanWriter(BinarySpanWriter&& move); + BinarySpanWriter& operator=(BinarySpanWriter&& move); + + ALWAYS_INLINE const std::span& GetSpan() const { return m_buf; } + ALWAYS_INLINE bool IsValid() const { return !m_buf.empty(); } + ALWAYS_INLINE size_t GetBufferRemaining() const { return (m_buf.size() - m_pos); } + ALWAYS_INLINE size_t GetBufferWritten() const { return m_pos; } + + std::span GetRemainingSpan() const; + std::span GetRemainingSpan(size_t size) const; + void IncrementPosition(size_t size); + + // clang-format off + template ALWAYS_INLINE bool WriteT(T dst) { return Write(&dst, sizeof(T)); } + ALWAYS_INLINE bool WriteBool(bool val) { const bool bval = static_cast(val); return Write(&bval, sizeof(bval)); } + ALWAYS_INLINE bool WriteS8(s8 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU8(u8 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteS16(s16 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU16(u16 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteS32(s32 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU32(u32 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteS64(s64 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU64(u64 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteFloat(float val) { return WriteT(val); } + bool WriteCString(std::string_view val); + bool WriteSizePrefixedString(std::string_view val); + + ALWAYS_INLINE BinarySpanWriter& operator<<(s8 val) { WriteS8(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(u8 val) { WriteU8(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(s16 val) { WriteS16(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(u16 val) { WriteU16(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(s32 val) { WriteS32(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(u32 val) { WriteU32(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(s64 val) { WriteS64(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(u64 val) { WriteU64(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(float val) { WriteFloat(val); return *this; } + ALWAYS_INLINE BinarySpanWriter& operator<<(std::string_view val) { WriteCString(val); return *this; } + // clang-format on + + template + ALWAYS_INLINE bool WriteOptionalT(const std::optional& val) + { + return (WriteBool(val.has_value()) && (!val.has_value() || WriteT(val.value()))); + } + + ALWAYS_INLINE bool Write(const void* buf, size_t size) + { + if ((m_pos + size) <= m_buf.size()) [[likely]] + { + std::memcpy(&m_buf[m_pos], buf, size); + m_pos += size; + return true; + } + + return false; + } + +private: + std::span m_buf; + size_t m_pos = 0; +}; + +class BinaryFileReader +{ +public: + BinaryFileReader(); + BinaryFileReader(std::FILE* fp); + + BinaryFileReader(const BinaryFileReader&) = delete; + BinaryFileReader& operator=(const BinaryFileReader&) = delete; + + BinaryFileReader(BinaryFileReader&& move); + BinaryFileReader& operator=(BinaryFileReader&& move); + + ALWAYS_INLINE const std::FILE* GetFile() const { return m_fp; } + ALWAYS_INLINE bool HasError() const { return !m_good; } + ALWAYS_INLINE bool IsGood() const { return m_good; } + ALWAYS_INLINE bool IsOpen() const { return (m_fp != nullptr); } + + bool IsAtEnd(); + + // clang-format off + template ALWAYS_INLINE bool ReadT(T* dst) { return Read(dst, sizeof(T)); } + ALWAYS_INLINE bool ReadBool(bool* dst) { u8 val; if (!Read(&val, sizeof(val))) [[unlikely]] { return false; } *dst = (val != 0); return true; } + ALWAYS_INLINE bool ReadS8(s8* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU8(u8* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadS16(s16* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU16(u16* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadS32(s32* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU32(u32* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadS64(s64* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadU64(u64* dst) { return ReadT(dst); } + ALWAYS_INLINE bool ReadFloat(float* dst) { return ReadT(dst); } + bool ReadCString(std::string* dst); + bool ReadCString(SmallStringBase* dst); + bool ReadSizePrefixedString(std::string* dst); + bool ReadSizePrefixedString(SmallStringBase* dst); + + template ALWAYS_INLINE T ReadT() { T ret; if (!Read(&ret, sizeof(ret))) [[unlikely]] { ret = {}; } return ret; } + ALWAYS_INLINE bool ReadBool() { return (ReadT() != 0); } + ALWAYS_INLINE s8 ReadS8() { return ReadT(); } + ALWAYS_INLINE u8 ReadU8() { return ReadT(); } + ALWAYS_INLINE s16 ReadS16() { return ReadT(); } + ALWAYS_INLINE u16 ReadU16() { return ReadT(); } + ALWAYS_INLINE s32 ReadS32() { return ReadT(); } + ALWAYS_INLINE u32 ReadU32() { return ReadT(); } + ALWAYS_INLINE s64 ReadS64() { return ReadT(); } + ALWAYS_INLINE u64 ReadU64() { return ReadT(); } + ALWAYS_INLINE float ReadFloat() { return ReadT(); } + std::string ReadCString(); + std::string ReadSizePrefixedString(); + + ALWAYS_INLINE BinaryFileReader& operator>>(s8& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(u8& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(s16& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(u16& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(s32& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(u32& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(s64& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(u64& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(float& val) { val = ReadT(); return *this; } + ALWAYS_INLINE BinaryFileReader& operator>>(std::string_view val) { val = ReadCString(); return *this; } + // clang-format on + + template + ALWAYS_INLINE bool ReadOptionalT(std::optional* dst) + { + u8 has_value; + if (!ReadT(&has_value)) [[unlikely]] + return false; + + if (has_value == 0) + { + dst->reset(); + return true; + } + + T value; + if (!ReadT(&value)) [[unlikely]] + return false; + + *dst = value; + return true; + } + + ALWAYS_INLINE bool Read(void* buf, size_t size) { return (m_good = (m_good && std::fread(buf, size, 1, m_fp) == 1)); } + +private: + std::FILE* m_fp; + s64 m_size; + bool m_good = true; +}; + +class BinaryFileWriter +{ +public: + BinaryFileWriter(); + BinaryFileWriter(std::FILE* fp); + + BinaryFileWriter(const BinaryFileWriter&) = delete; + BinaryFileWriter& operator=(const BinaryFileWriter&) = delete; + + BinaryFileWriter(BinaryFileWriter&& move); + BinaryFileWriter& operator=(BinaryFileWriter&& move); + + ALWAYS_INLINE const std::FILE* GetFile() const { return m_fp; } + ALWAYS_INLINE bool HasError() const { return !m_good; } + ALWAYS_INLINE bool IsGood() const { return m_good; } + ALWAYS_INLINE bool IsOpen() const { return (m_fp != nullptr); } + + // clang-format off + template ALWAYS_INLINE bool WriteT(T dst) { return Write(&dst, sizeof(T)); } + ALWAYS_INLINE bool WriteBool(bool val) { const bool bval = static_cast(val); return Write(&bval, sizeof(bval)); } + ALWAYS_INLINE bool WriteS8(s8 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU8(u8 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteS16(s16 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU16(u16 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteS32(s32 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU32(u32 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteS64(s64 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteU64(u64 val) { return WriteT(val); } + ALWAYS_INLINE bool WriteFloat(float val) { return WriteT(val); } + bool WriteCString(std::string_view val); + bool WriteSizePrefixedString(std::string_view val); + + ALWAYS_INLINE BinaryFileWriter& operator<<(s8 val) { WriteS8(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(u8 val) { WriteU8(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(s16 val) { WriteS16(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(u16 val) { WriteU16(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(s32 val) { WriteS32(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(u32 val) { WriteU32(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(s64 val) { WriteS64(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(u64 val) { WriteU64(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(float val) { WriteFloat(val); return *this; } + ALWAYS_INLINE BinaryFileWriter& operator<<(std::string_view val) { WriteCString(val); return *this; } + // clang-format on + + template + ALWAYS_INLINE bool WriteOptionalT(const std::optional& val) + { + return (WriteBool(val.has_value()) && (!val.has_value() || WriteT(val.value()))); + } + + ALWAYS_INLINE bool Write(const void* buf, size_t size) + { + return (m_good = (m_good && std::fwrite(buf, size, 1, m_fp) == 1)); + } + + bool Flush(Error* error = nullptr); + +private: + std::FILE* m_fp; + bool m_good; +}; diff --git a/src/common/binary_span_reader_writer.cpp b/src/common/binary_span_reader_writer.cpp deleted file mode 100644 index a0ac8078b..000000000 --- a/src/common/binary_span_reader_writer.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Connor McLaughlin -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "binary_span_reader_writer.h" -#include "assert.h" -#include "small_string.h" - -BinarySpanReader::BinarySpanReader() = default; - -BinarySpanReader::BinarySpanReader(std::span buf) : m_buf(buf) -{ -} - -bool BinarySpanReader::PeekCString(std::string_view* dst) -{ - size_t pos = m_pos; - size_t size = 0; - while (pos < m_buf.size()) - { - if (m_buf[pos] == 0) - break; - - pos++; - size++; - } - - if (pos == m_buf.size()) - return false; - - *dst = std::string_view(reinterpret_cast(&m_buf[m_pos]), size); - return true; -} - -std::span BinarySpanReader::GetRemainingSpan(size_t size) const -{ - DebugAssert(size <= GetBufferRemaining()); - return m_buf.subspan(m_pos, size); -} - -std::span BinarySpanReader::GetRemainingSpan() const -{ - return m_buf.subspan(m_pos, m_buf.size() - m_pos); -} - -void BinarySpanReader::IncrementPosition(size_t size) -{ - DebugAssert(size < GetBufferRemaining()); - m_pos += size; -} - -bool BinarySpanReader::ReadCString(std::string* dst) -{ - std::string_view sv; - if (!PeekCString(&sv)) - return false; - - dst->assign(sv); - m_pos += sv.size() + 1; - return true; -} - -bool BinarySpanReader::ReadCString(std::string_view* dst) -{ - if (!PeekCString(dst)) - return false; - - m_pos += dst->size() + 1; - return true; -} - -bool BinarySpanReader::ReadCString(SmallStringBase* dst) -{ - std::string_view sv; - if (!PeekCString(&sv)) - return false; - - dst->assign(sv); - m_pos += sv.size() + 1; - return true; -} - -std::string_view BinarySpanReader::ReadCString() -{ - std::string_view ret; - if (PeekCString(&ret)) - m_pos += ret.size() + 1; - return ret; -} - -bool BinarySpanReader::PeekCString(std::string* dst) -{ - std::string_view sv; - if (!PeekCString(&sv)) - return false; - - dst->assign(sv); - return true; -} - -bool BinarySpanReader::PeekCString(SmallStringBase* dst) -{ - std::string_view sv; - if (!PeekCString(&sv)) - return false; - - dst->assign(sv); - m_pos += sv.size() + 1; - return true; -} - -BinarySpanWriter::BinarySpanWriter() = default; - -BinarySpanWriter::BinarySpanWriter(std::span buf) : m_buf(buf) -{ -} - -std::span BinarySpanWriter::GetRemainingSpan(size_t size) const -{ - DebugAssert(size <= GetBufferRemaining()); - return m_buf.subspan(m_pos, size); -} - -std::span BinarySpanWriter::GetRemainingSpan() const -{ - return m_buf.subspan(m_pos, m_buf.size() - m_pos); -} - -void BinarySpanWriter::IncrementPosition(size_t size) -{ - DebugAssert(size < GetBufferRemaining()); - m_pos += size; -} - -bool BinarySpanWriter::WriteCString(std::string_view val) -{ - if ((m_pos + val.size() + 1) > m_buf.size()) [[unlikely]] - return false; - - if (!val.empty()) - std::memcpy(&m_buf[m_pos], val.data(), val.size()); - - m_buf[m_pos + val.size()] = 0; - m_pos += val.size() + 1; - return true; -} diff --git a/src/common/binary_span_reader_writer.h b/src/common/binary_span_reader_writer.h deleted file mode 100644 index 643047a39..000000000 --- a/src/common/binary_span_reader_writer.h +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Connor McLaughlin -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "types.h" - -#include -#include -#include -#include - -class SmallStringBase; - -class BinarySpanReader -{ -public: - BinarySpanReader(); - BinarySpanReader(std::span buf); - - ALWAYS_INLINE const std::span& GetSpan() const { return m_buf; } - ALWAYS_INLINE bool IsValid() const { return !m_buf.empty(); } - ALWAYS_INLINE bool CheckRemaining(size_t size) { return ((m_pos + size) <= m_buf.size()); } - ALWAYS_INLINE size_t GetBufferRemaining() const { return (m_buf.size() - m_pos); } - ALWAYS_INLINE size_t GetBufferConsumed() const { return m_pos; } - - std::span GetRemainingSpan() const; - std::span GetRemainingSpan(size_t size) const; - void IncrementPosition(size_t size); - - // clang-format off - template ALWAYS_INLINE bool ReadT(T* dst) { return Read(dst, sizeof(T)); } - ALWAYS_INLINE bool ReadU8(u8* dst) { return ReadT(dst); } - ALWAYS_INLINE bool ReadU16(u16* dst) { return ReadT(dst); } - ALWAYS_INLINE bool ReadU32(u32* dst) { return ReadT(dst); } - ALWAYS_INLINE bool ReadU64(u64* dst) { return ReadT(dst); } - ALWAYS_INLINE bool ReadFloat(float* dst) { return ReadT(dst); } - bool ReadCString(std::string* dst); - bool ReadCString(std::string_view* dst); - bool ReadCString(SmallStringBase* dst); - - template ALWAYS_INLINE T ReadT() { T ret; if (!Read(&ret, sizeof(ret))) [[unlikely]] { ret = {}; } return ret; } - ALWAYS_INLINE u8 ReadU8() { return ReadT(); } - ALWAYS_INLINE u16 ReadU16() { return ReadT(); } - ALWAYS_INLINE u32 ReadU32() { return ReadT(); } - ALWAYS_INLINE u64 ReadU64() { return ReadT(); } - ALWAYS_INLINE float ReadFloat() { return ReadT(); } - std::string_view ReadCString(); - - template ALWAYS_INLINE bool PeekT(T* dst) { return Peek(dst, sizeof(T)); } - ALWAYS_INLINE bool PeekU8(u8* dst) { return PeekT(dst); } - ALWAYS_INLINE bool PeekU16(u16* dst) { return PeekT(dst); } - ALWAYS_INLINE bool PeekU32(u32* dst) { return PeekT(dst); } - ALWAYS_INLINE bool PeekU64(u64* dst) { return PeekT(dst); } - ALWAYS_INLINE bool PeekFloat(float* dst) { return PeekT(dst); } - bool PeekCString(std::string* dst); - bool PeekCString(std::string_view* dst); - bool PeekCString(SmallStringBase* dst); - - ALWAYS_INLINE BinarySpanReader& operator>>(u8& val) { val = ReadT(); return *this; } - ALWAYS_INLINE BinarySpanReader& operator>>(u16& val) { val = ReadT(); return *this; } - ALWAYS_INLINE BinarySpanReader& operator>>(u32& val) { val = ReadT(); return *this; } - ALWAYS_INLINE BinarySpanReader& operator>>(u64& val) { val = ReadT(); return *this; } - ALWAYS_INLINE BinarySpanReader& operator>>(float& val) { val = ReadT(); return *this; } - ALWAYS_INLINE BinarySpanReader& operator>>(std::string_view val) { val = ReadCString(); return *this; } - // clang-format on - -private: - ALWAYS_INLINE bool Read(void* buf, size_t size) - { - if ((m_pos + size) <= m_buf.size()) [[likely]] - { - std::memcpy(buf, &m_buf[m_pos], size); - m_pos += size; - return true; - } - - return false; - } - - ALWAYS_INLINE bool Peek(void* buf, size_t size) - { - if ((m_pos + size) <= m_buf.size()) [[likely]] - { - std::memcpy(buf, &m_buf[m_pos], size); - return true; - } - - return false; - } - -private: - std::span m_buf; - size_t m_pos = 0; -}; - -class BinarySpanWriter -{ -public: - BinarySpanWriter(); - BinarySpanWriter(std::span buf); - - ALWAYS_INLINE const std::span& GetSpan() const { return m_buf; } - ALWAYS_INLINE bool IsValid() const { return !m_buf.empty(); } - ALWAYS_INLINE size_t GetBufferRemaining() const { return (m_buf.size() - m_pos); } - ALWAYS_INLINE size_t GetBufferWritten() const { return m_pos; } - - std::span GetRemainingSpan() const; - std::span GetRemainingSpan(size_t size) const; - void IncrementPosition(size_t size); - - // clang-format off - template ALWAYS_INLINE bool WriteT(T dst) { return Write(&dst, sizeof(T)); } - ALWAYS_INLINE bool WriteU8(u8 val) { return WriteT(val); } - ALWAYS_INLINE bool WriteU16(u16 val) { return WriteT(val); } - ALWAYS_INLINE bool WriteU32(u32 val) { return WriteT(val); } - ALWAYS_INLINE bool WriteU64(u64 val) { return WriteT(val); } - ALWAYS_INLINE bool WriteFloat(float val) { return WriteT(val); } - bool WriteCString(std::string_view val); - - ALWAYS_INLINE BinarySpanWriter& operator<<(u8 val) { WriteU8(val); return *this; } - ALWAYS_INLINE BinarySpanWriter& operator<<(u16 val) { WriteU16(val); return *this; } - ALWAYS_INLINE BinarySpanWriter& operator<<(u32 val) { WriteU32(val); return *this; } - ALWAYS_INLINE BinarySpanWriter& operator<<(u64 val) { WriteU64(val); return *this; } - ALWAYS_INLINE BinarySpanWriter& operator<<(float val) { WriteFloat(val); return *this; } - ALWAYS_INLINE BinarySpanWriter& operator<<(std::string_view val) { WriteCString(val); return *this; } - // clang-format on - -private: - ALWAYS_INLINE bool Write(void* buf, size_t size) - { - if ((m_pos + size) <= m_buf.size()) [[likely]] - { - std::memcpy(&m_buf[m_pos], buf, size); - m_pos += size; - return true; - } - - return false; - } - -private: - std::span m_buf; - size_t m_pos = 0; -}; diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index a8ebe6090..3118c7e8e 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -38,7 +38,7 @@ - + @@ -66,7 +66,7 @@ - + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 83084db04..f430ed1b7 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -44,7 +44,7 @@ thirdparty - + @@ -77,7 +77,7 @@ thirdparty - + diff --git a/src/common/heap_array.h b/src/common/heap_array.h index 9a5a6a02d..9075a982a 100644 --- a/src/common/heap_array.h +++ b/src/common/heap_array.h @@ -321,6 +321,22 @@ public: std::span span() { return std::span(m_data, m_size); } std::span cspan() const { return std::span(m_data, m_size); } + std::span span(size_t offset, size_t size = static_cast(-1)) + { + std::span ret; + if (offset < m_size) [[likely]] + ret = std::span(m_data + offset, std::min(m_size - offset, size)); + return ret; + } + + std::span cspan(size_t offset, size_t size = static_cast(-1)) const + { + std::span ret; + if (offset < m_size) [[likely]] + ret = std::span(m_data + offset, std::min(m_size - offset, size)); + return ret; + } + this_type& operator=(const this_type& rhs) { assign(rhs); diff --git a/src/core/pine_server.cpp b/src/core/pine_server.cpp index 4ebde72cc..455d9594b 100644 --- a/src/core/pine_server.cpp +++ b/src/core/pine_server.cpp @@ -12,7 +12,7 @@ #include "util/platform_misc.h" #include "util/sockets.h" -#include "common/binary_span_reader_writer.h" +#include "common/binary_reader_writer.h" #include "common/error.h" #include "common/file_system.h" #include "common/log.h"