#pragma once /** * \file DataBuffer.h * \brief File containing the sp::DataBuffer class */ #include #include #include #include #include #include #include #include namespace sp { /** * \class DataBuffer * \brief Class used to manipulate memory */ class DataBuffer { private: typedef std::vector Data; Data m_Buffer; std::size_t m_ReadOffset; public: typedef Data::iterator iterator; typedef Data::const_iterator const_iterator; typedef Data::reference reference; typedef Data::const_reference const_reference; typedef Data::difference_type difference_type; DataBuffer(); DataBuffer(const DataBuffer& other); DataBuffer(const DataBuffer& other, difference_type offset); DataBuffer(DataBuffer&& other); DataBuffer(const std::string& str); DataBuffer& operator=(const DataBuffer& other); DataBuffer& operator=(DataBuffer&& other); /** * \brief Append data to the buffer */ template void Append(const T& data) { std::size_t size = sizeof(data); std::size_t end_pos = m_Buffer.size(); m_Buffer.resize(m_Buffer.size() + size); std::memcpy(&m_Buffer[end_pos], &data, size); } /** * \brief Append data to the buffer */ template DataBuffer& operator<<(const T& data) { Append(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 Append a vector to the buffer by first writing the size * \param data The vector to append */ template DataBuffer& operator<<(const std::vector& data) { *this << VarInt{data.size()}; for (const auto& element : data) { *this << element; } return *this; } /** * \brief Append an array to the buffer by first writing the size * \param data The buffer to append */ template DataBuffer& operator<<(const std::array& data) { for (const auto& element : data) { *this << element; } return *this; } /** * \brief Read some data from the buffer and assign to desired variable */ template DataBuffer& operator>>(T& data) { assert(m_ReadOffset + sizeof(T) <= GetSize()); data = *(reinterpret_cast(&m_Buffer[m_ReadOffset])); m_ReadOffset += sizeof(T); 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 Read a vector (size + data) from the buffer * \pre The vector is assumed to be empty */ template DataBuffer& operator>>(std::vector& data) { VarInt arraySize; *this >> arraySize; for (std::size_t i = 0; i < arraySize.GetValue(); i++) { T newElement; *this >> newElement; data.push_back(newElement); } return *this; } /** * \brief Read an array from the buffer */ template DataBuffer& operator>>(std::array& data) { for (std::size_t i = 0; i < Size; i++) { T newElement; *this >> newElement; data[i] = newElement; } return *this; } /** * \brief Write some data to the buffer * \param buffer The buffer to write * \param amount The amount of data to write */ void WriteSome(const char* buffer, std::size_t amount); /** * \brief Write some data to the buffer * \param buffer The buffer to write * \param amount The amount of data to write */ void WriteSome(const std::uint8_t* buffer, std::size_t amount); /** * \brief Read some data from the buffer * \param buffer The buffer to Read * \param amount The amount of data from the buffer */ void ReadSome(char* buffer, std::size_t amount); /** * \brief Read some data from the buffer * \param buffer The buffer to Read * \param amount The amount of data from the buffer */ void ReadSome(std::uint8_t* buffer, std::size_t amount); /** * \brief Read some data from the buffer * \param buffer The buffer to Read * \param amount The amount of data from the buffer */ void ReadSome(DataBuffer& buffer, std::size_t amount); /** * \brief Resize the buffer * \param size The new size of the buffer */ void Resize(std::size_t size) { m_Buffer.resize(size); } /** * \brief Reserve some space in the buffer * \param amount The amount of space to reserve */ void Reserve(std::size_t amount) { m_Buffer.reserve(amount); } /** * \brief Clear the buffer */ void Clear() { m_Buffer.clear(); m_ReadOffset = 0; } /** * \brief When the buffer has been read entirely */ bool IsFinished() const { return m_ReadOffset >= m_Buffer.size(); } /** * \brief Get the buffer data */ std::uint8_t* data() { return m_Buffer.data(); } /** * \brief Get the buffer data */ const std::uint8_t* data() const { return m_Buffer.data(); } /** * \brief Get the read offset */ std::size_t GetReadOffset() const { return m_ReadOffset; } /** * \brief Set the read offset * \param pos The new read offset */ void SetReadOffset(std::size_t pos); /** * \brief Get the size of the buffer */ std::size_t GetSize() const; /** * \brief Get the remaining size of the buffer */ std::size_t GetRemaining() const; /** * \brief Read a file into the buffer * \param fileName The name of the file to read */ bool ReadFile(const std::string& fileName); /** * \brief Write a file into the buffer * \param fileName The name of the file to write to */ bool WriteFile(const std::string& fileName) const; /** * \brief Allocate the buffer on the heap * \warning Don't forget to free the data ! */ std::uint8_t* HeapAllocatedData() const { std::uint8_t* newBuffer = new std::uint8_t[GetSize()]; std::memcpy(newBuffer, data(), GetSize()); return newBuffer; } /** * \brief Operator == to compare two DataBuffer */ bool operator==(const DataBuffer& other) const { return m_Buffer == other.m_Buffer; } iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; }; /** * \brief Operator << to write a DataBuffer to an ostream */ std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer); } // namespace sp