diff --git a/include/sp/common/DataBuffer.h b/include/sp/common/DataBuffer.h index 8b5af48..e55241d 100644 --- a/include/sp/common/DataBuffer.h +++ b/include/sp/common/DataBuffer.h @@ -61,29 +61,6 @@ class DataBuffer { std::memcpy(&m_Buffer[end_pos], &a_Data, size); } - /** - * \brief Append data to the buffer (converted to big endian) - */ - template - DataBuffer& operator<<(T a_Data) { - SwapBytes(a_Data); - Append(a_Data); - return *this; - } - - /** - * \brief Append a string to the buffer - * \warning Don't use it for binary data ! - * \param str The string to append - */ - DataBuffer& operator<<(const std::string& str); - - /** - * \brief Append data to the buffer from another const buffer - * \param data The buffer to append - */ - DataBuffer& operator<<(const DataBuffer& data); - /** * \brief Read data into a_Data * \warning No endian checks @@ -95,29 +72,6 @@ class DataBuffer { m_ReadOffset += sizeof(T); } - /** - * \brief Read some data from the buffer and assign to desired variable - */ - template - DataBuffer& operator>>(T& a_Data) { - Read(a_Data); - SwapBytes(a_Data); - return *this; - } - - /** - * \brief Read some data from the buffer and assign to the new buffer - * \param data The buffer to assign - */ - DataBuffer& operator>>(DataBuffer& data); - - /** - * \brief Read a string from the buffer - * \param str The string to assign in the new buffer - * \warning Don't use it for binary data ! - */ - DataBuffer& operator>>(std::string& str); - /** * \brief Write some data to the buffer * \param buffer The buffer to write @@ -169,7 +123,6 @@ class DataBuffer { m_Buffer.reserve(amount); } - /** * \brief Clear the buffer */ @@ -251,6 +204,8 @@ class DataBuffer { return m_Buffer == other.m_Buffer; } + void insert(iterator a_DestBegin, const_iterator a_SrcBegin, const_iterator a_SrcEnd); + iterator begin(); iterator end(); const_iterator begin() const; @@ -258,10 +213,9 @@ class DataBuffer { }; /** - * \brief Operator << to write a DataBuffer to an ostream + * \brief Append data to the buffer from another const buffer + * \param data The buffer to append */ -std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer); +DataBuffer& operator<<(DataBuffer& a_Buffer, const DataBuffer& data); } // namespace sp - -#include "DataBuffer.inl" \ No newline at end of file diff --git a/include/sp/common/DataBuffer.inl b/include/sp/common/DataBuffer.inl deleted file mode 100644 index f8dead8..0000000 --- a/include/sp/common/DataBuffer.inl +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once - -namespace sp { - -/** - * \brief Append a pointer to the buffer - * \param data The data to append - */ -template >> -DataBuffer& operator<<(DataBuffer& buffer, const std::shared_ptr& data) { - return buffer << *data; -} - -/** - * \brief Append a pointer to the buffer - * \param data The data to append - */ -template >> -DataBuffer& operator<<(DataBuffer& buffer, const std::unique_ptr& data) { - return buffer << *data; -} - -/** - * \brief Append a vector to the buffer by first writing the size - * \param data The vector to append - */ -template -DataBuffer& operator<<(DataBuffer& buffer, const std::vector& data) { - buffer << VarInt{data.size()}; - for (const auto& element : data) { - buffer << element; - } - return buffer; -} - -/** - * \brief Append a list to the buffer by first writing the size - * \param data The list to append - */ -template -DataBuffer& operator<<(DataBuffer& buffer, const std::list& data) { - buffer << VarInt{data.size()}; - for (const auto& element : data) { - buffer << element; - } - return buffer; -} - -/** - * \brief Append a map to the buffer by first writing the size - * \param data The map to append - */ -template -DataBuffer& operator<<(DataBuffer& buffer, const std::map& data) { - buffer << VarInt{data.size()}; - for (const auto& [key, value] : data) { - buffer << key << value; - } - return buffer; -} - -/** - * \brief Append a map to the buffer by first writing the size - * \param data The map to append - */ -template -DataBuffer& operator<<(DataBuffer& buffer, const std::unordered_map& data) { - buffer << VarInt{data.size()}; - for (const auto& [key, value] : data) { - buffer << key << value; - } - return buffer; -} - -/** - * \brief Append a pair to the buffer - * \param data The pair to append - */ -template -DataBuffer& operator<<(DataBuffer& buffer, const std::pair& data) { - return buffer << data.first << data.second; -} - -/** - * \brief Append an array to the buffer by first writing the size - * \param data The buffer to append - */ -template -DataBuffer& operator<<(DataBuffer& buffer, const std::array& data) { - for (const auto& element : data) { - buffer << element; - } - return buffer; -} - -/** - * \brief Read a pointer - */ -template >> -DataBuffer& operator>>(DataBuffer& buffer, std::shared_ptr& data) { - data = std::make_shared(); - return buffer >> *data; -} - -/** - * \brief Read a pointer - */ -template >> -DataBuffer& operator>>(DataBuffer& buffer, std::unique_ptr& data) { - data = std::make_unique(); - return buffer >> *data; -} - -/** - * \brief Read a vector (size + data) from the buffer - * \pre The vector is assumed to be empty - */ -template -DataBuffer& operator>>(DataBuffer& buffer, std::vector& data) { - VarInt arraySize; - buffer >> arraySize; - for (std::size_t i = 0; i < arraySize.GetValue(); i++) { - T newElement; - buffer >> newElement; - data.push_back(newElement); - } - return buffer; -} - -/** - * \brief Read a list (size + data) from the buffer - * \pre The list is assumed to be empty - */ -template -DataBuffer& operator>>(DataBuffer& buffer, std::list& data) { - VarInt arraySize; - buffer >> arraySize; - for (std::size_t i = 0; i < arraySize.GetValue(); i++) { - T newElement; - buffer >> newElement; - data.push_back(newElement); - } - return buffer; -} - -/** - * \brief Read a map (size + data) from the buffer - * \pre The map is assumed to be empty - */ -template -DataBuffer& operator>>(DataBuffer& buffer, std::map& data) { - VarInt mapSize; - buffer >> mapSize; - for (std::size_t i = 0; i < mapSize.GetValue(); i++) { - K newKey; - V newValue; - buffer >> newKey >> newValue; - data.emplace(newKey, newValue); - } - return buffer; -} - -/** - * \brief Read a map (size + data) from the buffer - * \pre The map is assumed to be empty - */ -template -DataBuffer& operator>>(DataBuffer& buffer, std::unordered_map& data) { - VarInt mapSize; - buffer >> mapSize; - for (std::size_t i = 0; i < mapSize.GetValue(); i++) { - K newKey; - V newValue; - buffer >> newKey >> newValue; - data.emplace(newKey, newValue); - } - return buffer; -} - -/** - * \brief Read a pair - */ -template -DataBuffer& operator>>(DataBuffer& buffer, std::pair& data) { - return buffer >> data.first >> data.second; -} - -/** - * \brief Read an array from the buffer - */ -template -DataBuffer& operator>>(DataBuffer& buffer, std::array& data) { - for (std::size_t i = 0; i < Size; i++) { - T newElement; - buffer >> newElement; - data[i] = newElement; - } - return buffer; -} - -} // namespace sp \ No newline at end of file diff --git a/include/sp/common/DataBufferOperators.h b/include/sp/common/DataBufferOperators.h new file mode 100644 index 0000000..e47d3a1 --- /dev/null +++ b/include/sp/common/DataBufferOperators.h @@ -0,0 +1,268 @@ +#pragma once + +#include +#include + +namespace sp { + +template +using is_default_serializable = std::bool_constant<(std::is_class_v && std::is_aggregate_v) || !std::is_class_v>; + +template +static constexpr bool is_default_serializable_v = is_default_serializable::value; + + +/** + * \brief Append data to the buffer (converted to big endian) + */ +template >> +DataBuffer& operator<<(DataBuffer& a_Buffer, const T& a_Data) { + if constexpr (std::is_class_v) { + boost::pfr::for_each_field(a_Data, [&a_Buffer](const auto& a_Field) { a_Buffer << a_Field; }); + } else { + a_Buffer.Append(a_Data); + SwapBytes(a_Buffer.data() + a_Buffer.GetReadOffset() - sizeof(T), a_Buffer.data() + a_Buffer.GetReadOffset()); + } + return a_Buffer; +} + +/** + * \brief Append a string to the buffer + * \warning Don't use it for binary data ! + * \param str The string to append + */ +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::string& str); + +/** + * \brief Operator << to write a DataBuffer to an ostream + */ +std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer); + +/** + * \brief Append a pointer to the buffer + * \param data The data to append + */ +template >> +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::shared_ptr& data) { + return a_Buffer << *data; +} + +/** + * \brief Append a pointer to the buffer + * \param data The data to append + */ +template >> +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::unique_ptr& data) { + return a_Buffer << *data; +} + +/** + * \brief Append a vector to the buffer by first writing the size + * \param data The vector to append + */ +template +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::vector& data) { + a_Buffer << VarInt{data.size()}; + for (const auto& element : data) { + a_Buffer << element; + } + return a_Buffer; +} + +/** + * \brief Append a list to the buffer by first writing the size + * \param data The list to append + */ +template +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::list& data) { + a_Buffer << VarInt{data.size()}; + for (const auto& element : data) { + a_Buffer << element; + } + return a_Buffer; +} + +/** + * \brief Append a map to the buffer by first writing the size + * \param data The map to append + */ +template +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::map& data) { + a_Buffer << VarInt{data.size()}; + for (const auto& [key, value] : data) { + a_Buffer << key << value; + } + return a_Buffer; +} + +/** + * \brief Append a map to the buffer by first writing the size + * \param data The map to append + */ +template +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::unordered_map& data) { + a_Buffer << VarInt{data.size()}; + for (const auto& [key, value] : data) { + a_Buffer << key << value; + } + return a_Buffer; +} + +/** + * \brief Append a pair to the buffer + * \param data The pair to append + */ +template +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::pair& data) { + return a_Buffer << data.first << data.second; +} + +/** + * \brief Append an array to the buffer by first writing the size + * \param data The buffer to append + */ +template +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::array& data) { + for (const auto& element : data) { + a_Buffer << element; + } + return a_Buffer; +} + + + + + +/** + * \brief Read some data from the buffer and assign to desired variable + */ +template >> +DataBuffer& operator>>(DataBuffer& a_Buffer, T& a_Data) { + if constexpr (std::is_class_v) { + boost::pfr::for_each_field(a_Data, [&a_Buffer](auto& a_Field) { a_Buffer >> a_Field; }); + } else { + a_Buffer.Read(a_Data); + SwapBytes(a_Data); + } + return a_Buffer; +} + +/** + * \brief Read some data from the buffer and assign to the new buffer + * \param data The buffer to assign + */ +DataBuffer& operator>>(DataBuffer& a_Buffer, DataBuffer& data); + +/** + * \brief Read a string from the buffer + * \param str The string to assign in the new buffer + * \warning Don't use it for binary data ! + */ +DataBuffer& operator>>(DataBuffer& a_Buffer, std::string& str); + +/** + * \brief Read a pointer + */ +template >> +DataBuffer& operator>>(DataBuffer& a_Buffer, std::shared_ptr& data) { + data = std::make_shared(); + return a_Buffer >> *data; +} + +/** + * \brief Read a pointer + */ +template >> +DataBuffer& operator>>(DataBuffer& a_Buffer, std::unique_ptr& data) { + data = std::make_unique(); + return a_Buffer >> *data; +} + +/** + * \brief Read a vector (size + data) from the buffer + * \pre The vector is assumed to be empty + */ +template +DataBuffer& operator>>(DataBuffer& a_Buffer, std::vector& data) { + VarInt arraySize; + a_Buffer >> arraySize; + for (std::size_t i = 0; i < arraySize.GetValue(); i++) { + T newElement; + a_Buffer >> newElement; + data.push_back(newElement); + } + return a_Buffer; +} + +/** + * \brief Read a list (size + data) from the buffer + * \pre The list is assumed to be empty + */ +template +DataBuffer& operator>>(DataBuffer& a_Buffer, std::list& data) { + VarInt arraySize; + a_Buffer >> arraySize; + for (std::size_t i = 0; i < arraySize.GetValue(); i++) { + T newElement; + a_Buffer >> newElement; + data.push_back(newElement); + } + return a_Buffer; +} + +/** + * \brief Read a map (size + data) from the buffer + * \pre The map is assumed to be empty + */ +template +DataBuffer& operator>>(DataBuffer& a_Buffer, std::map& data) { + VarInt mapSize; + a_Buffer >> mapSize; + for (std::size_t i = 0; i < mapSize.GetValue(); i++) { + K newKey; + V newValue; + a_Buffer >> newKey >> newValue; + data.emplace(newKey, newValue); + } + return a_Buffer; +} + +/** + * \brief Read a map (size + data) from the buffer + * \pre The map is assumed to be empty + */ +template +DataBuffer& operator>>(DataBuffer& a_Buffer, std::unordered_map& data) { + VarInt mapSize; + a_Buffer >> mapSize; + for (std::size_t i = 0; i < mapSize.GetValue(); i++) { + K newKey; + V newValue; + a_Buffer >> newKey >> newValue; + data.emplace(newKey, newValue); + } + return a_Buffer; +} + +/** + * \brief Read a pair + */ +template +DataBuffer& operator>>(DataBuffer& a_Buffer, std::pair& data) { + return a_Buffer >> data.first >> data.second; +} + +/** + * \brief Read an array from the buffer + */ +template +DataBuffer& operator>>(DataBuffer& a_Buffer, std::array& data) { + for (std::size_t i = 0; i < Size; i++) { + T newElement; + a_Buffer >> newElement; + data[i] = newElement; + } + return a_Buffer; +} + +} // namespace sp \ No newline at end of file diff --git a/include/sp/io/MessageIO.h b/include/sp/io/MessageIO.h index 74df617..3c7a9e6 100644 --- a/include/sp/io/MessageIO.h +++ b/include/sp/io/MessageIO.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include namespace sp { namespace details { diff --git a/include/sp/io/MessageStream.inl b/include/sp/io/MessageStream.inl index 4a6f300..b0f27e9 100644 --- a/include/sp/io/MessageStream.inl +++ b/include/sp/io/MessageStream.inl @@ -8,7 +8,10 @@ namespace sp { template DataBuffer MessageStream::ReadAndDecapsulate() { VarInt messageLength; - messageLength.Read([this](std::uint8_t& data) { m_Stream->Read(1) >> data; }); + messageLength.Read([this](std::uint8_t& data) { + DataBuffer buffer = m_Stream->Read(1); + data = *buffer.data(); + }); std::size_t amount = messageLength.GetValue(); DataBuffer buffer = m_Stream->Read(amount); diff --git a/src/sp/common/DataBuffer.cpp b/src/sp/common/DataBuffer.cpp index 03c8a4e..b0b9bd7 100644 --- a/src/sp/common/DataBuffer.cpp +++ b/src/sp/common/DataBuffer.cpp @@ -21,33 +21,33 @@ DataBuffer::DataBuffer(const DataBuffer& other, Data::difference_type offset) : std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer)); } -DataBuffer& DataBuffer::operator<<(const std::string& str) { +DataBuffer& operator<<(DataBuffer& a_Buffer, const std::string& str) { std::size_t strlen = str.length() + 1; // including null character - Resize(GetSize() + strlen); - std::memcpy(m_Buffer.data() + GetSize() - strlen, str.data(), strlen); - return *this; + a_Buffer.Resize(a_Buffer.GetSize() + strlen); + std::memcpy(a_Buffer.data() + a_Buffer.GetSize() - strlen, str.data(), strlen); + return a_Buffer; } -DataBuffer& DataBuffer::operator<<(const DataBuffer& data) { - m_Buffer.insert(m_Buffer.end(), data.begin(), data.end()); - return *this; +DataBuffer& operator<<(DataBuffer& a_Buffer, const DataBuffer& data) { + a_Buffer.insert(a_Buffer.end(), data.begin(), data.end()); + return a_Buffer; } -DataBuffer& DataBuffer::operator>>(std::string& str) { - std::size_t stringSize = strlen(reinterpret_cast(m_Buffer.data()) + m_ReadOffset) + 1; // including null character +DataBuffer& operator>>(DataBuffer& a_Buffer, std::string& str) { + std::size_t stringSize = strlen(reinterpret_cast(a_Buffer.data()) + a_Buffer.GetReadOffset()) + 1; // including null character str.resize(stringSize); - std::copy(m_Buffer.begin() + static_cast(m_ReadOffset), - m_Buffer.begin() + static_cast(m_ReadOffset + stringSize), str.begin()); - m_ReadOffset += stringSize; + std::copy(a_Buffer.begin() + static_cast(a_Buffer.GetReadOffset()), + a_Buffer.begin() + static_cast(a_Buffer.GetReadOffset() + stringSize), str.begin()); + a_Buffer.SetReadOffset(a_Buffer.GetReadOffset() + stringSize); str.resize(stringSize - 1); - return *this; + return a_Buffer; } -DataBuffer& DataBuffer::operator>>(DataBuffer& data) { - data.Resize(GetSize() - m_ReadOffset); - std::copy(m_Buffer.begin() + static_cast(m_ReadOffset), m_Buffer.end(), data.begin()); - m_ReadOffset = m_Buffer.size(); - return *this; +DataBuffer& operator>>(DataBuffer& a_Buffer, DataBuffer& data) { + data.Resize(a_Buffer.GetSize() - a_Buffer.GetReadOffset()); + std::copy(a_Buffer.begin() + static_cast(a_Buffer.GetReadOffset()), a_Buffer.end(), data.begin()); + a_Buffer.SetReadOffset(a_Buffer.GetSize()); + return a_Buffer; } void DataBuffer::WriteSome(const char* buffer, std::size_t amount) { @@ -147,4 +147,8 @@ void DataBuffer::WriteFile(const std::string& fileName) const { file.flush(); } +void DataBuffer::insert(iterator a_DestBegin, const_iterator a_SrcBegin, const_iterator a_SrcEnd) { + m_Buffer.insert(a_DestBegin, a_SrcBegin, a_SrcEnd); +} + } // namespace sp diff --git a/src/sp/common/VarInt.cpp b/src/sp/common/VarInt.cpp index 30e2463..b9b4139 100644 --- a/src/sp/common/VarInt.cpp +++ b/src/sp/common/VarInt.cpp @@ -1,6 +1,7 @@ #include #include +#include #include namespace sp { diff --git a/test/test_message.cpp b/test/test_message.cpp index fdd0f2f..8a10ef8 100644 --- a/test/test_message.cpp +++ b/test/test_message.cpp @@ -71,7 +71,6 @@ int main() { d.Dispatch(*message); - // write tests auto compress = std::make_shared();