From e8367cd91c07913f5995b3eaae83b4a564344f9e Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Tue, 4 Mar 2025 12:01:15 +0100 Subject: [PATCH] MessagePrinter (Fixes #2) --- include/examples/UpgradeTowerPacket.h | 3 +- include/sp/common/Reflection.h | 26 ++++++ include/sp/protocol/Field.h | 15 ++-- include/sp/protocol/MessagePrinter.h | 19 +++++ .../sp/protocol/message/MessageImplOptions.h | 6 +- .../sp/protocol/message/MessagePrinterImpl.h | 81 +++++++++++++++++++ include/sp/protocol/message/MessagesImpl.h | 4 +- test/test_packets.cpp | 10 ++- 8 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 include/sp/common/Reflection.h create mode 100644 include/sp/protocol/MessagePrinter.h create mode 100644 include/sp/protocol/message/MessagePrinterImpl.h diff --git a/include/examples/UpgradeTowerPacket.h b/include/examples/UpgradeTowerPacket.h index de69cdf..1ae4821 100644 --- a/include/examples/UpgradeTowerPacket.h +++ b/include/examples/UpgradeTowerPacket.h @@ -14,7 +14,8 @@ using UpgradeTowerFields = std::tuple< sp::BitField, //<- m_Tower sp::Field //<- m_Upgrade - > + >, + sp::VarInt //<- just for testing >; DeclarePacket(UpgradeTower){ diff --git a/include/sp/common/Reflection.h b/include/sp/common/Reflection.h new file mode 100644 index 0000000..0fc4150 --- /dev/null +++ b/include/sp/common/Reflection.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +namespace sp { + +template +std::string GetClassName(const T& a_Value) { + int status; + char* demangled = abi::__cxa_demangle(typeid(a_Value).name(), 0, 0, &status); + if (status != 0) + return ""; + return std::string(demangled); +} + +template +std::string GetClassName() { + int status; + char* demangled = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status); + if (status != 0) + return ""; + return std::string(demangled); +} + +} // namespace sp diff --git a/include/sp/protocol/Field.h b/include/sp/protocol/Field.h index 7645546..f593c5f 100644 --- a/include/sp/protocol/Field.h +++ b/include/sp/protocol/Field.h @@ -70,29 +70,32 @@ class BitField { * \tparam ValueType the type of the value to store * \tparam IAlignment 0 means no alignment */ -template +template class Field { public: + using StorageType = ValueType; + static constexpr std::size_t AlignmentValue = IAlignment; + // Provide an access to the stored value - ValueType& GetValue() { + StorageType& GetValue() { return m_Value; } - const ValueType& GetValue() const { + const StorageType& GetValue() const { return m_Value; } - Field& operator=(const ValueType& value) { + Field& operator=(const StorageType& value) { m_Value = value; return *this; } - constexpr int GetAlignment() const { + constexpr std::size_t GetAlignment() const { return IAlignment; } private: - ValueType m_Value; + StorageType m_Value; }; namespace details { diff --git a/include/sp/protocol/MessagePrinter.h b/include/sp/protocol/MessagePrinter.h new file mode 100644 index 0000000..8885c49 --- /dev/null +++ b/include/sp/protocol/MessagePrinter.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +/** + * \brief Prints a message in a human readable string + */ +template +std::ostream& operator<<(std::ostream& a_Stream, const sp::MessageBase& a_Message) { + a_Stream + << sp::GetClassName(a_Message) + << sp::details::IdPrinter::PrintMessageId() + << "[" + << sp::details::PrintFields(a_Message.GetFields()) + << "]"; + return a_Stream; +} diff --git a/include/sp/protocol/message/MessageImplOptions.h b/include/sp/protocol/message/MessageImplOptions.h index 18b0fc2..5a23f50 100644 --- a/include/sp/protocol/message/MessageImplOptions.h +++ b/include/sp/protocol/message/MessageImplOptions.h @@ -4,7 +4,7 @@ namespace sp { namespace option { // Provide static numeric ID, to facilitate implementation of GetIdImpl() -template +template struct StaticNumIdImpl {}; // Facilitate implementation of DispatchImpl() @@ -39,10 +39,10 @@ struct MessageImplParsedOptions<> { -template +template struct MessageImplParsedOptions, TOptions...> : public MessageImplParsedOptions { static const bool HasStaticNumIdImpl = true; - static const std::intmax_t MsgId = TId; + static const std::uintmax_t MsgId = TId; }; template diff --git a/include/sp/protocol/message/MessagePrinterImpl.h b/include/sp/protocol/message/MessagePrinterImpl.h new file mode 100644 index 0000000..981f0e3 --- /dev/null +++ b/include/sp/protocol/message/MessagePrinterImpl.h @@ -0,0 +1,81 @@ +#pragma once + +#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) + ")"; + } +}; + +template +std::string PrintData(const T& a_Data) { + std::stringstream sStream; + sStream << a_Data; + return sStream.str(); +} + +template <> +std::string PrintData(const char& a_Data) { + return std::to_string(a_Data); +} + +template <> +std::string PrintData(const unsigned char& a_Data) { + return std::to_string(a_Data); +} + +template +std::string PrintFields(const std::tuple& a_Fields); + +template +struct FieldPrinter { + static std::string PrintField(const sp::Field& a_Field) { + return GetClassName() + "=" + PrintData(a_Field.GetValue()); + } +}; + +template +struct FieldPrinter, IAlignment> { + static std::string PrintField(const sp::Field, IAlignment>& a_Field) { + return "BitField<" + GetClassName() + ">[" + PrintFields(a_Field.GetValue().GetFields()) + "]"; + } +}; + +template +std::string PrintFields(const std::tuple& a_Fields) { + std::string concat; + TupleForEach( + [&concat](const auto& a_Field) { + using TField = typename std::decay::type; + constexpr std::size_t alignment = TField::AlignmentValue; + concat += FieldPrinter::PrintField(a_Field) + ", "; + }, + a_Fields); + return concat.substr(0, concat.size() - 2); +} + +} // namespace details +} // namespace sp diff --git a/include/sp/protocol/message/MessagesImpl.h b/include/sp/protocol/message/MessagesImpl.h index fd4838a..91875f2 100644 --- a/include/sp/protocol/message/MessagesImpl.h +++ b/include/sp/protocol/message/MessagesImpl.h @@ -81,7 +81,7 @@ class MessageImplFieldsReadBase : public TBase { } // reading field in bitfield - template + 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 @@ -118,7 +118,7 @@ class MessageImplFieldsWriteBase : public TBase { } // writing field in bitfield - template + 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 diff --git a/test/test_packets.cpp b/test/test_packets.cpp index b17f582..c22baad 100644 --- a/test/test_packets.cpp +++ b/test/test_packets.cpp @@ -5,10 +5,12 @@ #include #include +#include class KeepAliveHandler : public sp::PacketHandler { void Handle(const KeepAlivePacket& packet) { - std::cout << "KeepAlive handled !\n"; + std::cout << "KeepAlive handled !!\n"; + std::cout << packet << std::endl; } void Handle(const DisconnectPacket& packet) { @@ -21,12 +23,14 @@ class KeepAliveHandler : public sp::PacketHandler { }; int main() { - auto upgradeTower = std::make_unique(std::make_tuple(666, 9)); + auto upgradeTower = std::make_unique(std::make_tuple(666, 9), 789); + 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(); @@ -36,7 +40,7 @@ int main() { auto upgradeTower2 = std::make_unique(); upgradeTower2->Read(buffer); - std::cout << "Test : " << (unsigned)upgradeTower2->GetTowerId() << "\n"; + std::cout << "Test : " << *upgradeTower2 << "\n"; sp::PacketFactory factory; auto packet = factory.CreateMessage(msgId);