From 17459c4026aaa9f8e53d9dcbf32464a4de18836e Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Thu, 12 Jun 2025 21:38:47 +0200 Subject: [PATCH] use VarInt --- src/Common/Compression.cpp | 27 ++++++------------- src/Common/Compression.h | 7 ----- src/Common/VarInt.cpp | 48 +++++++++++++++++++++++++++++++++ src/Common/VarInt.h | 54 ++++++++++++++++++++++++++++++++++++++ src/Pieces/PiecesFiles.cpp | 2 +- 5 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 src/Common/VarInt.cpp create mode 100644 src/Common/VarInt.h diff --git a/src/Common/Compression.cpp b/src/Common/Compression.cpp index f09c6d1..22dc199 100644 --- a/src/Common/Compression.cpp +++ b/src/Common/Compression.cpp @@ -1,5 +1,7 @@ #include "Compression.h" +#include "VarInt.h" + #include #include @@ -33,10 +35,7 @@ DataBuffer Compress(const DataBuffer& buffer) { if (buffer.GetSize() < COMPRESSION_THRESHOLD) { // Don't compress since it's a small packet - std::uint64_t compressedDataLength = 0; - std::uint64_t packetLength = compressedDataLength + buffer.GetSize(); - - packet << packetLength; + VarInt compressedDataLength = 0; packet << compressedDataLength; packet << buffer; return packet; @@ -44,22 +43,19 @@ DataBuffer Compress(const DataBuffer& buffer) { DataBuffer compressedData = Deflate(buffer.data(), buffer.GetSize()); - std::uint64_t uncompressedDataLength = buffer.GetSize(); - std::uint64_t packetLength = uncompressedDataLength + compressedData.GetSize(); - - packet << packetLength; + VarInt uncompressedDataLength = buffer.GetSize(); packet << uncompressedDataLength; packet.WriteSome(compressedData.data(), compressedData.GetSize()); return packet; } DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) { - std::uint64_t uncompressedLength; + VarInt uncompressedLength; buffer >> uncompressedLength; - std::uint64_t compressedLength = packetLength - uncompressedLength; + std::uint64_t compressedLength = packetLength - uncompressedLength.GetSerializedLength(); - if (uncompressedLength == 0) { + if (uncompressedLength.GetValue() == 0) { // Data already uncompressed. Nothing to do DataBuffer ret; buffer.ReadSome(ret, compressedLength); @@ -68,12 +64,5 @@ DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) { assert(buffer.GetReadOffset() + compressedLength <= buffer.GetSize()); - return Inflate(buffer.data() + buffer.GetReadOffset(), compressedLength, uncompressedLength); -} - -DataBuffer Decompress(DataBuffer& buffer) { - std::uint64_t packetLength; - buffer >> packetLength; - - return Decompress(buffer, packetLength); + return Inflate(buffer.data() + buffer.GetReadOffset(), compressedLength, uncompressedLength.GetValue()); } diff --git a/src/Common/Compression.h b/src/Common/Compression.h index 96eff3e..37097d0 100644 --- a/src/Common/Compression.h +++ b/src/Common/Compression.h @@ -14,13 +14,6 @@ */ DataBuffer Compress(const DataBuffer& buffer); -/** - * \brief Reads the packet lenght and uncompress it - * \param buffer the data to uncompress - * \return the uncompressed data - */ -DataBuffer Decompress(DataBuffer& buffer); - /** * \brief Uncompress some data * \param buffer the data to uncompress diff --git a/src/Common/VarInt.cpp b/src/Common/VarInt.cpp new file mode 100644 index 0000000..399185a --- /dev/null +++ b/src/Common/VarInt.cpp @@ -0,0 +1,48 @@ +#include "VarInt.h" + +#include "DataBuffer.h" +#include + +static constexpr int SEGMENT_BITS = 0x7F; +static constexpr int CONTINUE_BIT = 0x80; + +std::size_t VarInt::GetSerializedLength() const { + DataBuffer buffer; + buffer << *this; + return buffer.GetSize(); +} + +DataBuffer& operator<<(DataBuffer& out, const VarInt& var) { + std::uint64_t value = var.m_Value; + while (true) { + if ((value & ~static_cast(SEGMENT_BITS)) == 0) { + out << static_cast(value); + return out; + } + + out << static_cast((value & SEGMENT_BITS) | CONTINUE_BIT); + + value >>= 7; + } +} + +DataBuffer& operator>>(DataBuffer& in, VarInt& var) { + var.m_Value = 0; + unsigned int position = 0; + std::uint8_t currentByte; + + while (true) { + in.ReadSome(¤tByte, 1); + var.m_Value |= static_cast(currentByte & SEGMENT_BITS) << position; + + if ((currentByte & CONTINUE_BIT) == 0) + break; + + position += 7; + + if (position >= 8 * sizeof(var.m_Value)) + throw std::runtime_error("VarInt is too big"); + } + + return in; +} diff --git a/src/Common/VarInt.h b/src/Common/VarInt.h new file mode 100644 index 0000000..84c3969 --- /dev/null +++ b/src/Common/VarInt.h @@ -0,0 +1,54 @@ +#pragma once + +/** + * \file VarInt.h + * \brief File containing the blitz::VarInt class + */ + +#include +#include + +class DataBuffer; + +/** + * \class VarInt + * \brief Variable-length format such that smaller numbers use fewer bytes. + */ +class VarInt { + private: + std::uint64_t m_Value; + + public: + VarInt() : m_Value(0) {} + /** + * \brief Construct a variable integer from a value + * \param value The value of the variable integer + */ + VarInt(std::uint64_t value) : m_Value(value) {} + + /** + * \brief Get the value of the variable integer + */ + std::uint64_t GetValue() const { + return m_Value; + } + + /** + * \brief Get the length of the serialized variable integer + */ + std::size_t GetSerializedLength() const; + + /** + * \brief Serialize the variable integer + * \param out The buffer to write the serialized variable integer to + * \param var The variable integer to serialize + */ + friend DataBuffer& operator<<(DataBuffer& out, const VarInt& var); + + /** + * \brief Deserialize the variable integer + * \param in The buffer to read the serialized variable integer from + * \param var The variable integer to deserialize + */ + friend DataBuffer& operator>>(DataBuffer& in, VarInt& var); +}; diff --git a/src/Pieces/PiecesFiles.cpp b/src/Pieces/PiecesFiles.cpp index bebff11..6500f41 100644 --- a/src/Pieces/PiecesFiles.cpp +++ b/src/Pieces/PiecesFiles.cpp @@ -73,7 +73,7 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector& pieces, std: if(!compressed.ReadFile(filePath)) return false; - DataBuffer buffer = Decompress(compressed); + DataBuffer buffer = Decompress(compressed, compressed.GetSize()); std::ifstream piecesFile(filePath, std::ios::binary); if (!piecesFile.good()) {