From 10b49b34dd0e531a5c6809ddafccd7c29235d44a Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 25 Jun 2025 19:33:11 +0200 Subject: [PATCH] working dispatcher + factory --- include/examples/DisconnectPacket.h | 25 ++- include/examples/KeepAlivePacket.h | 41 +++- include/examples/PacketExample.h | 2 +- include/examples/UpgradeTowerPacket.h | 42 +++-- include/sp/common/{Templates.h => Tuples.h} | 0 include/sp/common/VarInt.h | 2 - include/sp/default/DefaultPacket.h | 13 +- include/sp/protocol/ConcreteMessage.h | 29 +++ include/sp/protocol/Field.h | 134 ------------- include/sp/protocol/GenericHandler.h | 142 +++++++------- include/sp/protocol/Message.h | 16 -- include/sp/protocol/MessageBase.h | 25 +-- include/sp/protocol/MessageDispatcher.h | 19 +- include/sp/protocol/MessageDispatcherImpl.inl | 43 +++++ include/sp/protocol/MessageFactory.h | 22 ++- include/sp/protocol/message/ArrayFillerImpl.h | 39 ---- .../message/MessageDispatcherImpl.inl | 36 ---- .../sp/protocol/message/MessageImplBuilder.h | 49 ----- .../sp/protocol/message/MessageImplOptions.h | 66 ------- .../sp/protocol/message/MessageImplProcess.h | 107 ----------- .../message/MessageInterfaceBuilder.h | 44 ----- .../message/MessageInterfaceProcess.h | 119 ------------ .../sp/protocol/message/MessageInterfaces.h | 7 - .../protocol/message/MessageInterfacesImpl.h | 145 -------------- .../message/MessageInterfacesOptions.h | 69 ------- include/sp/protocol/message/MessageOptions.h | 37 ---- .../sp/protocol/message/MessagePrinterImpl.h | 79 -------- include/sp/protocol/message/MessagesImpl.h | 178 ------------------ .../protocol/message/OstreamFieldIterator.h | 56 ------ src/sp/common/VarInt.cpp | 4 - test/test_file.cpp | 42 ----- test/test_io.cpp | 40 ---- test/test_message.cpp | 49 +++++ test/test_packets.cpp | 61 ------ xmake.lua | 5 + 35 files changed, 315 insertions(+), 1472 deletions(-) rename include/sp/common/{Templates.h => Tuples.h} (100%) create mode 100644 include/sp/protocol/ConcreteMessage.h delete mode 100644 include/sp/protocol/Field.h delete mode 100644 include/sp/protocol/Message.h create mode 100644 include/sp/protocol/MessageDispatcherImpl.inl delete mode 100644 include/sp/protocol/message/ArrayFillerImpl.h delete mode 100644 include/sp/protocol/message/MessageDispatcherImpl.inl delete mode 100644 include/sp/protocol/message/MessageImplBuilder.h delete mode 100644 include/sp/protocol/message/MessageImplOptions.h delete mode 100644 include/sp/protocol/message/MessageImplProcess.h delete mode 100644 include/sp/protocol/message/MessageInterfaceBuilder.h delete mode 100644 include/sp/protocol/message/MessageInterfaceProcess.h delete mode 100644 include/sp/protocol/message/MessageInterfaces.h delete mode 100644 include/sp/protocol/message/MessageInterfacesImpl.h delete mode 100644 include/sp/protocol/message/MessageInterfacesOptions.h delete mode 100644 include/sp/protocol/message/MessageOptions.h delete mode 100644 include/sp/protocol/message/MessagePrinterImpl.h delete mode 100644 include/sp/protocol/message/MessagesImpl.h delete mode 100644 include/sp/protocol/message/OstreamFieldIterator.h delete mode 100644 test/test_file.cpp delete mode 100644 test/test_io.cpp create mode 100644 test/test_message.cpp delete mode 100644 test/test_packets.cpp diff --git a/include/examples/DisconnectPacket.h b/include/examples/DisconnectPacket.h index 013f7f0..84c99b4 100644 --- a/include/examples/DisconnectPacket.h +++ b/include/examples/DisconnectPacket.h @@ -4,17 +4,28 @@ #include #include -enum class DisconnectFieldsE { - Reason = 0 + +struct DisconnectPacketData { + std::string m_Reason; }; -using DisconnectFields = std::tuple; +class DisconnectPacket : public sp::MessageBase> { + private: + DisconnectPacketData m_Data; -DeclarePacket(Disconnect){ - public: - PacketConstructor(Disconnect) + public: + template + DisconnectPacket(T... args) : m_Data{args...} {} const std::string& GetReason() const { - return GetField(); + return m_Data.m_Reason; + } + + virtual sp::PacketID GetId() const { + return Disconnect; } }; + +void ff() { + sizeof(std::string); +} diff --git a/include/examples/KeepAlivePacket.h b/include/examples/KeepAlivePacket.h index 770b078..bf38ab0 100644 --- a/include/examples/KeepAlivePacket.h +++ b/include/examples/KeepAlivePacket.h @@ -4,19 +4,40 @@ #include #include -enum class KeepAliveFieldsE { - KeepAliveId = 0, + +template +class ConcreteMessage { + public: + using DataType = TData; + + template + ConcreteMessage(const T&... args) : m_Data {args ...}; + + private: + DataType m_Data; + + virtual sp::PacketID GetId() const { + return ID; + } }; -using KeepAliveFields = std::tuple< - std::uint64_t //<- KeepAliveId - >; -DeclarePacket(KeepAlive){ - public: - PacketConstructor(KeepAlive) - std::uint64_t GetKeepAliveId() const { - return GetField(); + + +struct KeepAlivePacket { + std::uint64_t m_AliveId; +}; + +class KeepAliveMessage : public sp::MessageBase> { + private: + KeepAlivePacket m_Data; + + public: + template + KeepAliveMessage(T... args) : m_Data{args...} {} + + virtual sp::PacketID GetId() const { + return KeepAlive; } }; \ No newline at end of file diff --git a/include/examples/PacketExample.h b/include/examples/PacketExample.h index bf51532..e5dd3bb 100644 --- a/include/examples/PacketExample.h +++ b/include/examples/PacketExample.h @@ -1,6 +1,6 @@ #pragma once -enum PacketId { +enum PacketIds { KeepAlive = 0, Disconnect, UpgradeTower, diff --git a/include/examples/UpgradeTowerPacket.h b/include/examples/UpgradeTowerPacket.h index fc566b2..88c3972 100644 --- a/include/examples/UpgradeTowerPacket.h +++ b/include/examples/UpgradeTowerPacket.h @@ -4,30 +4,36 @@ #include #include - -enum class UpgradeTowerFieldsE { - m_Tower = 0, - m_Upgrade, +struct UpgradeTowerPacketData { + sp::BitField, // std::uint16_t m_Tower : 12; + sp::Field // std::uint8_t m_Upgrade : 4; + > m_TowerAndUpgrade; + sp::VarInt m_Test; + std::map> m_Test2; }; -using UpgradeTowerFields = std::tuple< - sp::BitField, //<- m_Tower - sp::Field //<- m_Upgrade - >, - sp::VarInt, //<- just for testing - std::map> - >; +class UpgradeTowerPacket : public sp::MessageBase> { + private: + UpgradeTowerPacketData m_Data; -DeclarePacket(UpgradeTower){ - public: - PacketConstructor(UpgradeTower) + public: + template + UpgradeTowerPacket(T... args) : m_Data{args...} {} std::uint16_t GetTowerId() const { - return GetField<0>().GetField(); + return m_Data.m_TowerAndUpgrade.GetField<0>(); } std::uint8_t GetTowerUpgrade() const { - return GetField<0>().GetField(); + return m_Data.m_TowerAndUpgrade.GetField<1>(); } -}; \ No newline at end of file + + virtual sp::PacketID GetId() const { + return UpgradeTower; + } + + UpgradeTowerPacketData& GetData() { + return m_Data; + } +}; diff --git a/include/sp/common/Templates.h b/include/sp/common/Tuples.h similarity index 100% rename from include/sp/common/Templates.h rename to include/sp/common/Tuples.h diff --git a/include/sp/common/VarInt.h b/include/sp/common/VarInt.h index af96df8..2f0bf6b 100644 --- a/include/sp/common/VarInt.h +++ b/include/sp/common/VarInt.h @@ -8,7 +8,6 @@ #include #include #include -#include namespace sp { @@ -58,7 +57,6 @@ class VarInt { */ friend DataBuffer& operator>>(DataBuffer& in, VarInt& var); - friend std::ostream& operator<<(std::ostream& a_Stream, const PrintableField& a_VarInt); }; } // namespace sp diff --git a/include/sp/default/DefaultPacket.h b/include/sp/default/DefaultPacket.h index 107a9ec..3882a40 100644 --- a/include/sp/default/DefaultPacket.h +++ b/include/sp/default/DefaultPacket.h @@ -3,16 +3,15 @@ #include #include + namespace sp { class PacketHandler; + +using PacketID = std::uint8_t; using PacketMessage = Message< - option::MsgIdType, // add id() operation - option::ReadOperations, // add read() operation - option::WriteOperations, // add write() operation - option::WriteId, // write id before data - option::Handler, // add dispatch() operation - option::DebugPrint // add ToString() operator + option::MsgIdType, // add id() operation + option::Handler // add dispatch() operation >; #define PacketConstructor(packetName) \ @@ -23,7 +22,7 @@ using PacketMessage = Message< } #define DeclarePacket(packetName) \ - class packetName##Packet : public sp::MessageBase, \ + class packetName##Packet : public sp::MessageBase, sp::option::FieldsImpl>, \ sp::option::ToStringImpl diff --git a/include/sp/protocol/ConcreteMessage.h b/include/sp/protocol/ConcreteMessage.h new file mode 100644 index 0000000..b057276 --- /dev/null +++ b/include/sp/protocol/ConcreteMessage.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +namespace sp { + +template +class ConcreteMessage : public MessageBase { + public: + using DataType = TData; + + template + ConcreteMessage(const T&... args) : m_Data{args...} {} + + virtual ~ConcreteMessage() {} + + virtual constexpr TMessageID GetId() const override { + return ID; + } + + virtual void Dispatch(THandler& handler) const override { + handler.Handle(static_cast&>(*this)); + } + + private: + DataType m_Data; +}; + +} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/Field.h b/include/sp/protocol/Field.h deleted file mode 100644 index 5fb377f..0000000 --- a/include/sp/protocol/Field.h +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -#include - -namespace sp { - -/** - * \brief Example usage : - * sp::BitField, sp::Field>; - */ -template -class BitField { - using AllFields = std::tuple; - - public: - template - BitField(const std::tuple& args) { - Apply<0, T...>(args); - } - - BitField() {} - - template - BitField& operator=(const std::tuple& args) { - Apply<0, T...>(args); - return *this; - } - - AllFields& GetFields() { - return m_Fields; - } - - const AllFields& GetFields() const { - return m_Fields; - } - - template - auto& GetField() { - return std::get(this->GetFields()).GetValue(); - } - - template - const auto& GetField() const { - return std::get(this->GetFields()).GetValue(); - } - - // allow use of enums - template - const auto& GetField() const { - return std::get(FIndex)>(this->GetFields()).GetValue(); - } - - private: - template = sizeof...(T), bool> = true> - void Apply(const std::tuple& args) {} - - template = sizeof...(T)), bool> = true> - void Apply(const std::tuple& args) { - this->GetField() = std::get(args); - Apply<1 + IOffset, T...>(args); - } - - TContainer m_Value; - AllFields m_Fields; -}; - -/** - * - * \tparam ValueType the type of the value to store - * \tparam IAlignment 0 means no alignment - */ -template -class Field { - public: - using StorageType = ValueType; - static constexpr std::size_t AlignmentValue = IAlignment; - - // Provide an access to the stored value - StorageType& GetValue() { - return m_Value; - } - - const StorageType& GetValue() const { - return m_Value; - } - - Field& operator=(const StorageType& value) { - m_Value = value; - return *this; - } - - constexpr std::size_t GetAlignment() const { - return IAlignment; - } - - private: - StorageType m_Value; -}; - -template -class PrintableField { - public: - PrintableField(const T& a_Value) : m_Value(a_Value) {} - - const T& GetValue() const { - return m_Value; - } - - private: - const T& m_Value; -}; - -namespace details { - -template -struct FieldsBuilder {}; - -template <> -struct FieldsBuilder<> { - using Type = std::tuple<>; -}; - -template -struct FieldsBuilder> { - using Type = typename FieldsBuilder::Type; -}; - -template -struct FieldsBuilder { - using Type = sp::tuple_cat_t>, typename FieldsBuilder::Type>; -}; - -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/GenericHandler.h b/include/sp/protocol/GenericHandler.h index dca0813..1232176 100644 --- a/include/sp/protocol/GenericHandler.h +++ b/include/sp/protocol/GenericHandler.h @@ -8,134 +8,132 @@ namespace sp // TCommon is common interface class for all the messages // TAll is all the message types, that need to be handled, bundled in std::tuple - template + template class GenericHandler; // Big boy to process packets 20 by 20, preventing needlessly copying vtable many times at each inheritance stage - template - class GenericHandler > : public GenericHandler > + class GenericHandler > : public GenericHandler > { - using Base = GenericHandler >; + using Base = GenericHandler >; public: using Base::Handle; // Don't hide all Handle() functions from base classes - virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T5& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T6& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T7& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T8& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T9& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T10& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T11& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T12& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T13& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T14& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T15& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T16& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T17& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T18& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T19& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T20& msg) { this->Handle(static_cast(msg)); } + virtual void Handle(const T1& msg) {} + virtual void Handle(const T2& msg) {} + virtual void Handle(const T3& msg) {} + virtual void Handle(const T4& msg) {} + virtual void Handle(const T5& msg) {} + virtual void Handle(const T6& msg) {} + virtual void Handle(const T7& msg) {} + virtual void Handle(const T8& msg) {} + virtual void Handle(const T9& msg) {} + virtual void Handle(const T10& msg) {} + virtual void Handle(const T11& msg) {} + virtual void Handle(const T12& msg) {} + virtual void Handle(const T13& msg) {} + virtual void Handle(const T14& msg) {} + virtual void Handle(const T15& msg) {} + virtual void Handle(const T16& msg) {} + virtual void Handle(const T17& msg) {} + virtual void Handle(const T18& msg) {} + virtual void Handle(const T19& msg) {} + virtual void Handle(const T20& msg) {} }; // 10 by 10 - template - class GenericHandler > : public GenericHandler > + class GenericHandler > : public GenericHandler > { - using Base = GenericHandler >; + using Base = GenericHandler >; public: using Base::Handle; // Don't hide all Handle() functions from base classes - virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T5& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T6& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T7& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T8& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T9& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T10& msg) { this->Handle(static_cast(msg)); } + virtual void Handle(const T1& msg) {} + virtual void Handle(const T2& msg) {} + virtual void Handle(const T3& msg) {} + virtual void Handle(const T4& msg) {} + virtual void Handle(const T5& msg) {} + virtual void Handle(const T6& msg) {} + virtual void Handle(const T7& msg) {} + virtual void Handle(const T8& msg) {} + virtual void Handle(const T9& msg) {} + virtual void Handle(const T10& msg) {} }; // 5 by 5 - template - class GenericHandler > : public GenericHandler > + class GenericHandler > : public GenericHandler > { - using Base = GenericHandler >; + using Base = GenericHandler >; public: using Base::Handle; // Don't hide all Handle() functions from base classes - virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T5& msg) { this->Handle(static_cast(msg)); } + virtual void Handle(const T1& msg) {} + virtual void Handle(const T2& msg) {} + virtual void Handle(const T3& msg) {} + virtual void Handle(const T4& msg) {} + virtual void Handle(const T5& msg) {} }; // Deal with rest with 4 types - template - class GenericHandler > + template + class GenericHandler > { public: virtual ~GenericHandler() {} - virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const TCommon&) { } //Nothing to do + virtual void Handle(const T1& msg) {} + virtual void Handle(const T2& msg) {} + virtual void Handle(const T3& msg) {} + virtual void Handle(const T4& msg) {} + // virtual void Handle(const TCommon&) {} //Nothing to do }; // Deal with rest with 3 types - template - class GenericHandler > + template < typename T1, typename T2, typename T3> + class GenericHandler > { public: virtual ~GenericHandler() {} - virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const TCommon&) { } //Nothing to do + virtual void Handle(const T1& msg) {} + virtual void Handle(const T2& msg) {} + virtual void Handle(const T3& msg) {} + // virtual void Handle(const TCommon&) {} //Nothing to do }; // Deal with rest with 2 types - template - class GenericHandler > + template + class GenericHandler > { public: virtual ~GenericHandler() {} - virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const TCommon&) { } //Nothing to do + virtual void Handle(const T1& msg) {} + virtual void Handle(const T2& msg) {} + // virtual void Handle(const TCommon&) {} //Nothing to do }; // Deal with rest with 1 type - template - class GenericHandler > + template + class GenericHandler > { public: virtual ~GenericHandler() {} - virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(const TCommon&) { } //Nothing to do + virtual void Handle(const T1& msg) {} + // virtual void Handle(const TCommon&) {} //Nothing to do }; // Deal with rest with 0 type - template - class GenericHandler > + template <> + class GenericHandler > { public: virtual ~GenericHandler() {} - virtual void Handle(const TCommon&) { } //Nothing to do + // virtual void Handle(const TCommon&) {} //Nothing to do }; } // sp \ No newline at end of file diff --git a/include/sp/protocol/Message.h b/include/sp/protocol/Message.h deleted file mode 100644 index c347b24..0000000 --- a/include/sp/protocol/Message.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -// Inspired by -// https://alex-robenko.gitbook.io/comms-protocols-cpp - -#include - -namespace sp { - -template -class Message : public details::MessageInterfaceBuilder::Type { - public: - using ParsedOptions = typename details::MessageInterfaceBuilder::ParsedOptions; -}; - -} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/MessageBase.h b/include/sp/protocol/MessageBase.h index 80d0b8a..5fd2441 100644 --- a/include/sp/protocol/MessageBase.h +++ b/include/sp/protocol/MessageBase.h @@ -1,18 +1,19 @@ #pragma once -#include - -#include - -#include -#include -#include - namespace sp { -template -class MessageBase : public details::MessageImplBuilder::Type {}; +template +class MessageBase { + public: + using HandlerType = THandler; + using MessageIdType = TMessageID; + + MessageBase() {} + virtual ~MessageBase() {} + + virtual MessageIdType GetId() const = 0; + + virtual void Dispatch(HandlerType& handler) const = 0; +}; } // namespace sp - -#include \ No newline at end of file diff --git a/include/sp/protocol/MessageDispatcher.h b/include/sp/protocol/MessageDispatcher.h index 1cdba2c..c7e2f6d 100644 --- a/include/sp/protocol/MessageDispatcher.h +++ b/include/sp/protocol/MessageDispatcher.h @@ -7,6 +7,7 @@ #include #include +#include namespace sp { @@ -14,13 +15,12 @@ namespace sp { * \class MessageDispatcher * \brief Class used to dispatch messages */ -template +template class MessageDispatcher { - private: - std::map> m_Handlers; - public: using MessageBaseType = MessageBase; + using MessageIdType = typename MessageBase::MessageIdType; + using MessageHandler = typename MessageBase::HandlerType; /** * \brief Constructor @@ -39,21 +39,24 @@ class MessageDispatcher { * \param handler The packet handler */ void RegisterHandler(MessageIdType a_MessageType, MessageHandler* a_Handler); - + /** * \brief Unregister a packet handler * \param type The packet type * \param handler The packet handler */ void UnregisterHandler(MessageIdType a_MessageType, MessageHandler* a_Handler); - + /** * \brief Unregister a packet handler * \param handler The packet handler */ void UnregisterHandler(MessageHandler* a_Handler); + + private: + std::map> m_Handlers; }; -#include - } // namespace sp + +#include \ No newline at end of file diff --git a/include/sp/protocol/MessageDispatcherImpl.inl b/include/sp/protocol/MessageDispatcherImpl.inl new file mode 100644 index 0000000..408a9b9 --- /dev/null +++ b/include/sp/protocol/MessageDispatcherImpl.inl @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace sp { + +template +void MessageDispatcher::RegisterHandler(MessageIdType a_MessageType, MessageHandler* a_Handler) { + assert(a_Handler); + auto found = std::find(m_Handlers[a_MessageType].begin(), m_Handlers[a_MessageType].end(), a_Handler); + if (found == m_Handlers[a_MessageType].end()) + m_Handlers[a_MessageType].push_back(a_Handler); +} + +template +void MessageDispatcher::UnregisterHandler(MessageIdType a_MessageType, MessageHandler* a_Handler) { + auto found = std::find(m_Handlers[a_MessageType].begin(), m_Handlers[a_MessageType].end(), a_Handler); + if (found != m_Handlers[a_MessageType].end()) + m_Handlers[a_MessageType].erase(found); +} + +template +void MessageDispatcher::UnregisterHandler(MessageHandler* a_Handler) { + for (auto& pair : m_Handlers) { + if (pair.second.empty()) + continue; + + MessageIdType type = pair.first; + + pair.second.erase(std::remove(pair.second.begin(), pair.second.end(), a_Handler), pair.second.end()); + } +} + +template +void MessageDispatcher::Dispatch(const MessageBase& a_Message) { + MessageIdType type = a_Message.GetId(); + for (auto& handler : m_Handlers[type]) { + a_Message.Dispatch(*handler); + } +} + +} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/MessageFactory.h b/include/sp/protocol/MessageFactory.h index abc5a99..c7c5d59 100644 --- a/include/sp/protocol/MessageFactory.h +++ b/include/sp/protocol/MessageFactory.h @@ -2,28 +2,36 @@ #include #include -#include #include -#include +#include namespace sp { template class MessageFactory { public: - using IdType = typename TBase::MsgIdType; + using IdType = typename TBase::MessageIdType; - MessageFactory() : m_Factory(details::ArrayFiller::ArrayCreate()) {} + MessageFactory() { + constexpr std::size_t messageCount = std::tuple_size_v; + m_Factory.resize(messageCount); + TupleForEach([this](const auto& message){ + std::size_t messageID = static_cast(message.GetId()); + using MessageType = std::remove_const_t>; + m_Factory.emplace(m_Factory.begin() + messageID, []() -> std::unique_ptr { return std::make_unique(); }); + }, TTMessages{}); + } std::unique_ptr CreateMessage(IdType id) const { - if (id >= m_Factory.size()) + std::size_t idSize = static_cast(id); + if (idSize >= m_Factory.size()) return nullptr; - return m_Factory.at(id)(); + return m_Factory.at(idSize)(); } private: - details::ArrayType m_Factory; + std::vector(void)>> m_Factory; }; diff --git a/include/sp/protocol/message/ArrayFillerImpl.h b/include/sp/protocol/message/ArrayFillerImpl.h deleted file mode 100644 index 556cd8f..0000000 --- a/include/sp/protocol/message/ArrayFillerImpl.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -namespace sp { -namespace details { - -template -using ArrayType = std::vector(void)>>; - - -template -struct ArrayFiller {}; - -template -struct ArrayFiller> { - static ArrayType ArrayCreate() { - ArrayType array; - array.reserve(sizeof...(TMessages)); - ArrayFiller::ArrayAppend(array); - return array; - } -}; - -template -struct ArrayFiller { - static void ArrayAppend(details::ArrayType& array) { - ArrayFiller::ArrayAppend(array); - ArrayFiller::ArrayAppend(array); - } -}; - -template -struct ArrayFiller { - static void ArrayAppend(details::ArrayType& array) { - array.emplace_back([]() -> std::unique_ptr { return std::make_unique(); }); - } -}; - -} // namespace details -} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/message/MessageDispatcherImpl.inl b/include/sp/protocol/message/MessageDispatcherImpl.inl deleted file mode 100644 index 7319fbf..0000000 --- a/include/sp/protocol/message/MessageDispatcherImpl.inl +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -template -void MessageDispatcher::RegisterHandler(MessageIdType a_MessageType, MessageHandler* a_Handler) { - assert(a_Handler); - auto found = std::find(m_Handlers[a_MessageType].begin(), m_Handlers[a_MessageType].end(), a_Handler); - if (found == m_Handlers[a_MessageType].end()) - m_Handlers[a_MessageType].push_back(a_Handler); -} - -template -void MessageDispatcher::UnregisterHandler(MessageIdType a_MessageType, MessageHandler* a_Handler) { - auto found = std::find(m_Handlers[a_MessageType].begin(), m_Handlers[a_MessageType].end(), a_Handler); - if (found != m_Handlers[a_MessageType].end()) - m_Handlers[a_MessageType].erase(found); -} - -template -void MessageDispatcher::UnregisterHandler(MessageHandler* a_Handler) { - for (auto& pair : m_Handlers) { - if (pair.second.empty()) - continue; - - MessageIdType type = pair.first; - - pair.second.erase(std::remove(pair.second.begin(), pair.second.end(), a_Handler), pair.second.end()); - } -} - -template -void MessageDispatcher::Dispatch(const MessageBase& a_Message) { - MessageIdType type = a_Message.GetId(); - for (auto& handler : m_Handlers[type]) { - a_Message.Dispatch(*handler); - } -} diff --git a/include/sp/protocol/message/MessageImplBuilder.h b/include/sp/protocol/message/MessageImplBuilder.h deleted file mode 100644 index b01219e..0000000 --- a/include/sp/protocol/message/MessageImplBuilder.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -namespace sp { -namespace details { - - -// TBase is interface class -// TOptions... are the implementation options -template -struct MessageImplBuilder { - // ParsedOptions class is supposed to be defined in comms::Message class - using InterfaceOptions = typename TBase::ParsedOptions; - - // Parse implementation options - using ImplOptions = MessageImplParsedOptions; - - // Provide GetIdImpl() if possible - static const bool HasStaticNumIdImpl = InterfaceOptions::HasMsgIdType && ImplOptions::HasStaticNumIdImpl; - using Base1 = typename MessageImplProcessStaticNumId::Type; - - // Provide DispatchImpl() if possible - static const bool HasDispatchImpl = InterfaceOptions::HasHandler && ImplOptions::HasDispatchImpl; - using Base2 = typename MessageImplProcessDispatch::Type; - - // Provide access to fields if possible - using Base3 = typename MessageImplProcessFields::Type; - - // Provide ReadImpl() if possible - static const bool HasReadImpl = InterfaceOptions::HasReadOperations && ImplOptions::HasFieldsImpl; - using Base4 = typename MessageImplProcessReadFields::Type; - - // Provide WriteImpl() if possible - static const bool HasWriteImpl = InterfaceOptions::HasWriteOperations && ImplOptions::HasFieldsImpl; - using Base5 = typename MessageImplProcessWriteFields::Type; - - // Provide ValidImpl() if possible - static const bool HasValidImpl = InterfaceOptions::HasValid && ImplOptions::HasFieldsImpl; - using Base6 = typename MessageImplProcessValidFields::Type; - - // Provide ToStringImpl() if possible - static const bool HasToStringImpl = InterfaceOptions::HasToString; - using Base7 = typename MessageImplProcessToString::Type; - - // The last BaseN must be taken as final type. - using Type = Base7; -}; - -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/message/MessageImplOptions.h b/include/sp/protocol/message/MessageImplOptions.h deleted file mode 100644 index 5944a8d..0000000 --- a/include/sp/protocol/message/MessageImplOptions.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -namespace sp { -namespace option { - -// Provide static numeric ID, to facilitate implementation of GetIdImpl() -template -struct StaticNumIdImpl {}; - -// Facilitate implementation of DispatchImpl() -template -struct DispatchImpl {}; - -// Provide fields of the message, facilitate implementation of -// ReadImpl(), WriteImpl(), ValidImpl(), etc... -template -struct FieldsImpl {}; - -// Print fields of the message, facilitate implementation of -// ToStringImpl() -template -struct ToStringImpl {}; - -} // namespace option - - -namespace details { - - - - - -template -class MessageImplParsedOptions; - -template <> -struct MessageImplParsedOptions<> { - static const bool HasStaticNumIdImpl = false; - static const bool HasDispatchImpl = false; - static const bool HasFieldsImpl = false; -}; - - - - - -template -struct MessageImplParsedOptions, TOptions...> : public MessageImplParsedOptions { - static const bool HasStaticNumIdImpl = true; - static const std::uintmax_t MsgId = TId; -}; - -template -struct MessageImplParsedOptions, TOptions...> : public MessageImplParsedOptions { - static const bool HasDispatchImpl = true; - using ActualMessage = TActual; -}; - -template -struct MessageImplParsedOptions, TOptions...> : public MessageImplParsedOptions { - static const bool HasFieldsImpl = true; - using Fields = TFields; -}; - -} // namespace details -} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/message/MessageImplProcess.h b/include/sp/protocol/message/MessageImplProcess.h deleted file mode 100644 index 31706f6..0000000 --- a/include/sp/protocol/message/MessageImplProcess.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -namespace sp { -namespace details { - - -// ToString impl -template -struct MessageImplProcessToString; - -template -struct MessageImplProcessToString { - using Type = MessageImplToStringBase; -}; - -template -struct MessageImplProcessToString { - using Type = TBase; -}; - - -// id impl -template -struct MessageImplProcessStaticNumId; - -template -struct MessageImplProcessStaticNumId { - using Type = MessageImplStaticNumIdBase; -}; - -template -struct MessageImplProcessStaticNumId { - using Type = TBase; -}; - -// dispatch impl -template -struct MessageImplProcessDispatch; - -template -struct MessageImplProcessDispatch { - using Type = MessageImplDispatchBase; -}; - -template -struct MessageImplProcessDispatch { - using Type = TBase; -}; - -// fields impl -template -struct MessageImplProcessFields; - -template -struct MessageImplProcessFields { - using Type = MessageImplFieldsBase; -}; - -template -struct MessageImplProcessFields { - using Type = TBase; -}; - -// read impl -template -struct MessageImplProcessReadFields; - -template -struct MessageImplProcessReadFields { - using Type = MessageImplFieldsReadBase; -}; - -template -struct MessageImplProcessReadFields { - using Type = TBase; -}; - -// write impl -template -struct MessageImplProcessWriteFields; - -template -struct MessageImplProcessWriteFields { - using Type = MessageImplFieldsWriteBase; -}; - -template -struct MessageImplProcessWriteFields { - using Type = TBase; -}; - -// valid impl -template -struct MessageImplProcessValidFields; - -template -struct MessageImplProcessValidFields { - using Type = MessageImplFieldsValidBase; -}; - -template -struct MessageImplProcessValidFields { - using Type = TBase; -}; - -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/message/MessageInterfaceBuilder.h b/include/sp/protocol/message/MessageInterfaceBuilder.h deleted file mode 100644 index 7496a18..0000000 --- a/include/sp/protocol/message/MessageInterfaceBuilder.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -namespace sp { -namespace details { - -class EmptyBase {}; - -template -struct MessageInterfaceBuilder { - // Parse the options - using ParsedOptions = MessageInterfaceParsedOptions; - - // Add ID retrieval functionality if ID type was provided - using Base1 = typename MessageInterfaceProcessMsgId::Type; - - // Add ReadData() and WriteData(), that use the right endian - using Base2 = typename MessageInterfaceProcessEndian::Type; - - // Add read functionality if Read type was provided - using Base3 = typename MessageInterfaceProcessRead::Type; - - // Add write functionality if Write type was provided - using Base4 = typename MessageInterfaceProcessWrite::Type; - - // add dispatch functionality if Handler type was provided - using Base5 = typename MessageInterfaceProcessHandler::Type; - - // add valid functionality if Valid tpe was provided - using Base6 = typename MessageInterfaceProcessValid::Type; - - // add write id functionality if write id and write was provided - using Base7 = typename MessageInterfaceProcessWriteId::Type; - - // add ToString() if HasToString was provided - using Base8 = typename MessageInterfaceProcessToString::Type; - - // The last Base8 must be taken as final type. - using Type = Base8; -}; - -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/message/MessageInterfaceProcess.h b/include/sp/protocol/message/MessageInterfaceProcess.h deleted file mode 100644 index 9b4fb97..0000000 --- a/include/sp/protocol/message/MessageInterfaceProcess.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -namespace sp { -namespace details { - -// Build message Id -template -struct MessageInterfaceProcessMsgId; - -template -struct MessageInterfaceProcessMsgId { - using Type = MessageInterfaceIdTypeBase; -}; - -template -struct MessageInterfaceProcessMsgId { - using Type = TBase; -}; - -// Build endianess -template -struct MessageInterfaceProcessEndian; - -template -struct MessageInterfaceProcessEndian { - using Type = MessageInterfaceLittleEndian; -}; - -template -struct MessageInterfaceProcessEndian { - using Type = MessageInterfaceBigEndian; -}; - -// Build read -template -struct MessageInterfaceProcessRead; - -template -struct MessageInterfaceProcessRead { - using Type = MessageInterfaceReadBase; -}; - -template -struct MessageInterfaceProcessRead { - using Type = TBase; -}; - -// Build write -template -struct MessageInterfaceProcessWrite; - -template -struct MessageInterfaceProcessWrite { - using Type = MessageInterfaceWriteBase; -}; - -template -struct MessageInterfaceProcessWrite { - using Type = TBase; -}; - -// Build handler -template -struct MessageInterfaceProcessHandler; - -template -struct MessageInterfaceProcessHandler { - using Type = MessageInterfaceHandlerBase; -}; - -template -struct MessageInterfaceProcessHandler { - using Type = TBase; -}; - -// Build valid -template -struct MessageInterfaceProcessValid; - -template -struct MessageInterfaceProcessValid { - using Type = MessageInterfaceValidityBase; -}; - -template -struct MessageInterfaceProcessValid { - using Type = TBase; -}; - -// Build id writing -template -struct MessageInterfaceProcessWriteId; - -template -struct MessageInterfaceProcessWriteId { - using Type = MessageInterfaceWriteIdBase; -}; - -template -struct MessageInterfaceProcessWriteId { - using Type = TBase; -}; - -// Build to string -template -struct MessageInterfaceProcessToString; - -template -struct MessageInterfaceProcessToString { - using Type = MessageInterfaceToStringBase; -}; - -template -struct MessageInterfaceProcessToString { - using Type = TBase; -}; - -} // namespace details -} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/message/MessageInterfaces.h b/include/sp/protocol/message/MessageInterfaces.h deleted file mode 100644 index a1b1176..0000000 --- a/include/sp/protocol/message/MessageInterfaces.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -#include -#include -#include diff --git a/include/sp/protocol/message/MessageInterfacesImpl.h b/include/sp/protocol/message/MessageInterfacesImpl.h deleted file mode 100644 index d9df12e..0000000 --- a/include/sp/protocol/message/MessageInterfacesImpl.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include - -namespace sp { -namespace details { - - -// ID retrieval chunk -template -class MessageInterfaceIdTypeBase : public TBase { - public: - using MsgIdType = TId; - MsgIdType GetId() const { - return GetIdImpl(); - } - - protected: - virtual MsgIdType GetIdImpl() const = 0; -}; - -// Big endian serialisation chunk -template -class MessageInterfaceBigEndian : public TBase { - protected: - template - void ReadData(T& value, DataBuffer& buffer) { - buffer >> value; - FromNetwork(value); - } - - template - void WriteData(T value, DataBuffer& buffer) const { - ToNetwork(value); - buffer << value; - } -}; - -// Little endian serialisation chunk -template -class MessageInterfaceLittleEndian : public TBase { - protected: - template - void ReadData(T& value, DataBuffer& buffer) { - buffer >> value; - TrySwapBytes(value); - FromNetwork(value); - } - - template - void WriteData(const T& value, DataBuffer& buffer) { - ToNetwork(value); - TrySwapBytes(value); - buffer << value; - } -}; - -// Read functionality chunk -template -class MessageInterfaceReadBase : public TBase { - public: - void Read(DataBuffer& buffer) { - return ReadImpl(buffer); - } - - protected: - virtual void ReadImpl(DataBuffer& buffer) = 0; -}; - -// Write functionality chunk -template -class MessageInterfaceWriteBase : public TBase { - public: - void Write(DataBuffer& buffer) const { - WriteImpl(buffer); - } - - // helper - DataBuffer Write() const { - DataBuffer buffer; - this->Write(buffer); - return buffer; - } - - protected: - virtual void WriteImpl(DataBuffer& buffer) const = 0; -}; - -// Handler functionality chunk -template -class MessageInterfaceHandlerBase : public TBase { - public: - using HandlerType = typename THandler::HandlerT; - - void Dispatch(HandlerType& handler) const { - DispatchImpl(handler); - } - - protected: - virtual void DispatchImpl(HandlerType& handler) const = 0; -}; - -// Validity functionality chunk -template -class MessageInterfaceValidityBase : public TBase { - public: - bool Valid() const { - return ValidImpl(); - } - - protected: - virtual bool ValidImpl() const = 0; -}; - -// Writing id functionality chunk -template -class MessageInterfaceWriteIdBase : public TBase { - public: - void Write(DataBuffer& buffer) const { - buffer << VarInt{this->GetId()}; - this->WriteImpl(buffer); - } - - // helper - DataBuffer Write() const { - DataBuffer buffer; - this->Write(buffer); - return buffer; - } -}; - -// Debug print functionality chunk -template -class MessageInterfaceToStringBase : public TBase { - public: - friend std::ostream& operator<<(std::ostream& a_Stream, const MessageInterfaceToStringBase& a_Message) { - return a_Message.OpOutImpl(a_Stream); - } - - protected: - virtual std::ostream& OpOutImpl(std::ostream& a_Stream) const = 0; -}; - -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/message/MessageInterfacesOptions.h b/include/sp/protocol/message/MessageInterfacesOptions.h deleted file mode 100644 index a311c16..0000000 --- a/include/sp/protocol/message/MessageInterfacesOptions.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -namespace sp { -namespace details { - - -template -struct MessageInterfaceParsedOptions {}; - -template <> -struct MessageInterfaceParsedOptions<> { - static const bool HasMsgIdType = false; - static const bool HasLittleEndian = false; - static const bool HasReadOperations = false; - static const bool HasWriteOperations = false; - static const bool HasWriteId = false; - static const bool HasHandler = false; - static const bool HasValid = false; - static const bool HasToString = false; -}; - - - - - -template -struct MessageInterfaceParsedOptions, TOptions...> : public MessageInterfaceParsedOptions { - static const bool HasMsgIdType = true; - using MsgIdType = T; -}; - -template -struct MessageInterfaceParsedOptions : public MessageInterfaceParsedOptions { - static const bool HasLittleEndian = true; -}; - -template -struct MessageInterfaceParsedOptions : public MessageInterfaceParsedOptions { - static const bool HasReadOperations = true; -}; - -template -struct MessageInterfaceParsedOptions : public MessageInterfaceParsedOptions { - static const bool HasWriteOperations = true; -}; - -template -struct MessageInterfaceParsedOptions : public MessageInterfaceParsedOptions { - static const bool HasWriteId = true; -}; - -template -struct MessageInterfaceParsedOptions, TOptions...> : public MessageInterfaceParsedOptions { - static const bool HasHandler = true; - using HandlerType = option::Handler; -}; - -template -struct MessageInterfaceParsedOptions : public MessageInterfaceParsedOptions { - static const bool HasValid = true; -}; - -template -struct MessageInterfaceParsedOptions : public MessageInterfaceParsedOptions { - static const bool HasToString = true; -}; - -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/message/MessageOptions.h b/include/sp/protocol/message/MessageOptions.h deleted file mode 100644 index dadd1e0..0000000 --- a/include/sp/protocol/message/MessageOptions.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -namespace sp { -namespace option { - -// Define type used to store message ID -template -struct MsgIdType {}; - -// Enable reading -struct ReadOperations {}; - -// Enable writing -struct WriteOperations {}; - -// Enable id writing -struct WriteId {}; - -// Use little endian for serialisation (instead of default big) -struct LittleEndian {}; - -// Include validity check in public interface -struct ValidCheckInterface {}; - -// Add a ToString() method containing fields -struct DebugPrint {}; - -// Define handler class -template -struct Handler { - using HandlerT = T; -}; - -} // namespace option -} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/message/MessagePrinterImpl.h b/include/sp/protocol/message/MessagePrinterImpl.h deleted file mode 100644 index 1b4cfc4..0000000 --- a/include/sp/protocol/message/MessagePrinterImpl.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace sp { -namespace details { - -template -struct IdPrinter {}; - -template <> -struct IdPrinter<> { - static std::string PrintMessageId() { - return ""; - } -}; - -template -struct IdPrinter { - static std::string PrintMessageId() { - return IdPrinter::PrintMessageId(); - } -}; - -template -struct IdPrinter, TOptions...> { - static std::string PrintMessageId() { - return "(Id: " + std::to_string(TId) + ")"; - } -}; - -} // namespace details - -template -std::ostream& operator<<(std::ostream& a_Stream, const std::tuple& a_Fields); - -template -struct FieldPrinter { - static std::ostream& PrintField(std::ostream& a_Stream, const sp::Field& a_Field) { - return a_Stream << sp::Reflector::GetClassName() << "=" << PrintableField(a_Field.GetValue()); - } -}; - -template -struct FieldPrinter, IAlignment> { - static std::ostream& PrintField( - std::ostream& a_Stream, const sp::Field, IAlignment>& a_Field) { - a_Stream << "BitField<" << sp::Reflector::GetClassName() << ">["; - a_Stream << a_Field.GetValue().GetFields() << "]"; - return a_Stream; - } -}; - -template -std::ostream& operator<<(std::ostream& a_Stream, const std::tuple& a_Fields) { - bool first = true; - TupleForEach( - [&a_Stream, &first](const auto& a_Field) { - if (!first) - a_Stream << ", "; - using TField = typename std::decay::type; - constexpr std::size_t alignment = TField::AlignmentValue; - FieldPrinter::PrintField(a_Stream, a_Field); - first = false; - }, - a_Fields); - return a_Stream; -} - -template -std::ostream& operator<<(std::ostream& a_Stream, const sp::MessageBase& a_Message) { - a_Stream << sp::GetBasicClassName(a_Message) << sp::details::IdPrinter::PrintMessageId() << "[" - << a_Message.GetFields() << "]"; - return a_Stream; -} - -} // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/message/MessagesImpl.h b/include/sp/protocol/message/MessagesImpl.h deleted file mode 100644 index 3afb4b3..0000000 --- a/include/sp/protocol/message/MessagesImpl.h +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once - -namespace sp { - -template -class MessageBase; - -namespace details { - -template -std::string PrintMessage(const MessageBase& a_Message); - -// ID information chunk -template -class MessageImplToStringBase : public TBase { - protected: - virtual std::ostream& OpOutImpl(std::ostream& a_Stream) const override{ - return a_Stream << static_cast(*this); - } -}; - - - -// ID information chunk -template -class MessageImplStaticNumIdBase : public TBase { - public: - // Reuse the message ID type defined in the interface - using MsgIdType = typename TBase::MsgIdType; - - protected: - virtual MsgIdType GetIdImpl() const override { - return static_cast(TId); - } -}; - - - -// Dispatch implementation chunk -template -class MessageImplDispatchBase : public TBase { - public: - // Reuse the Handler type defined in the interface class - using Handler = typename TBase::HandlerType; - - protected: - virtual void DispatchImpl(Handler& handler) const override { - handler.Handle(static_cast(*this)); - } -}; - - - -template -class MessageImplFieldsBase : public TBase { - public: - using AllFields = typename details::FieldsBuilder::Type; - - template - void Construct(Args... args) { - m_Fields = std::make_tuple(args...); - } - - AllFields& GetFields() { - return m_Fields; - } - - const AllFields& GetFields() const { - return m_Fields; - } - - template - auto& GetField() { - return std::get(GetFields()).GetValue(); - } - - template - const auto& GetField() const { - return std::get(GetFields()).GetValue(); - } - - // allow use of enums - template - const auto& GetField() const { - return std::get(FIndex)>(this->GetFields()).GetValue(); - } - - private: - AllFields m_Fields; -}; - -template -class MessageImplFieldsReadBase : public TBase { - private: - // normal reading - template - void ReadField(Field& field, DataBuffer& buffer) { - this->ReadData(field.GetValue(), buffer); - } - - // reading field in bitfield - template - void ReadField(Field& field, TFieldType data, std::size_t offset) { - static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8; - // we suppose that the first element is at the highest bits - field.GetValue() = (data >> TotalBitCount - IAlignment - offset) & ((1 << IAlignment) - 1); - } - - // reading bitfield - template - void ReadField(Field, 0>& field, DataBuffer& buffer) { - TContainer data; - this->ReadData(data, buffer); - std::size_t offset = 0; - TupleForEach( - [data, this, &offset](auto& field) { - this->ReadField(field, data, offset); - offset += field.GetAlignment(); - }, - field.GetValue().GetFields()); - } - - void ReadImpl(DataBuffer& buffer) override { - auto& allFields = this->GetFields(); - TupleForEach([&buffer, this](auto& field) { this->ReadField(field, buffer); }, allFields); - } -}; - -template -class MessageImplFieldsWriteBase : public TBase { - private: - // normal writing - template - void WriteField(const Field& field, DataBuffer& buffer) const { - this->WriteData(field.GetValue(), buffer); - } - - // writing field in bitfield - template - void WriteField(const Field& field, TFieldType& data, std::size_t offset) const { - static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8; - // we suppose that the first element is at the highest bits - data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset; - } - - // writing bitfield - template - void WriteField(const Field, 0>& field, DataBuffer& buffer) const { - TContainer data = 0; - std::size_t offset = 0; - TupleForEach( - [&data, this, &offset](auto& field) { - this->WriteField(field, data, offset); - offset += field.GetAlignment(); - }, - field.GetValue().GetFields()); - this->WriteData(data, buffer); - } - - void WriteImpl(DataBuffer& buffer) const override { - auto& allFields = this->GetFields(); - TupleForEach([&buffer, this](const auto& field) { this->WriteField(field, buffer); }, allFields); - } -}; - -template -class MessageImplFieldsValidBase : public TBase { - protected: - bool ValidImpl() const override { - // Access fields via interface provided in previous chunk - // auto& allFields = TBase::GetFields(); - //... // validate all the fields - return true; - } -}; - -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/message/OstreamFieldIterator.h b/include/sp/protocol/message/OstreamFieldIterator.h deleted file mode 100644 index 6d26c42..0000000 --- a/include/sp/protocol/message/OstreamFieldIterator.h +++ /dev/null @@ -1,56 +0,0 @@ -// infix_iterator.h -// -// Lifted from Jerry Coffin's 's prefix_ostream_iterator -#pragma once - -#include -#include - -namespace sp { - -template > -class OstreamFieldIterator { - private: - std::basic_ostream* m_Os; - std::string m_Delimiter; - bool m_FirstElem; - - public: - using iterator_category = std::output_iterator_tag; - using value_type = void; - using difference_type = void; - using pointer = void; - using reference = void; - - using char_type = charT; - using traits_type = traits; - using ostream_type = std::basic_ostream; - - OstreamFieldIterator(ostream_type& a_Stream) : m_Os(&a_Stream), m_Delimiter(0), m_FirstElem(true) {} - OstreamFieldIterator(ostream_type& a_Stream, std::string&& a_Delimiter) : - m_Os(&a_Stream), m_Delimiter(std::move(a_Delimiter)), m_FirstElem(true) {} - - auto& operator=(const T& item) { - // Here's the only real change from ostream_iterator: - // Normally, the '*m_Os << item;' would come before the 'if'. - if (!m_FirstElem && !m_Delimiter.empty()) - *m_Os << m_Delimiter; - *m_Os << sp::PrintableField(item); - m_FirstElem = false; - return *this; - } - - auto& operator*() { - return *this; - } - - auto& operator++() { - return *this; - } - - auto& operator++(int) { - return *this; - } -}; - -} // namespace sp diff --git a/src/sp/common/VarInt.cpp b/src/sp/common/VarInt.cpp index a2e0913..a02bf6f 100644 --- a/src/sp/common/VarInt.cpp +++ b/src/sp/common/VarInt.cpp @@ -49,8 +49,4 @@ DataBuffer& operator>>(DataBuffer& in, VarInt& var) { return in; } -std::ostream& operator<<(std::ostream& a_Stream, const PrintableField& a_VarInt) { - return a_Stream << a_VarInt.GetValue().GetValue(); -} - } // namespace sp diff --git a/test/test_file.cpp b/test/test_file.cpp deleted file mode 100644 index f777338..0000000 --- a/test/test_file.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include - -#include -#include - -class CustomPacketHandler : public sp::PacketHandler { - void Handle(const KeepAlivePacket& packet) { - std::cout << "KeepAlive handled ! " << packet.GetKeepAliveId() << "\n"; - } - - void Handle(const DisconnectPacket& packet) { - std::cout << "Disconnect handled ! " << packet.GetReason() << "\n"; - } - - void Handle(const UpgradeTowerPacket& packet) { - std::cout << "UpgradeTower handled !\n"; - } -}; - -using FileStream = sp::io::Stream; - -int main() { - auto handler = std::make_shared(); - - FileStream stream(sp::io::File{"test.txt", sp::io::FileTag::In | sp::io::FileTag::Out}, {}); - stream.GetDispatcher().RegisterHandler(PacketId::Disconnect, handler.get()); - stream.GetDispatcher().RegisterHandler(PacketId::KeepAlive, handler.get()); - - stream.SendMessage(KeepAlivePacket{96}); - stream.SendMessage(KeepAlivePacket{69}); - stream.SendMessage(DisconnectPacket{ - "This is in the " - "fiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiile !"}); - stream.GetOption().m_Enabled = false; - stream.SendMessage(DisconnectPacket{ - "This is in the " - "fiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiile !"}); - - stream.RecieveMessages(); - - return 0; -} \ No newline at end of file diff --git a/test/test_io.cpp b/test/test_io.cpp deleted file mode 100644 index d67c521..0000000 --- a/test/test_io.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include - -#include -#include - -using DataBufferStream = sp::io::Stream; - -class CustomPacketHandler : public sp::PacketHandler { - void Handle(const KeepAlivePacket& packet) { - std::cout << "KeepAlive handled ! " << packet.GetKeepAliveId() << "\n"; - } - - void Handle(const DisconnectPacket& packet) { - std::cout << "Disconnect handled ! " << packet.GetReason() << "\n"; - } - - void Handle(const UpgradeTowerPacket& packet) { - std::cout << "UpgradeTower handled !\n"; - } -}; - -int main() { - auto handler = std::make_shared(); - - DataBufferStream stream; - stream.GetDispatcher().RegisterHandler(PacketId::Disconnect, handler.get()); - - // this should not be dispatched - stream.SendMessage(KeepAlivePacket{96}); - stream.RecieveMessages(); - - stream.GetDispatcher().RegisterHandler(PacketId::KeepAlive, handler.get()); - - stream.SendMessage(KeepAlivePacket{69}); - stream.RecieveMessages(); - stream.SendMessage(DisconnectPacket{"A valid reason"}); - stream.RecieveMessages(); - - return 0; -} \ No newline at end of file diff --git a/test/test_message.cpp b/test/test_message.cpp new file mode 100644 index 0000000..047ab2a --- /dev/null +++ b/test/test_message.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#include +#include + +enum class PacketID { KeepAlive = 0}; + +class PacketHandler; + +using PacketBase = sp::MessageBase; + +template +using Message = sp::ConcreteMessage; + +struct KeepAlivePacket { + std::uint64_t m_KeepAlive; +}; + +using KeepAliveMessage = Message; + +using AllMessages = std::tuple; + +class PacketHandler : public sp::GenericHandler {}; + +class MyHandler : public PacketHandler { + public: + virtual void Handle(const KeepAliveMessage& msg) { + std::cout << "yo !" << "\n"; + } +}; + +using PacketDispatcher = sp::MessageDispatcher; + +using PacketFactory = sp::MessageFactory; + +int main() { + KeepAliveMessage m{5U}; + MyHandler h; + PacketDispatcher d; + d.RegisterHandler(PacketID::KeepAlive, &h); + d.Dispatch(m); + PacketFactory f; + auto message = f.CreateMessage(PacketID::KeepAlive); + d.Dispatch(*message); + return 0; +} \ No newline at end of file diff --git a/test/test_packets.cpp b/test/test_packets.cpp deleted file mode 100644 index 47f0fd4..0000000 --- a/test/test_packets.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include - -#include -#include - -#include -#include - -class KeepAliveHandler : public sp::PacketHandler { - void Handle(const KeepAlivePacket& packet) { - std::cout << "KeepAlive handled !!\n"; - std::cout << packet << std::endl; - } - - void Handle(const DisconnectPacket& packet) { - std::cout << "Disconnect handled !\n"; - } - - void Handle(const UpgradeTowerPacket& packet) { - std::cout << "UpgradeTower handled !\n"; - } -}; - -int main() { - std::map> yes = {{"woa", {5, 8}}, {"insane", {6, 9}}}; - auto upgradeTower = std::make_unique(std::make_tuple(666, 9), 789, yes); - auto keepAlive = std::make_unique(6969); - - sp::PacketMessage* msg = upgradeTower.get(); - - auto handler = std::make_shared(); - msg->Dispatch(*handler); - keepAlive->Dispatch(*handler); - - sp::DataBuffer buffer = msg->Write(); - - std::uint8_t msgId; - buffer >> msgId; - - auto upgradeTower2 = std::make_unique(); - upgradeTower2->Read(buffer); - - std::cout << "Test : " << *msg << "\n"; - - sp::PacketFactory factory; - auto packet = factory.CreateMessage(msgId); - if (packet == nullptr) { - std::cout << "Bad ID !\n"; - return 1; - } - std::cout << (unsigned)packet->GetId() << std::endl; - packet->Dispatch(*handler); - - sp::PacketDispatcher dispatcher; - dispatcher.RegisterHandler(PacketId::KeepAlive, handler.get()); - dispatcher.Dispatch(*packet); - dispatcher.UnregisterHandler(PacketId::KeepAlive, handler.get()); - dispatcher.UnregisterHandler(handler.get()); - - return 0; -} \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index 1785976..1a9d65c 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,5 +1,9 @@ add_rules("mode.debug", "mode.release") +add_requires("boost_pfr") + +set_warnings("all") + set_languages("c++17") local modules = { @@ -71,6 +75,7 @@ target("SimpleProtocol") add_files("src/sp/**.cpp") set_group("Library") set_kind("$(kind)") + add_packages("boost_pfr", {public = true}) add_headerfiles("include/(sp/**.h)", "include/(sp/**.inl)")