From 605a310ede1210bf0aca97277729ccc5fd49fe6f Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 26 Feb 2025 10:14:06 +0100 Subject: [PATCH] refactor io --- include/sp/io/File.h | 33 ++++++++++++++ include/sp/io/FileIO.h | 42 ----------------- include/sp/io/IOInterface.h | 76 ++++--------------------------- include/sp/io/IOInterfaceImpl.inl | 72 +++++++++++++++++++++++++++++ include/sp/io/Memory.h | 23 ++++++++++ src/sp/io/File.cpp | 31 +++++++++++++ src/sp/io/Memory.cpp | 16 +++++++ test/test_file.cpp | 7 ++- test/test_io.cpp | 30 ++---------- 9 files changed, 190 insertions(+), 140 deletions(-) create mode 100644 include/sp/io/File.h delete mode 100644 include/sp/io/FileIO.h create mode 100644 include/sp/io/Memory.h create mode 100644 src/sp/io/File.cpp create mode 100644 src/sp/io/Memory.cpp diff --git a/include/sp/io/File.h b/include/sp/io/File.h new file mode 100644 index 0000000..2b329e6 --- /dev/null +++ b/include/sp/io/File.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace sp { +namespace io { + +struct FileTag { + enum OpenMode { + In = 1, + Out = 1 << 1, + }; +}; + +template <> +class IOInterface { + private: + std::unique_ptr m_FileInput; + std::unique_ptr m_FileOutput; + + public: + IOInterface(const std::string& a_FilePath, unsigned int a_OpenMode); + IOInterface(IOInterface&& other); + + DataBuffer Read(std::size_t a_Amount); + void Write(const sp::DataBuffer& a_Data); +}; + +using File = IOInterface; + +} // namespace io +} // namespace sp diff --git a/include/sp/io/FileIO.h b/include/sp/io/FileIO.h deleted file mode 100644 index 2729616..0000000 --- a/include/sp/io/FileIO.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include - -namespace sp { - -struct FileTag {}; - -template <> -class IOInterface { - private: - std::unique_ptr m_FileInput; - std::unique_ptr m_FileOutput; - - public: - IOInterface(const std::string& fileInput, const std::string& fileOutput) { - if (!fileInput.empty()) - m_FileInput = std::make_unique(fileInput); - if (!fileOutput.empty()) - m_FileOutput = std::make_unique(fileOutput); - } - IOInterface(IOInterface&& other) : m_FileOutput(std::move(other.m_FileOutput)), m_FileInput(std::move(other.m_FileInput)) {} - - DataBuffer Read(std::size_t a_Amount) { - DataBuffer buffer; - buffer.Resize(a_Amount); - assert(m_FileInput != nullptr); - m_FileInput->read(reinterpret_cast(buffer.data()), a_Amount); - return buffer; - } - - void Write(const sp::DataBuffer& a_Data) { - assert(m_FileOutput != nullptr); - m_FileOutput->write(reinterpret_cast(a_Data.data()), a_Data.GetSize()); - m_FileOutput->flush(); - } -}; - -using FileIO = IOInterface; - -} // namespace sp diff --git a/include/sp/io/IOInterface.h b/include/sp/io/IOInterface.h index a749f54..41420d2 100644 --- a/include/sp/io/IOInterface.h +++ b/include/sp/io/IOInterface.h @@ -4,6 +4,7 @@ #include namespace sp { +namespace io { template class IOInterface { @@ -13,7 +14,7 @@ class IOInterface { }; template -class IOStream { +class Stream { protected: MessageDispatcher m_Dispatcher; IOInterface m_Interface; @@ -22,9 +23,9 @@ class IOStream { using MsgIdType = typename MessageBase::MsgIdType; public: - IOStream() {} - IOStream(IOInterface&& a_Interface) : m_Interface(std::move(a_Interface)) {} - IOStream(IOStream&& a_Stream) : m_Dispatcher(std::move(a_Stream.m_Dispatcher)), m_Interface(std::move(a_Stream.m_Interface)) {} + Stream() {} + Stream(IOInterface&& a_Interface) : m_Interface(std::move(a_Interface)) {} + Stream(Stream&& a_Stream) : m_Dispatcher(std::move(a_Stream.m_Dispatcher)), m_Interface(std::move(a_Stream.m_Interface)) {} void RecieveMessages(); void SendMessage(const MessageBase& a_Message); @@ -34,68 +35,7 @@ class IOStream { } }; -template -void IOStream::SendMessage(const MessageBase& a_Message) { - // TODO: process compress + encryption - DataBuffer data = a_Message.Write(); - DataBuffer dataSize; - m_Interface.Write(dataSize << sp::VarInt{data.GetSize()} << data); -} - -template -void IOStream::RecieveMessages() { - // TODO: process compress + encryption - while (true) { - - // reading the first VarInt part byte by byte - std::uint64_t lenghtValue = 0; - unsigned int readPos = 0; - - while (true) { - static constexpr int SEGMENT_BITS = (1 << 7) - 1; - static constexpr int CONTINUE_BIT = 1 << 7; - - DataBuffer buffer = m_Interface.Read(sizeof(std::uint8_t)); - - // if non-blocking call - if (buffer.GetSize() == 0) - return; - - std::uint8_t part; - buffer >> part; - lenghtValue |= static_cast(part & SEGMENT_BITS) << readPos; - - if ((part & CONTINUE_BIT) == 0) - break; - - readPos += 7; - - if (readPos >= 8 * sizeof(lenghtValue)) - throw std::runtime_error("VarInt is too big"); - } - - // nothing to read - if (lenghtValue == 0) - return; - - DataBuffer buffer; - buffer = m_Interface.Read(lenghtValue); - - // TODO: process compress + encryption - - MsgIdType packetType; - buffer >> packetType; - - static const MessageFactory messageFactory; - - std::unique_ptr message = messageFactory.CreateMessage(packetType); - - assert(message != nullptr); - - message->Read(buffer); - - GetDispatcher().Dispatch(*message); - } -} - +} // namespace io } // namespace sp + +#include \ No newline at end of file diff --git a/include/sp/io/IOInterfaceImpl.inl b/include/sp/io/IOInterfaceImpl.inl index 6f70f09..d0b8937 100644 --- a/include/sp/io/IOInterfaceImpl.inl +++ b/include/sp/io/IOInterfaceImpl.inl @@ -1 +1,73 @@ #pragma once + +#include + +namespace sp { +namespace io { + +template +void Stream::SendMessage(const MessageBase& a_Message) { + // TODO: process compress + encryption + DataBuffer data = a_Message.Write(); + DataBuffer dataSize; + m_Interface.Write(dataSize << sp::VarInt{data.GetSize()} << data); +} + +template +void Stream::RecieveMessages() { + // TODO: process compress + encryption + while (true) { + + // reading the first VarInt part byte by byte + std::uint64_t lenghtValue = 0; + unsigned int readPos = 0; + + while (true) { + static constexpr int SEGMENT_BITS = (1 << 7) - 1; + static constexpr int CONTINUE_BIT = 1 << 7; + + DataBuffer buffer = m_Interface.Read(sizeof(std::uint8_t)); + + // eof + if (buffer.GetSize() == 0) + return; + + std::uint8_t part; + buffer >> part; + lenghtValue |= static_cast(part & SEGMENT_BITS) << readPos; + + if ((part & CONTINUE_BIT) == 0) + break; + + readPos += 7; + + if (readPos >= 8 * sizeof(lenghtValue)) + throw std::runtime_error("VarInt is too big"); + } + + // nothing to read + if (lenghtValue == 0) + return; + + DataBuffer buffer; + buffer = m_Interface.Read(lenghtValue); + + // TODO: process compress + encryption + + MsgIdType packetType; + buffer >> packetType; + + static const MessageFactory messageFactory; + + std::unique_ptr message = messageFactory.CreateMessage(packetType); + + assert(message != nullptr); + + message->Read(buffer); + + GetDispatcher().Dispatch(*message); + } +} + +} // namespace io +} // namespace sp \ No newline at end of file diff --git a/include/sp/io/Memory.h b/include/sp/io/Memory.h new file mode 100644 index 0000000..83021bc --- /dev/null +++ b/include/sp/io/Memory.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace sp { +namespace io { + +struct MemoryTag {}; + +template <> +class IOInterface { + private: + sp::DataBuffer m_VirtualIO; + + public: + sp::DataBuffer Read(std::size_t a_Amount); + void Write(const sp::DataBuffer& a_Data); +}; + +using Memory = IOInterface; + +} // namespace io +} // namespace sp diff --git a/src/sp/io/File.cpp b/src/sp/io/File.cpp new file mode 100644 index 0000000..2bccc19 --- /dev/null +++ b/src/sp/io/File.cpp @@ -0,0 +1,31 @@ +#include + +namespace sp { +namespace io { + +File::IOInterface(const std::string& a_FilePath, unsigned int a_OpenMode) { + if (a_OpenMode & FileTag::OpenMode::In) + m_FileInput = std::make_unique(a_FilePath, std::ios::binary); + if (a_OpenMode & FileTag::OpenMode::Out) + m_FileOutput = std::make_unique(a_FilePath, std::ios::binary); +} + +File::IOInterface(File&& other) : + m_FileOutput(std::move(other.m_FileOutput)), m_FileInput(std::move(other.m_FileInput)) {} + +DataBuffer File::Read(std::size_t a_Amount) { + DataBuffer buffer; + buffer.Resize(a_Amount); + assert(m_FileInput != nullptr); + m_FileInput->read(reinterpret_cast(buffer.data()), a_Amount); + return buffer; +} + +void File::Write(const sp::DataBuffer& a_Data) { + assert(m_FileOutput != nullptr); + m_FileOutput->write(reinterpret_cast(a_Data.data()), a_Data.GetSize()); + m_FileOutput->flush(); +} + +} // namespace io +} // namespace sp diff --git a/src/sp/io/Memory.cpp b/src/sp/io/Memory.cpp new file mode 100644 index 0000000..57ffd4f --- /dev/null +++ b/src/sp/io/Memory.cpp @@ -0,0 +1,16 @@ +#include + +namespace sp { +namespace io { + +sp::DataBuffer Memory::Read(std::size_t a_Amount) { + DataBuffer data; + m_VirtualIO.ReadSome(data, a_Amount > m_VirtualIO.GetRemaining() ? m_VirtualIO.GetRemaining() : a_Amount); + return data; +} +void Memory::Write(const sp::DataBuffer& a_Data) { + m_VirtualIO << a_Data; +} + +} // namespace io +} // namespace sp diff --git a/test/test_file.cpp b/test/test_file.cpp index 727a5bd..f05d696 100644 --- a/test/test_file.cpp +++ b/test/test_file.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include class CustomPacketHandler : public sp::PacketHandler { void Handle(const KeepAlivePacket& packet) { @@ -17,13 +17,12 @@ class CustomPacketHandler : public sp::PacketHandler { } }; -using FileStream = sp::IOStream; - +using FileStream = sp::io::Stream; int main() { auto handler = std::make_shared(); - FileStream stream(sp::FileIO{"test.txt", "text.txt"}); + FileStream stream(sp::io::File{"test.txt", sp::io::FileTag::In | sp::io::FileTag::Out}); stream.GetDispatcher().RegisterHandler(PacketId::Disconnect, handler); stream.GetDispatcher().RegisterHandler(PacketId::KeepAlive, handler); diff --git a/test/test_io.cpp b/test/test_io.cpp index 01ff612..8bb78ec 100644 --- a/test/test_io.cpp +++ b/test/test_io.cpp @@ -1,31 +1,9 @@ #include #include -#include +#include -struct DBTag {}; - -template <> -class sp::IOInterface { - private: - sp::DataBuffer m_VirtualIO; - - public: - sp::DataBuffer Read(std::size_t a_Amount) { - // since we are just testing it, we ignore reads that overflows - if (m_VirtualIO.GetReadOffset() + a_Amount > m_VirtualIO.GetSize()) - return {}; - - DataBuffer data; - m_VirtualIO.ReadSome(data, a_Amount); - return data; - } - void Write(const sp::DataBuffer& a_Data) { - m_VirtualIO << a_Data; - } -}; - -using DataBufferStream = sp::IOStream; +using DataBufferStream = sp::io::Stream; class CustomPacketHandler : public sp::PacketHandler { void Handle(const KeepAlivePacket& packet) { @@ -54,9 +32,9 @@ int main() { stream.GetDispatcher().RegisterHandler(PacketId::KeepAlive, handler); stream.SendMessage(KeepAlivePacket{69}); - stream.RecieveMessages(); // here, it's non-blocking + stream.RecieveMessages(); stream.SendMessage(DisconnectPacket{"I don't know"}); - stream.RecieveMessages(); // here, it's non-blocking + stream.RecieveMessages(); return 0; } \ No newline at end of file