From 0b28bde25b3f578438bdcd393fd3bc6f6a74782d Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 8 Feb 2025 20:11:02 +0100 Subject: [PATCH 01/19] test --- include/examples/KeepAlivePacket.h | 11 +++++++++-- src/main.cpp | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/examples/KeepAlivePacket.h b/include/examples/KeepAlivePacket.h index dfa45ae..7cfe3f6 100644 --- a/include/examples/KeepAlivePacket.h +++ b/include/examples/KeepAlivePacket.h @@ -5,9 +5,16 @@ #include enum KeepAlivePacketFields { - KeepAliveId = 0 + KeepAliveId = 0, + TestAlignField = 1, }; -using KeepAliveFields = std::tuple; +using KeepAliveFields = std::tuple< + std::uint64_t, //<- KeepAliveId + sp::BitField, //<- m_Tower + sp::Field //<- m_Upgrade + > +>; DeclarePacket(KeepAlive); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0cde3b6..9eb8d25 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,8 @@ class KeepAliveHandler : public sp::PacketHandler { }; int main() { - auto keepAlive = std::make_unique(69); + auto keepAlive = std::make_unique(69, std::make_tuple(666, 9)); + sp::PacketMessage* msg = keepAlive.get(); KeepAliveHandler handler; -- 2.49.1 From e39f8de89836899a12a8e06108a91c1eb7058871 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 15 Feb 2025 12:39:53 +0100 Subject: [PATCH 02/19] better fields access --- include/examples/DisconnectPacket.h | 13 +++++++++---- include/examples/KeepAlivePacket.h | 27 +++++++++++++++++++++------ include/sp/default/DefaultPacket.h | 20 +++++++++++--------- include/sp/protocol/Field.h | 5 +++++ include/sp/protocol/MessageBase.h | 5 +++++ src/main.cpp | 5 ++++- 6 files changed, 55 insertions(+), 20 deletions(-) diff --git a/include/examples/DisconnectPacket.h b/include/examples/DisconnectPacket.h index 6a69371..c6a51bb 100644 --- a/include/examples/DisconnectPacket.h +++ b/include/examples/DisconnectPacket.h @@ -4,10 +4,15 @@ #include #include -enum DisconnectPacketFields { - Reason = 0 -}; +enum DisconnectPacketFields { Reason = 0 }; using DisconnectFields = std::tuple; -DeclarePacket(Disconnect); \ No newline at end of file +DeclarePacket(Disconnect){ + public: + PacketConstructor(Disconnect) + + const std::string& GetReason() const { + return GetField(); + } +}; diff --git a/include/examples/KeepAlivePacket.h b/include/examples/KeepAlivePacket.h index 7cfe3f6..02b63e2 100644 --- a/include/examples/KeepAlivePacket.h +++ b/include/examples/KeepAlivePacket.h @@ -10,11 +10,26 @@ enum KeepAlivePacketFields { }; using KeepAliveFields = std::tuple< - std::uint64_t, //<- KeepAliveId + std::uint64_t, //<- KeepAliveId sp::BitField, //<- m_Tower - sp::Field //<- m_Upgrade - > ->; + sp::Field, //<- m_Tower + sp::Field //<- m_Upgrade + > + >; -DeclarePacket(KeepAlive); \ No newline at end of file +DeclarePacket(KeepAlive){ + public: + PacketConstructor(KeepAlive) + + std::uint64_t GetKeepAliveId() const { + return GetField(); + } + + std::uint16_t GetTowerId() const { + return GetField().GetField<0>(); + } + + std::uint8_t GetTowerUpgrade() const { + return GetField().GetField<1>(); + } +}; \ No newline at end of file diff --git a/include/sp/default/DefaultPacket.h b/include/sp/default/DefaultPacket.h index 43a0770..63b7ae4 100644 --- a/include/sp/default/DefaultPacket.h +++ b/include/sp/default/DefaultPacket.h @@ -13,15 +13,17 @@ using PacketMessage = Message, // add id() opera option::Handler // add dispatch() operation >; -#define DeclarePacket(packetName) \ - class packetName##Packet : public sp::MessageBase, \ - sp::option::DispatchImpl, sp::option::FieldsImpl> { \ - public: \ - packetName##Packet() {} \ - template \ - packetName##Packet(Args... args) { \ - Construct(args...); \ - } \ +#define PacketConstructor(packetName) \ + packetName##Packet() {} \ + template \ + packetName##Packet(Args... args) { \ + Construct(args...); \ } +#define DeclarePacket(packetName) \ + class packetName##Packet : public sp::MessageBase, \ + sp::option::DispatchImpl, sp::option::FieldsImpl> + + + } // namespace sp diff --git a/include/sp/protocol/Field.h b/include/sp/protocol/Field.h index 6bafa85..dc1f702 100644 --- a/include/sp/protocol/Field.h +++ b/include/sp/protocol/Field.h @@ -40,6 +40,11 @@ class BitField { return std::get(this->GetFields()).GetValue(); } + template + const auto& GetField() const { + return std::get(this->GetFields()).GetValue(); + } + private: template = sizeof...(T), bool> = true> void Apply(const std::tuple& args) {} diff --git a/include/sp/protocol/MessageBase.h b/include/sp/protocol/MessageBase.h index a489b7b..ce9a798 100644 --- a/include/sp/protocol/MessageBase.h +++ b/include/sp/protocol/MessageBase.h @@ -114,6 +114,11 @@ class MessageImplFieldsBase : public TBase { return std::get(GetFields()).GetValue(); } + template + const auto& GetField() const { + return std::get(GetFields()).GetValue(); + } + private: AllFields m_Fields; }; diff --git a/src/main.cpp b/src/main.cpp index 9eb8d25..d6d7347 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,7 +30,10 @@ int main() { auto keepAlive2 = std::make_unique(); keepAlive2->Read(buffer); - std::cout << "KeepAlive2 : " << keepAlive2->GetField() << "\n"; + std::cout << "KeepAlive2 : " << keepAlive2->GetKeepAliveId() << "\n"; + + keepAlive2->GetField().GetField<0>(); + std::cout << "Test : " << (unsigned) keepAlive2->GetTowerId() << "\n"; sp::PacketFactory factory; auto packet = factory.CreateMessage(msgId); -- 2.49.1 From 044b12cdec3267c132d159eed57f33523f8d0395 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:00:01 +0100 Subject: [PATCH 03/19] refactor --- include/examples/DisconnectPacket.h | 4 +- include/sp/common/MacroMap.h | 54 ---- include/sp/common/NonCopyable.h | 25 -- include/sp/misc/Format.h | 38 --- include/sp/misc/Log.h | 32 -- include/sp/misc/Test.h | 70 ----- include/sp/protocol/Message.h | 2 +- include/sp/protocol/MessageInterfaces.h | 278 ------------------ .../{ => message}/MessageInterfaceBuilder.h | 2 +- .../message/MessageInterfaceProcess.h | 105 +++++++ .../sp/protocol/message/MessageInterfaces.h | 7 + .../protocol/message/MessageInterfacesImpl.h | 119 ++++++++ .../message/MessageInterfacesOptions.h | 63 ++++ .../{Options.h => message/MessageOptions.h} | 0 src/sp/common/DataBuffer.cpp | 7 +- src/sp/misc/Log.cpp | 37 --- src/sp/misc/Test.cpp | 14 - 17 files changed, 301 insertions(+), 556 deletions(-) delete mode 100644 include/sp/common/MacroMap.h delete mode 100644 include/sp/common/NonCopyable.h delete mode 100644 include/sp/misc/Format.h delete mode 100644 include/sp/misc/Log.h delete mode 100644 include/sp/misc/Test.h delete mode 100644 include/sp/protocol/MessageInterfaces.h rename include/sp/protocol/{ => message}/MessageInterfaceBuilder.h (96%) create mode 100644 include/sp/protocol/message/MessageInterfaceProcess.h create mode 100644 include/sp/protocol/message/MessageInterfaces.h create mode 100644 include/sp/protocol/message/MessageInterfacesImpl.h create mode 100644 include/sp/protocol/message/MessageInterfacesOptions.h rename include/sp/protocol/{Options.h => message/MessageOptions.h} (100%) delete mode 100644 src/sp/misc/Log.cpp delete mode 100644 src/sp/misc/Test.cpp diff --git a/include/examples/DisconnectPacket.h b/include/examples/DisconnectPacket.h index c6a51bb..ae61f43 100644 --- a/include/examples/DisconnectPacket.h +++ b/include/examples/DisconnectPacket.h @@ -4,7 +4,9 @@ #include #include -enum DisconnectPacketFields { Reason = 0 }; +enum DisconnectPacketFields { + Reason = 0 +}; using DisconnectFields = std::tuple; diff --git a/include/sp/common/MacroMap.h b/include/sp/common/MacroMap.h deleted file mode 100644 index e5afacf..0000000 --- a/include/sp/common/MacroMap.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Created by William Swanson in 2012. - * - * I, William Swanson, dedicate this work to the public domain. - * I waive all rights to the work worldwide under copyright law, - * including all related and neighboring rights, - * to the extent allowed by law. - * - * You can copy, modify, distribute and perform the work, - * even for commercial purposes, all without asking permission. - */ - -#ifndef MAP_H_INCLUDED -#define MAP_H_INCLUDED - -#define EVAL0(...) __VA_ARGS__ -#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__))) -#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) -#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) -#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) -#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) - -#define MAP_END(...) -#define MAP_OUT -#define MAP_COMMA , - -#define MAP_GET_END2() 0, MAP_END -#define MAP_GET_END1(...) MAP_GET_END2 -#define MAP_GET_END(...) MAP_GET_END1 -#define MAP_NEXT0(test, next, ...) next MAP_OUT -#define MAP_NEXT1(test, next) MAP_NEXT0(test, next, 0) -#define MAP_NEXT(test, next) MAP_NEXT1(MAP_GET_END test, next) - -#define MAP0(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP1)(f, peek, __VA_ARGS__) -#define MAP1(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP0)(f, peek, __VA_ARGS__) - -#define MAP_LIST_NEXT1(test, next) MAP_NEXT0(test, MAP_COMMA next, 0) -#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next) - -#define MAP_LIST0(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST1)(f, peek, __VA_ARGS__) -#define MAP_LIST1(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST0)(f, peek, __VA_ARGS__) - -/** - * Applies the function macro `f` to each of the remaining parameters. - */ -#define MAP(f, ...) EVAL(MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -/** - * Applies the function macro `f` to each of the remaining parameters and - * inserts commas between the results. - */ -#define MAP_LIST(f, ...) EVAL(MAP_LIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#endif \ No newline at end of file diff --git a/include/sp/common/NonCopyable.h b/include/sp/common/NonCopyable.h deleted file mode 100644 index 85b155e..0000000 --- a/include/sp/common/NonCopyable.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -/** - * \file NonCopyable.h - * \brief File containing the sp::NonCopyable class - */ - -namespace sp { - -/** - * \class NonCopyable - * \brief Class used to make a class non copyable - * \note Inherit from this class privately to make a class non copyable - */ -class NonCopyable { - public: - NonCopyable(const NonCopyable&) = delete; - NonCopyable& operator=(const NonCopyable&) = delete; - - protected: - NonCopyable() {} - ~NonCopyable() {} -}; - -} // namespace sp diff --git a/include/sp/misc/Format.h b/include/sp/misc/Format.h deleted file mode 100644 index 55ba136..0000000 --- a/include/sp/misc/Format.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -/** - * \file Format.h - * \brief This file contains the definition of the `Format` function. - */ - -#include -#include -#include - -namespace sp { -namespace utils { - -/** - * \brief Formats a string using a format string and variadic arguments. - * - * This function takes a format string and a variable number of arguments and returns a formatted string. - * The format string can contain placeholders that will be replaced by the corresponding arguments. - * - * \param format The format string. - * \param args The variadic arguments to be formatted. - * \return The formatted string. - * \throws std::runtime_error if an error occurs during formatting. - */ -template -std::string Format(const std::string& format, Args... args) { - int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' - if (size <= 0) { - throw std::runtime_error("Error during formatting."); - } - std::unique_ptr buf(new char[size]); - snprintf(buf.get(), static_cast(size), format.c_str(), args...); - return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside -} - -} // namespace utils -} // namespace sp diff --git a/include/sp/misc/Log.h b/include/sp/misc/Log.h deleted file mode 100644 index 4e83c7d..0000000 --- a/include/sp/misc/Log.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -/** - * \file Log.h - * \brief File defining log functions - */ - -#include - -namespace sp { -namespace utils { - -/** - * \brief Logs a normal message. - * \param msg The message to be logged. - */ -void LOG(const std::string& msg); - -/** - * \brief Logs a normal message in debug mode. - * \param msg The message to be logged. - */ -void LOGD(const std::string& msg); - -/** - * \brief Logs an error message. - * \param err The error message to be logged. - */ -void LOGE(const std::string& err); - -} // namespace utils -} // namespace sp diff --git a/include/sp/misc/Test.h b/include/sp/misc/Test.h deleted file mode 100644 index da122c7..0000000 --- a/include/sp/misc/Test.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -/** - * \file Test.h - * \brief File containing unit testing utilities - */ - -#include -#include - -namespace sp { -namespace test { - -/** - * \def SP_TEST_SUCCESSFUL - * \brief Used in tests to indicate that a test was successful - */ -#define SP_TEST_SUCCESSFUL 0 - -/** - * \def SP_TEST_FAILED - * \brief Used in tests to indicate that a test failed - */ -#define SP_TEST_FAILED 1 - -#ifndef __FUNCTION_NAME__ -#ifdef _WIN32 -#define __FUNCTION_NAME__ __FUNCTION__ -#else -#define __FUNCTION_NAME__ __PRETTY_FUNCTION__ -#endif -#endif - -/** - * \def blitz_test_assert - * \param ... The expression to evaluate - * \brief Evaluates the expression and exits the program if not valid. - * \note It works like a basic assert() but also in release mode - */ -#define sp_test_assert(...) \ - if (!static_cast(__VA_ARGS__)) { \ - td::test::LogAssert(#__VA_ARGS__, __FILE__, __LINE__, __FUNCTION_NAME__); \ - std::exit(SP_TEST_FAILED); \ - } - - -/** - * \def blitz_debug_assert - * \param ... The expression to execute - * \brief Assertion without checks in release mode - * \note The expression is always executed. However, in release, no checks are made ! - */ -#ifdef NDEBUG -#define sp_debug_assert(...) __VA_ARGS__ -#else -#define sp_debug_assert sp_test_assert -#endif - - -/** - * \brief Prints an error message associated with a failed assertion - * \param expression The expression that was tested - * \param file The file in which the assertion failed - * \param line The line in the file in which the assertion failed - * \param function The function in which the assertion failed - */ -void LogAssert(const char* expression, const char* file, int line, const char* function); - -} // namespace test -} // namespace sp diff --git a/include/sp/protocol/Message.h b/include/sp/protocol/Message.h index a83ca82..c347b24 100644 --- a/include/sp/protocol/Message.h +++ b/include/sp/protocol/Message.h @@ -3,7 +3,7 @@ // Inspired by // https://alex-robenko.gitbook.io/comms-protocols-cpp -#include +#include namespace sp { diff --git a/include/sp/protocol/MessageInterfaces.h b/include/sp/protocol/MessageInterfaces.h deleted file mode 100644 index bc15cb3..0000000 --- a/include/sp/protocol/MessageInterfaces.h +++ /dev/null @@ -1,278 +0,0 @@ -#pragma once - -#include -#include - -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; -}; - - - - - -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; -}; - - - - - -// 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) { - 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) { - WriteImpl(buffer); - } - - protected: - virtual void WriteImpl(DataBuffer& buffer) = 0; -}; - -// Handler functionality chunk -template -class MessageInterfaceHandlerBase : public TBase { - public: - using HandlerType = typename THandler::HandlerT; - - void Dispatch(HandlerType& handler) { - DispatchImpl(handler); - } - - protected: - virtual void DispatchImpl(HandlerType& handler) = 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) { - this->WriteData(this->GetId(), buffer); - this->WriteImpl(buffer); - } -}; - - - - -// 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; -}; -} // namespace details -} // namespace sp diff --git a/include/sp/protocol/MessageInterfaceBuilder.h b/include/sp/protocol/message/MessageInterfaceBuilder.h similarity index 96% rename from include/sp/protocol/MessageInterfaceBuilder.h rename to include/sp/protocol/message/MessageInterfaceBuilder.h index 4fb0b71..8c34bab 100644 --- a/include/sp/protocol/MessageInterfaceBuilder.h +++ b/include/sp/protocol/message/MessageInterfaceBuilder.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace sp { namespace details { diff --git a/include/sp/protocol/message/MessageInterfaceProcess.h b/include/sp/protocol/message/MessageInterfaceProcess.h new file mode 100644 index 0000000..b6d7da2 --- /dev/null +++ b/include/sp/protocol/message/MessageInterfaceProcess.h @@ -0,0 +1,105 @@ +#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; +}; + +} // 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 new file mode 100644 index 0000000..a1b1176 --- /dev/null +++ b/include/sp/protocol/message/MessageInterfaces.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include +#include +#include diff --git a/include/sp/protocol/message/MessageInterfacesImpl.h b/include/sp/protocol/message/MessageInterfacesImpl.h new file mode 100644 index 0000000..9ccf3f9 --- /dev/null +++ b/include/sp/protocol/message/MessageInterfacesImpl.h @@ -0,0 +1,119 @@ +#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) { + 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) { + WriteImpl(buffer); + } + + protected: + virtual void WriteImpl(DataBuffer& buffer) = 0; +}; + +// Handler functionality chunk +template +class MessageInterfaceHandlerBase : public TBase { + public: + using HandlerType = typename THandler::HandlerT; + + void Dispatch(HandlerType& handler) { + DispatchImpl(handler); + } + + protected: + virtual void DispatchImpl(HandlerType& handler) = 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) { + this->WriteData(this->GetId(), buffer); + this->WriteImpl(buffer); + } +}; + +} // namespace details +} // namespace sp diff --git a/include/sp/protocol/message/MessageInterfacesOptions.h b/include/sp/protocol/message/MessageInterfacesOptions.h new file mode 100644 index 0000000..15ecb06 --- /dev/null +++ b/include/sp/protocol/message/MessageInterfacesOptions.h @@ -0,0 +1,63 @@ +#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; +}; + + + + + +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; +}; + +} // namespace details +} // namespace sp diff --git a/include/sp/protocol/Options.h b/include/sp/protocol/message/MessageOptions.h similarity index 100% rename from include/sp/protocol/Options.h rename to include/sp/protocol/message/MessageOptions.h diff --git a/src/sp/common/DataBuffer.cpp b/src/sp/common/DataBuffer.cpp index 42d424f..36975c5 100644 --- a/src/sp/common/DataBuffer.cpp +++ b/src/sp/common/DataBuffer.cpp @@ -4,9 +4,6 @@ #include #include -#include -#include - namespace sp { DataBuffer::DataBuffer() : m_ReadOffset(0) {} @@ -142,7 +139,7 @@ bool DataBuffer::ReadFile(const std::string& fileName) { m_Buffer = DataBuffer::Data(s.begin(), s.end()); m_ReadOffset = 0; } catch (std::exception& e) { - utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what())); + // utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what())); return false; } return m_Buffer.size() > 0; @@ -154,7 +151,7 @@ bool DataBuffer::WriteFile(const std::string& fileName) const { file.write(reinterpret_cast(m_Buffer.data()), static_cast(m_Buffer.size())); file.flush(); } catch (std::exception& e) { - utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what())); + // utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what())); return false; } return true; diff --git a/src/sp/misc/Log.cpp b/src/sp/misc/Log.cpp deleted file mode 100644 index 829f46d..0000000 --- a/src/sp/misc/Log.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include - - - -#ifdef SP_ANDROID_LOGGING -#include -#else -#include -#endif - -namespace sp { -namespace utils { - -void LOG(const std::string& msg) { -#ifdef SP_ANDROID_LOGGING - __android_log_print(ANDROID_LOG_INFO, "TRACKERS", "%s", msg.c_str()); -#else - std::cout << msg << "\n"; -#endif -} - -void LOGD(const std::string& msg) { -#if !defined(NDEBUG) - LOG(msg); -#endif -} - -void LOGE(const std::string& err) { -#ifdef SP_ANDROID_LOGGING - __android_log_print(ANDROID_LOG_ERROR, "TRACKERS", "%s", err.c_str()); -#else - std::cerr << err << "\n"; -#endif -} - -} // namespace utils -} // namespace sp diff --git a/src/sp/misc/Test.cpp b/src/sp/misc/Test.cpp deleted file mode 100644 index 28cb8ff..0000000 --- a/src/sp/misc/Test.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include - -namespace sp { -namespace test { - -void LogAssert(const char* expression, const char* file, int line, const char* function) { - utils::LOGE(utils::Format("%s:%i: %s: Assertion failed !", file, line, function)); - utils::LOGE(utils::Format(" %i |\t%s;", line, expression)); -} - -} // namespace test -} // namespace sp -- 2.49.1 From d924685e0ce287b4646519d919a531551ef64c11 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:00:59 +0100 Subject: [PATCH 04/19] oups --- include/sp/protocol/message/MessageInterfaceBuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sp/protocol/message/MessageInterfaceBuilder.h b/include/sp/protocol/message/MessageInterfaceBuilder.h index 8c34bab..310e2cd 100644 --- a/include/sp/protocol/message/MessageInterfaceBuilder.h +++ b/include/sp/protocol/message/MessageInterfaceBuilder.h @@ -33,7 +33,7 @@ struct MessageInterfaceBuilder { // add write id functionality if write id and write was provided using Base7 = typename MessageInterfaceProcessWriteId::Type; - // The last Base6 must be taken as final type. + // The last Base7 must be taken as final type. using Type = Base7; }; -- 2.49.1 From baa52d3baac17571c453ef46edc8d3713473a15c Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:02:33 +0100 Subject: [PATCH 05/19] databuffer --- include/sp/common/DataBuffer.h | 4 ++-- src/sp/common/DataBuffer.cpp | 34 +++++++++++----------------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/include/sp/common/DataBuffer.h b/include/sp/common/DataBuffer.h index 7c1f063..32ac95b 100644 --- a/include/sp/common/DataBuffer.h +++ b/include/sp/common/DataBuffer.h @@ -261,13 +261,13 @@ class DataBuffer { * \brief Read a file into the buffer * \param fileName The name of the file to read */ - bool ReadFile(const std::string& fileName); + void 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; + void WriteFile(const std::string& fileName) const; /** * \brief Allocate the buffer on the heap diff --git a/src/sp/common/DataBuffer.cpp b/src/sp/common/DataBuffer.cpp index 36975c5..00d8335 100644 --- a/src/sp/common/DataBuffer.cpp +++ b/src/sp/common/DataBuffer.cpp @@ -130,31 +130,19 @@ std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) { return os; } -bool DataBuffer::ReadFile(const std::string& fileName) { - try { - std::ifstream file(fileName, std::istream::binary); - std::ostringstream ss; - ss << file.rdbuf(); - const std::string& s = ss.str(); - m_Buffer = DataBuffer::Data(s.begin(), s.end()); - m_ReadOffset = 0; - } catch (std::exception& e) { - // utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what())); - return false; - } - return m_Buffer.size() > 0; +void DataBuffer::ReadFile(const std::string& fileName) { + std::ifstream file(fileName, std::istream::binary); + std::ostringstream ss; + ss << file.rdbuf(); + const std::string& s = ss.str(); + m_Buffer = DataBuffer::Data(s.begin(), s.end()); + m_ReadOffset = 0; } -bool DataBuffer::WriteFile(const std::string& fileName) const { - try { - std::ofstream file(fileName, std::ostream::binary); - file.write(reinterpret_cast(m_Buffer.data()), static_cast(m_Buffer.size())); - file.flush(); - } catch (std::exception& e) { - // utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what())); - return false; - } - return true; +void DataBuffer::WriteFile(const std::string& fileName) const { + std::ofstream file(fileName, std::ostream::binary); + file.write(reinterpret_cast(m_Buffer.data()), static_cast(m_Buffer.size())); + file.flush(); } } // namespace sp -- 2.49.1 From 2eab50932f140b1d857c94997122bbd74af79e64 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:09:40 +0100 Subject: [PATCH 06/19] better example --- include/examples/KeepAlivePacket.h | 14 +------------ include/examples/PacketExample.h | 6 ++++-- include/examples/UpgradeTowerPacket.h | 30 +++++++++++++++++++++++++++ src/main.cpp | 18 +++++++++------- 4 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 include/examples/UpgradeTowerPacket.h diff --git a/include/examples/KeepAlivePacket.h b/include/examples/KeepAlivePacket.h index 02b63e2..fe6c266 100644 --- a/include/examples/KeepAlivePacket.h +++ b/include/examples/KeepAlivePacket.h @@ -10,11 +10,7 @@ enum KeepAlivePacketFields { }; using KeepAliveFields = std::tuple< - std::uint64_t, //<- KeepAliveId - sp::BitField, //<- m_Tower - sp::Field //<- m_Upgrade - > + std::uint64_t //<- KeepAliveId >; DeclarePacket(KeepAlive){ @@ -24,12 +20,4 @@ DeclarePacket(KeepAlive){ std::uint64_t GetKeepAliveId() const { return GetField(); } - - std::uint16_t GetTowerId() const { - return GetField().GetField<0>(); - } - - std::uint8_t GetTowerUpgrade() const { - return GetField().GetField<1>(); - } }; \ No newline at end of file diff --git a/include/examples/PacketExample.h b/include/examples/PacketExample.h index 02e18fc..c185c8f 100644 --- a/include/examples/PacketExample.h +++ b/include/examples/PacketExample.h @@ -3,13 +3,15 @@ enum PacketId { KeepAlive = 0, Disconnect, + UpgradeTower, }; #include #include +#include -// they must be in the same order ! -using AllPackets = std::tuple; +// they must be in the same order as in the enum ! +using AllPackets = std::tuple; #include #include \ No newline at end of file diff --git a/include/examples/UpgradeTowerPacket.h b/include/examples/UpgradeTowerPacket.h new file mode 100644 index 0000000..d54e692 --- /dev/null +++ b/include/examples/UpgradeTowerPacket.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +enum UpgradeTowerPacketFields { + m_Tower = 0, + m_Upgrade, +}; + +using UpgradeTowerFields = std::tuple< + sp::BitField, //<- m_Tower + sp::Field //<- m_Upgrade + > + >; + +DeclarePacket(UpgradeTower){ + public: + PacketConstructor(UpgradeTower) + + std::uint16_t GetTowerId() const { + return GetField<0>().GetField(); + } + + std::uint8_t GetTowerUpgrade() const { + return GetField<0>().GetField(); + } +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d6d7347..47f8ae5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,12 +11,17 @@ class KeepAliveHandler : public sp::PacketHandler { void Handle(DisconnectPacket& packet) { std::cout << "Disconnect handled !\n"; } + + // TODO: add constness + void Handle(UpgradeTowerPacket& packet) { + std::cout << "UpgradeTower handled !\n"; + } }; int main() { - auto keepAlive = std::make_unique(69, std::make_tuple(666, 9)); + auto upgradeTower = std::make_unique(std::make_tuple(666, 9)); - sp::PacketMessage* msg = keepAlive.get(); + sp::PacketMessage* msg = upgradeTower.get(); KeepAliveHandler handler; msg->Dispatch(handler); @@ -27,13 +32,10 @@ int main() { std::uint8_t msgId; buffer >> msgId; - auto keepAlive2 = std::make_unique(); - keepAlive2->Read(buffer); + auto upgradeTower2 = std::make_unique(); + upgradeTower2->Read(buffer); - std::cout << "KeepAlive2 : " << keepAlive2->GetKeepAliveId() << "\n"; - - keepAlive2->GetField().GetField<0>(); - std::cout << "Test : " << (unsigned) keepAlive2->GetTowerId() << "\n"; + std::cout << "Test : " << (unsigned) upgradeTower2->GetTowerId() << "\n"; sp::PacketFactory factory; auto packet = factory.CreateMessage(msgId); -- 2.49.1 From 3ad18cacf6f2fe1fda7300e50f870ff44578d4df Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:12:16 +0100 Subject: [PATCH 07/19] add handlers constness --- include/sp/protocol/GenericHandler.h | 100 +++++++++++++-------------- src/main.cpp | 6 +- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/include/sp/protocol/GenericHandler.h b/include/sp/protocol/GenericHandler.h index 9e50a37..dca0813 100644 --- a/include/sp/protocol/GenericHandler.h +++ b/include/sp/protocol/GenericHandler.h @@ -23,26 +23,26 @@ namespace sp using Base = GenericHandler >; public: using Base::Handle; // Don't hide all Handle() functions from base classes - virtual void Handle(T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T5& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T6& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T7& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T8& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T9& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T10& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T11& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T12& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T13& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T14& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T15& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T16& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T17& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T18& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T19& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T20& msg) { this->Handle(static_cast(msg)); } + 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)); } }; // 10 by 10 @@ -55,16 +55,16 @@ namespace sp using Base = GenericHandler >; public: using Base::Handle; // Don't hide all Handle() functions from base classes - virtual void Handle(T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T5& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T6& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T7& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T8& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T9& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T10& msg) { this->Handle(static_cast(msg)); } + 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)); } }; // 5 by 5 @@ -76,11 +76,11 @@ namespace sp using Base = GenericHandler >; public: using Base::Handle; // Don't hide all Handle() functions from base classes - virtual void Handle(T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T5& msg) { this->Handle(static_cast(msg)); } + 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)); } }; // Deal with rest with 4 types @@ -89,11 +89,11 @@ namespace sp { public: virtual ~GenericHandler() {} - virtual void Handle(T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T4& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(TCommon&) { } //Nothing to do + 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 }; // Deal with rest with 3 types @@ -102,10 +102,10 @@ namespace sp { public: virtual ~GenericHandler() {} - virtual void Handle(T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T3& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(TCommon&) { } //Nothing to do + 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 }; // Deal with rest with 2 types @@ -114,9 +114,9 @@ namespace sp { public: virtual ~GenericHandler() {} - virtual void Handle(T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(T2& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(TCommon&) { } //Nothing to do + 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 }; // Deal with rest with 1 type @@ -125,8 +125,8 @@ namespace sp { public: virtual ~GenericHandler() {} - virtual void Handle(T1& msg) { this->Handle(static_cast(msg)); } - virtual void Handle(TCommon&) { } //Nothing to do + virtual void Handle(const T1& msg) { this->Handle(static_cast(msg)); } + virtual void Handle(const TCommon&) { } //Nothing to do }; // Deal with rest with 0 type @@ -135,7 +135,7 @@ namespace sp { public: virtual ~GenericHandler() {} - virtual void Handle(TCommon&) { } //Nothing to do + virtual void Handle(const TCommon&) { } //Nothing to do }; } // sp \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 47f8ae5..6c886f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,16 +4,16 @@ #include class KeepAliveHandler : public sp::PacketHandler { - void Handle(KeepAlivePacket& packet) { + void Handle(const KeepAlivePacket& packet) { std::cout << "KeepAlive handled !\n"; } - void Handle(DisconnectPacket& packet) { + void Handle(const DisconnectPacket& packet) { std::cout << "Disconnect handled !\n"; } // TODO: add constness - void Handle(UpgradeTowerPacket& packet) { + void Handle(const UpgradeTowerPacket& packet) { std::cout << "UpgradeTower handled !\n"; } }; -- 2.49.1 From c1e6409c18f14e39a36082ecee319922366e73a7 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:12:35 +0100 Subject: [PATCH 08/19] idk --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 6c886f4..e447059 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,7 +40,7 @@ int main() { sp::PacketFactory factory; auto packet = factory.CreateMessage(msgId); if (packet == nullptr) { - std::cout << "Mauvais ID !\n"; + std::cout << "Bad ID !\n"; return 1; } std::cout << (unsigned)packet->GetId() << std::endl; -- 2.49.1 From e16ad84865692f0783fbd5748476a9e9c4925f48 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:12:51 +0100 Subject: [PATCH 09/19] oui --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index e447059..c3fff88 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,7 +12,6 @@ class KeepAliveHandler : public sp::PacketHandler { std::cout << "Disconnect handled !\n"; } - // TODO: add constness void Handle(const UpgradeTowerPacket& packet) { std::cout << "UpgradeTower handled !\n"; } -- 2.49.1 From 66835554f16b054e66e1b7a164a71753f983987f Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:33:02 +0100 Subject: [PATCH 10/19] enum class field access --- include/examples/DisconnectPacket.h | 4 ++-- include/examples/KeepAlivePacket.h | 5 ++--- include/examples/UpgradeTowerPacket.h | 7 ++++--- include/sp/protocol/Field.h | 6 ++++++ include/sp/protocol/MessageBase.h | 6 ++++++ 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/examples/DisconnectPacket.h b/include/examples/DisconnectPacket.h index ae61f43..013f7f0 100644 --- a/include/examples/DisconnectPacket.h +++ b/include/examples/DisconnectPacket.h @@ -4,7 +4,7 @@ #include #include -enum DisconnectPacketFields { +enum class DisconnectFieldsE { Reason = 0 }; @@ -15,6 +15,6 @@ DeclarePacket(Disconnect){ PacketConstructor(Disconnect) const std::string& GetReason() const { - return GetField(); + return GetField(); } }; diff --git a/include/examples/KeepAlivePacket.h b/include/examples/KeepAlivePacket.h index fe6c266..770b078 100644 --- a/include/examples/KeepAlivePacket.h +++ b/include/examples/KeepAlivePacket.h @@ -4,9 +4,8 @@ #include #include -enum KeepAlivePacketFields { +enum class KeepAliveFieldsE { KeepAliveId = 0, - TestAlignField = 1, }; using KeepAliveFields = std::tuple< @@ -18,6 +17,6 @@ DeclarePacket(KeepAlive){ PacketConstructor(KeepAlive) std::uint64_t GetKeepAliveId() const { - return GetField(); + return GetField(); } }; \ No newline at end of file diff --git a/include/examples/UpgradeTowerPacket.h b/include/examples/UpgradeTowerPacket.h index d54e692..de69cdf 100644 --- a/include/examples/UpgradeTowerPacket.h +++ b/include/examples/UpgradeTowerPacket.h @@ -4,7 +4,8 @@ #include #include -enum UpgradeTowerPacketFields { + +enum class UpgradeTowerFieldsE { m_Tower = 0, m_Upgrade, }; @@ -21,10 +22,10 @@ DeclarePacket(UpgradeTower){ PacketConstructor(UpgradeTower) std::uint16_t GetTowerId() const { - return GetField<0>().GetField(); + return GetField<0>().GetField(); } std::uint8_t GetTowerUpgrade() const { - return GetField<0>().GetField(); + return GetField<0>().GetField(); } }; \ No newline at end of file diff --git a/include/sp/protocol/Field.h b/include/sp/protocol/Field.h index dc1f702..f0a05dd 100644 --- a/include/sp/protocol/Field.h +++ b/include/sp/protocol/Field.h @@ -45,6 +45,12 @@ class BitField { 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) {} diff --git a/include/sp/protocol/MessageBase.h b/include/sp/protocol/MessageBase.h index ce9a798..61f4947 100644 --- a/include/sp/protocol/MessageBase.h +++ b/include/sp/protocol/MessageBase.h @@ -119,6 +119,12 @@ class MessageImplFieldsBase : public TBase { 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; }; -- 2.49.1 From 3bc5b50905632da3b6ff564421ce54e088f40cb7 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:40:41 +0100 Subject: [PATCH 11/19] refactor: split message classes --- include/sp/protocol/MessageBase.h | 347 +----------------- .../sp/protocol/message/MessageImplBuilder.h | 45 +++ .../sp/protocol/message/MessageImplOptions.h | 61 +++ .../sp/protocol/message/MessageImplProcess.h | 93 +++++ include/sp/protocol/message/MessagesImpl.h | 160 ++++++++ 5 files changed, 365 insertions(+), 341 deletions(-) create mode 100644 include/sp/protocol/message/MessageImplBuilder.h create mode 100644 include/sp/protocol/message/MessageImplOptions.h create mode 100644 include/sp/protocol/message/MessageImplProcess.h create mode 100644 include/sp/protocol/message/MessagesImpl.h diff --git a/include/sp/protocol/MessageBase.h b/include/sp/protocol/MessageBase.h index 61f4947..628233b 100644 --- a/include/sp/protocol/MessageBase.h +++ b/include/sp/protocol/MessageBase.h @@ -2,350 +2,15 @@ #include +#include + +#include +#include +#include + 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 {}; - -} // 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::intmax_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; -}; - - - - - -// 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) 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(Field& field, DataBuffer& buffer) { - this->WriteData(field.GetValue(), buffer); - } - - // writing field in bitfield - template - void WriteField(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 - data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset; - } - - // writing bitfield - template - void WriteField(Field, 0>& field, DataBuffer& buffer) { - 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) override { - auto& allFields = this->GetFields(); - TupleForEach([&buffer, this](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; - } -}; - - - - -// 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; -}; - - - - - -// 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; - - // The last BaseN must be taken as final type. - using Type = Base6; -}; - -} // namespace details template class MessageBase : public details::MessageImplBuilder::Type {}; - } // namespace sp \ No newline at end of file diff --git a/include/sp/protocol/message/MessageImplBuilder.h b/include/sp/protocol/message/MessageImplBuilder.h new file mode 100644 index 0000000..2ae61fd --- /dev/null +++ b/include/sp/protocol/message/MessageImplBuilder.h @@ -0,0 +1,45 @@ +#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; + + // The last BaseN must be taken as final type. + using Type = Base6; +}; + +} // namespace details +} // namespace sp diff --git a/include/sp/protocol/message/MessageImplOptions.h b/include/sp/protocol/message/MessageImplOptions.h new file mode 100644 index 0000000..18b0fc2 --- /dev/null +++ b/include/sp/protocol/message/MessageImplOptions.h @@ -0,0 +1,61 @@ +#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 {}; + +} // 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::intmax_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 new file mode 100644 index 0000000..c377df1 --- /dev/null +++ b/include/sp/protocol/message/MessageImplProcess.h @@ -0,0 +1,93 @@ +#pragma once + +namespace sp { +namespace details { + + + +// 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/MessagesImpl.h b/include/sp/protocol/message/MessagesImpl.h new file mode 100644 index 0000000..00a5b45 --- /dev/null +++ b/include/sp/protocol/message/MessagesImpl.h @@ -0,0 +1,160 @@ +#pragma once + +namespace sp { +namespace details { + + + +// 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) 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(Field& field, DataBuffer& buffer) { + this->WriteData(field.GetValue(), buffer); + } + + // writing field in bitfield + template + void WriteField(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 + data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset; + } + + // writing bitfield + template + void WriteField(Field, 0>& field, DataBuffer& buffer) { + 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) override { + auto& allFields = this->GetFields(); + TupleForEach([&buffer, this](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 -- 2.49.1 From c669e459dd21f59570569e3d66b9fcc0cb61b3b2 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 18 Feb 2025 19:50:59 +0100 Subject: [PATCH 12/19] refactor xmake.lua --- xmake.lua | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/xmake.lua b/xmake.lua index 71fed3a..5229937 100644 --- a/xmake.lua +++ b/xmake.lua @@ -2,15 +2,24 @@ add_rules("mode.debug", "mode.release") set_languages("c++17") -add_requires("enet6") - target("SimpleProtocolLib") - add_includedirs("include", {public = true}) - set_kind("binary") - add_files("src/**.cpp") - add_packages("enet6", {public = true}) + add_includedirs("include") + add_files("src/sp/**.cpp") + set_kind("static") + -- handle shared/static kind + if is_plat("wasm") or has_config("static") then + set_kind("static") + else + set_kind("shared") + end +target("SimpleProtocolLibMain") + set_kind("binary") + add_includedirs("include") + add_deps("SimpleProtocolLib") + add_files("src/main.cpp") + -- Tests for _, file in ipairs(os.files("test/**.cpp")) do -- 2.49.1 From 8762222e0fd07aad1b613ff84e1960e52d9f144e Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 22 Feb 2025 22:05:53 +0100 Subject: [PATCH 13/19] add header files for install --- xmake.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/xmake.lua b/xmake.lua index 5229937..ba0d1ec 100644 --- a/xmake.lua +++ b/xmake.lua @@ -4,6 +4,7 @@ set_languages("c++17") target("SimpleProtocolLib") add_includedirs("include") + add_headerfiles("include/sp/**.h") add_files("src/sp/**.cpp") set_kind("static") -- handle shared/static kind -- 2.49.1 From 992a6eeca0f416b776bdb9a94e22030edeca29e0 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 22 Feb 2025 22:10:54 +0100 Subject: [PATCH 14/19] refactor xmake.lua --- xmake.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xmake.lua b/xmake.lua index ba0d1ec..6d99c4e 100644 --- a/xmake.lua +++ b/xmake.lua @@ -4,9 +4,8 @@ set_languages("c++17") target("SimpleProtocolLib") add_includedirs("include") - add_headerfiles("include/sp/**.h") + add_headerfiles("include/(sp/**.h)") add_files("src/sp/**.cpp") - set_kind("static") -- handle shared/static kind if is_plat("wasm") or has_config("static") then set_kind("static") -- 2.49.1 From 3bc1f605315c45b3d5395ff419a3ff54cdd61116 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 22 Feb 2025 22:32:36 +0100 Subject: [PATCH 15/19] jsp --- xmake.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/xmake.lua b/xmake.lua index 6d99c4e..7e7c83b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -5,6 +5,7 @@ set_languages("c++17") target("SimpleProtocolLib") add_includedirs("include") add_headerfiles("include/(sp/**.h)") + set_group("Library") add_files("src/sp/**.cpp") -- handle shared/static kind if is_plat("wasm") or has_config("static") then -- 2.49.1 From d99137d78de463382828dc07fe88957d3342b054 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 22 Feb 2025 22:51:13 +0100 Subject: [PATCH 16/19] yes --- xmake.lua | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/xmake.lua b/xmake.lua index 7e7c83b..ae11424 100644 --- a/xmake.lua +++ b/xmake.lua @@ -3,16 +3,11 @@ add_rules("mode.debug", "mode.release") set_languages("c++17") target("SimpleProtocolLib") - add_includedirs("include") + add_includedirs("include", {public = true}) add_headerfiles("include/(sp/**.h)") set_group("Library") add_files("src/sp/**.cpp") - -- handle shared/static kind - if is_plat("wasm") or has_config("static") then - set_kind("static") - else - set_kind("shared") - end + set_kind("$(kind)") target("SimpleProtocolLibMain") -- 2.49.1 From 014db341167d789c6105d0ae74e7152c9db2ef9b Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 23 Feb 2025 10:35:47 +0100 Subject: [PATCH 17/19] refactor --- src/main.cpp => test/test_packets.cpp | 0 xmake.lua | 82 +-------------------------- 2 files changed, 2 insertions(+), 80 deletions(-) rename src/main.cpp => test/test_packets.cpp (100%) diff --git a/src/main.cpp b/test/test_packets.cpp similarity index 100% rename from src/main.cpp rename to test/test_packets.cpp diff --git a/xmake.lua b/xmake.lua index ae11424..0c1c8af 100644 --- a/xmake.lua +++ b/xmake.lua @@ -3,20 +3,12 @@ add_rules("mode.debug", "mode.release") set_languages("c++17") target("SimpleProtocolLib") - add_includedirs("include", {public = true}) + add_includedirs("include") add_headerfiles("include/(sp/**.h)") set_group("Library") add_files("src/sp/**.cpp") set_kind("$(kind)") - -target("SimpleProtocolLibMain") - set_kind("binary") - add_includedirs("include") - add_deps("SimpleProtocolLib") - add_files("src/main.cpp") - - -- Tests for _, file in ipairs(os.files("test/**.cpp")) do local name = path.basename(file) @@ -24,79 +16,9 @@ for _, file in ipairs(os.files("test/**.cpp")) do set_kind("binary") add_files(file) - - set_default(false) + add_includedirs("include") add_deps("SimpleProtocolLib") add_tests("compile_and_run") end --- --- If you want to known more usage about xmake, please see https://xmake.io --- --- ## FAQ --- --- You can enter the project directory firstly before building project. --- --- $ cd projectdir --- --- 1. How to build project? --- --- $ xmake --- --- 2. How to configure project? --- --- $ xmake f -p [macosx|linux|iphoneos ..] -a [x86_64|i386|arm64 ..] -m [debug|release] --- --- 3. Where is the build output directory? --- --- The default output directory is `./build` and you can configure the output directory. --- --- $ xmake f -o outputdir --- $ xmake --- --- 4. How to run and debug target after building project? --- --- $ xmake run [targetname] --- $ xmake run -d [targetname] --- --- 5. How to install target to the system directory or other output directory? --- --- $ xmake install --- $ xmake install -o installdir --- --- 6. Add some frequently-used compilation flags in xmake.lua --- --- @code --- -- add debug and release modes --- add_rules("mode.debug", "mode.release") --- --- -- add macro definition --- add_defines("NDEBUG", "_GNU_SOURCE=1") --- --- -- set warning all as error --- set_warnings("all", "error") --- --- -- set language: c99, c++11 --- set_languages("c99", "c++11") --- --- -- set optimization: none, faster, fastest, smallest --- set_optimize("fastest") --- --- -- add include search directories --- add_includedirs("/usr/include", "/usr/local/include") --- --- -- add link libraries and search directories --- add_links("tbox") --- add_linkdirs("/usr/local/lib", "/usr/lib") --- --- -- add system link libraries --- add_syslinks("z", "pthread") --- --- -- add compilation and link flags --- add_cxflags("-stdnolib", "-fno-strict-aliasing") --- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true}) --- --- @endcode --- - -- 2.49.1 From 734154e9f61abf978c3e092478031fe908507664 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 23 Feb 2025 10:36:53 +0100 Subject: [PATCH 18/19] ref --- include/sp/protocol/Field.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sp/protocol/Field.h b/include/sp/protocol/Field.h index f0a05dd..7645546 100644 --- a/include/sp/protocol/Field.h +++ b/include/sp/protocol/Field.h @@ -114,6 +114,6 @@ template struct FieldsBuilder { using Type = sp::tuple_cat_t>, typename FieldsBuilder::Type>; }; -} // namespace details +} // namespace details } // namespace sp -- 2.49.1 From 99fb052dde2d7f197bce2130874bf5d2182e474f Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 23 Feb 2025 10:38:49 +0100 Subject: [PATCH 19/19] good enough --- include/sp/default/DefaultPacket.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/sp/default/DefaultPacket.h b/include/sp/default/DefaultPacket.h index 63b7ae4..24e8156 100644 --- a/include/sp/default/DefaultPacket.h +++ b/include/sp/default/DefaultPacket.h @@ -6,12 +6,13 @@ namespace sp { class PacketHandler; -using PacketMessage = Message, // add id() operation - option::ReadOperations, // add read() operation - option::WriteOperations, // add write() operation - option::WriteId, // write id before data - option::Handler // add dispatch() operation - >; +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 +>; #define PacketConstructor(packetName) \ packetName##Packet() {} \ -- 2.49.1