Compare commits
3 Commits
e8367cd91c
...
v1.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
| 77356ce749 | |||
| 7f8d9e3f96 | |||
| 81c9dbadd6 |
@@ -6,7 +6,7 @@
|
||||
namespace sp {
|
||||
|
||||
template <typename T>
|
||||
std::string GetClassName(const T& a_Value) {
|
||||
std::string GetBasicClassName(const T& a_Value) {
|
||||
int status;
|
||||
char* demangled = abi::__cxa_demangle(typeid(a_Value).name(), 0, 0, &status);
|
||||
if (status != 0)
|
||||
@@ -15,7 +15,7 @@ std::string GetClassName(const T& a_Value) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string GetClassName() {
|
||||
std::string GetBasicClassName() {
|
||||
int status;
|
||||
char* demangled = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
|
||||
if (status != 0)
|
||||
@@ -23,4 +23,38 @@ std::string GetClassName() {
|
||||
return std::string(demangled);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct Reflector {
|
||||
static std::string GetClassName() {
|
||||
return GetBasicClassName<T>();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Reflector<std::string> {
|
||||
static std::string GetClassName() {
|
||||
return "std::string";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct Reflector<std::map<K, V>> {
|
||||
static std::string GetClassName();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Reflector<std::vector<T>> {
|
||||
static std::string GetClassName();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::string Reflector<std::vector<T>>::GetClassName() {
|
||||
return "std::vector<" + Reflector<T>::GetClassName() + ">";
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
std::string Reflector<std::map<K, V>>::GetClassName() {
|
||||
return "std::map<" + Reflector<K>::GetClassName() + ", " + Reflector<V>::GetClassName() + ">";
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace sp {
|
||||
|
||||
@@ -50,4 +51,48 @@ void TupleForEach(TFunc&& func, TTuple&& tuple) {
|
||||
details::TupleForEachHelper<TupleSize>::Exec(std::forward<TTuple>(tuple), std::forward<TFunc>(func));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename T, typename U = void>
|
||||
struct is_mappish_impl : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_mappish_impl<T, std::void_t<typename T::key_type, typename T::mapped_type,
|
||||
decltype(std::declval<T&>()[std::declval<const typename T::key_type&>()])>> : std::true_type {};
|
||||
|
||||
template <typename T, typename U = void>
|
||||
struct is_vectish_impl : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_vectish_impl<T,
|
||||
std::void_t<typename T::value_type, decltype(std::declval<T&>()[std::declval<const typename T::value_type&>()])>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename U = void>
|
||||
struct is_pairish_impl : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_pairish_impl<T,
|
||||
std::void_t<typename T::first_type, decltype(std::declval<T&>()[std::declval<const typename T::first_type&>()])>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
using is_general_t = std::integral_constant<bool,
|
||||
(std::is_same_v<T, std::string> || (!std::is_same_v<T, char> && !std::is_same_v<T, unsigned char> && !std::is_arithmetic_v<T> &&
|
||||
!is_pairish_impl<T>::value && !is_mappish_impl<T>::value && !is_vectish_impl<T>::value))>;
|
||||
|
||||
template <typename T>
|
||||
using is_primitive =
|
||||
std::integral_constant<bool, std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_arithmetic_v<T>>;
|
||||
|
||||
} // namespace details
|
||||
|
||||
} // namespace sp
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <sp/protocol/MessagePrinter.h>
|
||||
|
||||
namespace sp {
|
||||
|
||||
@@ -56,11 +56,11 @@ class VarInt {
|
||||
* \param var The variable integer to deserialize
|
||||
*/
|
||||
friend DataBuffer& operator>>(DataBuffer& in, VarInt& var);
|
||||
|
||||
/**
|
||||
* \brief overriding stream operator
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& a_Stream, const sp::VarInt& a_VarInt);
|
||||
};
|
||||
|
||||
template<>
|
||||
inline std::string PrintData(const VarInt& a_VarInt) {
|
||||
return PrintData(a_VarInt.GetValue());
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
|
||||
@@ -11,8 +11,9 @@ using PacketMessage = Message<
|
||||
option::ReadOperations, // add read() operation
|
||||
option::WriteOperations, // add write() operation
|
||||
option::WriteId, // write id before data
|
||||
option::Handler<PacketHandler> // add dispatch() operation
|
||||
>;
|
||||
option::Handler<PacketHandler>, // add dispatch() operation
|
||||
option::DebugPrint // add ToString() operator
|
||||
>;
|
||||
|
||||
#define PacketConstructor(packetName) \
|
||||
packetName##Packet() {} \
|
||||
@@ -23,7 +24,8 @@ using PacketMessage = Message<
|
||||
|
||||
#define DeclarePacket(packetName) \
|
||||
class packetName##Packet : public sp::MessageBase<sp::PacketMessage, sp::option::StaticNumIdImpl<packetName>, \
|
||||
sp::option::DispatchImpl<packetName##Packet>, sp::option::FieldsImpl<packetName##Fields>>
|
||||
sp::option::DispatchImpl<packetName##Packet>, sp::option::FieldsImpl<packetName##Fields>>, \
|
||||
sp::option::ToStringImpl<packetName##Packet>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14,3 +14,5 @@ template <typename TBase, typename... TOptions>
|
||||
class MessageBase : public details::MessageImplBuilder<TBase, TOptions...>::Type {};
|
||||
|
||||
} // namespace sp
|
||||
|
||||
#include <sp/protocol/message/MessagePrinterImpl.h>
|
||||
@@ -1,19 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <sp/common/Reflection.h>
|
||||
#include <sp/protocol/message/MessagePrinterImpl.h>
|
||||
#include <map>
|
||||
#include <sp/common/Templates.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \brief Prints a message in a human readable string
|
||||
*/
|
||||
template <typename TBase, typename... TOptions>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const sp::MessageBase<TBase, TOptions...>& a_Message) {
|
||||
a_Stream
|
||||
<< sp::GetClassName(a_Message)
|
||||
<< sp::details::IdPrinter<TOptions...>::PrintMessageId()
|
||||
<< "["
|
||||
<< sp::details::PrintFields(a_Message.GetFields())
|
||||
<< "]";
|
||||
return a_Stream;
|
||||
namespace sp {
|
||||
|
||||
template <typename T, std::enable_if_t<details::is_general_t<T>::value, bool> = true>
|
||||
inline std::string PrintData(const T& a_Data);
|
||||
|
||||
template <typename T, std::enable_if_t<details::is_primitive<T>::value, bool> = true>
|
||||
inline std::string PrintData(T a_Data) {
|
||||
return std::to_string(a_Data);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string PrintData(const std::string& a_Data) {
|
||||
return "\"" + a_Data + "\"";
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
std::string PrintData(const std::pair<K, V>& a_Data);
|
||||
|
||||
template <typename K, typename V>
|
||||
std::string PrintData(const std::map<K, V>& a_Data);
|
||||
|
||||
template <typename T>
|
||||
std::string PrintData(const std::vector<T>& a_Data);
|
||||
|
||||
template <typename K, typename V>
|
||||
std::string PrintData(const std::pair<K, V>& a_Data) {
|
||||
return "{" + PrintData(a_Data.first) + " => " + PrintData(a_Data.second) + "}";
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
std::string PrintData(const std::map<K, V>& a_Data) {
|
||||
std::string result = "{";
|
||||
for (const auto& pair : a_Data) {
|
||||
result += PrintData(pair) + ", ";
|
||||
}
|
||||
return result.substr(0, result.size() - 2) + "}";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string PrintData(const std::vector<T>& a_Data) {
|
||||
std::string result = "{";
|
||||
for (const T& value : a_Data) {
|
||||
result += PrintData(value) + ", ";
|
||||
}
|
||||
return result.substr(0, result.size() - 2) + "}";
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
@@ -37,8 +37,12 @@ struct MessageImplBuilder {
|
||||
static const bool HasValidImpl = InterfaceOptions::HasValid && ImplOptions::HasFieldsImpl;
|
||||
using Base6 = typename MessageImplProcessValidFields<Base5, HasValidImpl>::Type;
|
||||
|
||||
// Provide ToStringImpl() if possible
|
||||
static const bool HasToStringImpl = InterfaceOptions::HasToString;
|
||||
using Base7 = typename MessageImplProcessToString<Base6, ImplOptions, HasToStringImpl>::Type;
|
||||
|
||||
// The last BaseN must be taken as final type.
|
||||
using Type = Base6;
|
||||
using Type = Base7;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
@@ -16,6 +16,11 @@ struct DispatchImpl {};
|
||||
template <typename TFields>
|
||||
struct FieldsImpl {};
|
||||
|
||||
// Print fields of the message, facilitate implementation of
|
||||
// ToStringImpl()
|
||||
template <typename TActual>
|
||||
struct ToStringImpl {};
|
||||
|
||||
} // namespace option
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,20 @@ namespace sp {
|
||||
namespace details {
|
||||
|
||||
|
||||
// ToString impl
|
||||
template <typename TBase, typename ParsedImplOptions, bool TImplement>
|
||||
struct MessageImplProcessToString;
|
||||
|
||||
template <typename TBase, typename ParsedImplOptions>
|
||||
struct MessageImplProcessToString<TBase, ParsedImplOptions, true> {
|
||||
using Type = MessageImplToStringBase<TBase, typename ParsedImplOptions::ActualMessage>;
|
||||
};
|
||||
|
||||
template <typename TBase, typename ParsedImplOptions>
|
||||
struct MessageImplProcessToString<TBase, ParsedImplOptions, false> {
|
||||
using Type = TBase;
|
||||
};
|
||||
|
||||
|
||||
// id impl
|
||||
template <typename TBase, typename ParsedImplOptions, bool TImplement>
|
||||
|
||||
@@ -33,8 +33,11 @@ struct MessageInterfaceBuilder {
|
||||
// add write id functionality if write id and write was provided
|
||||
using Base7 = typename MessageInterfaceProcessWriteId<Base6, ParsedOptions::HasWriteId && ParsedOptions::HasWriteOperations>::Type;
|
||||
|
||||
// The last Base7 must be taken as final type.
|
||||
using Type = Base7;
|
||||
// add ToString() if HasToString was provided
|
||||
using Base8 = typename MessageInterfaceProcessToString<Base7, ParsedOptions::HasToString>::Type;
|
||||
|
||||
// The last Base8 must be taken as final type.
|
||||
using Type = Base8;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
@@ -101,5 +101,19 @@ struct MessageInterfaceProcessWriteId<TBase, false> {
|
||||
using Type = TBase;
|
||||
};
|
||||
|
||||
// Build to string
|
||||
template <typename TBase, bool THasToString>
|
||||
struct MessageInterfaceProcessToString;
|
||||
|
||||
template <typename TBase>
|
||||
struct MessageInterfaceProcessToString<TBase, true> {
|
||||
using Type = MessageInterfaceToStringBase<TBase>;
|
||||
};
|
||||
|
||||
template <typename TBase>
|
||||
struct MessageInterfaceProcessToString<TBase, false> {
|
||||
using Type = TBase;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace sp
|
||||
@@ -129,5 +129,17 @@ class MessageInterfaceWriteIdBase : public TBase {
|
||||
}
|
||||
};
|
||||
|
||||
// Debug print functionality chunk
|
||||
template <typename TBase>
|
||||
class MessageInterfaceToStringBase : public TBase {
|
||||
public:
|
||||
std::string ToString() const {
|
||||
return ToStringImpl();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::string ToStringImpl() const = 0;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace sp
|
||||
|
||||
@@ -16,6 +16,7 @@ struct MessageInterfaceParsedOptions<> {
|
||||
static const bool HasWriteId = false;
|
||||
static const bool HasHandler = false;
|
||||
static const bool HasValid = false;
|
||||
static const bool HasToString = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,5 +60,10 @@ struct MessageInterfaceParsedOptions<option::ValidCheckInterface, TOptions...> :
|
||||
static const bool HasValid = true;
|
||||
};
|
||||
|
||||
template <typename... TOptions>
|
||||
struct MessageInterfaceParsedOptions<option::DebugPrint, TOptions...> : public MessageInterfaceParsedOptions<TOptions...> {
|
||||
static const bool HasToString = true;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace sp
|
||||
|
||||
@@ -24,6 +24,9 @@ struct LittleEndian {};
|
||||
// Include validity check in public interface
|
||||
struct ValidCheckInterface {};
|
||||
|
||||
// Add a ToString() method containing fields
|
||||
struct DebugPrint {};
|
||||
|
||||
// Define handler class
|
||||
template <typename T>
|
||||
struct Handler {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <sp/protocol/MessageBase.h>
|
||||
#include <sp/common/Reflection.h>
|
||||
#include <sp/common/Templates.h>
|
||||
#include <sp/protocol/MessagePrinter.h>
|
||||
|
||||
namespace sp {
|
||||
namespace details {
|
||||
@@ -30,37 +31,20 @@ struct IdPrinter<option::StaticNumIdImpl<TId>, TOptions...> {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::string PrintData(const T& a_Data) {
|
||||
std::stringstream sStream;
|
||||
sStream << a_Data;
|
||||
return sStream.str();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string PrintData<char>(const char& a_Data) {
|
||||
return std::to_string(a_Data);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string PrintData<unsigned char>(const unsigned char& a_Data) {
|
||||
return std::to_string(a_Data);
|
||||
}
|
||||
|
||||
template <typename... TFields>
|
||||
std::string PrintFields(const std::tuple<TFields...>& a_Fields);
|
||||
|
||||
template <typename TField, unsigned int IAlignment>
|
||||
struct FieldPrinter {
|
||||
static std::string PrintField(const sp::Field<TField, IAlignment>& a_Field) {
|
||||
return GetClassName<TField>() + "=" + PrintData(a_Field.GetValue());
|
||||
return Reflector<TField>::GetClassName() + "=" + PrintData(a_Field.GetValue());
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned int IAlignment, typename TContainer, typename... TFields>
|
||||
struct FieldPrinter<sp::BitField<TContainer, TFields...>, IAlignment> {
|
||||
static std::string PrintField(const sp::Field<sp::BitField<TContainer, TFields...>, IAlignment>& a_Field) {
|
||||
return "BitField<" + GetClassName<TContainer>() + ">[" + PrintFields(a_Field.GetValue().GetFields()) + "]";
|
||||
struct FieldPrinter<BitField<TContainer, TFields...>, IAlignment> {
|
||||
static std::string PrintField(const Field<BitField<TContainer, TFields...>, IAlignment>& a_Field) {
|
||||
return "BitField<" + Reflector<TContainer>::GetClassName() + ">[" + PrintFields(a_Field.GetValue().GetFields()) + "]";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,5 +61,11 @@ std::string PrintFields(const std::tuple<TFields...>& a_Fields) {
|
||||
return concat.substr(0, concat.size() - 2);
|
||||
}
|
||||
|
||||
template <typename TBase, typename... TOptions>
|
||||
std::string PrintMessage(const MessageBase<TBase, TOptions...>& a_Message) {
|
||||
return sp::GetBasicClassName(a_Message) + sp::details::IdPrinter<TOptions...>::PrintMessageId() + "[" +
|
||||
sp::details::PrintFields(a_Message.GetFields()) + "]";
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace sp
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
namespace sp {
|
||||
|
||||
template <typename TBase, typename... TOptions>
|
||||
class MessageBase;
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename TBase, typename... TOptions>
|
||||
std::string PrintMessage(const MessageBase<TBase, TOptions...>& a_Message);
|
||||
|
||||
// ID information chunk
|
||||
template <typename TBase, typename TActual>
|
||||
class MessageImplToStringBase : public TBase {
|
||||
protected:
|
||||
virtual std::string ToStringImpl() const override {
|
||||
return PrintMessage(static_cast<const TActual&>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ID information chunk
|
||||
@@ -18,6 +34,8 @@ class MessageImplStaticNumIdBase : public TBase {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Dispatch implementation chunk
|
||||
template <typename TBase, typename TActual>
|
||||
class MessageImplDispatchBase : public TBase {
|
||||
|
||||
@@ -49,9 +49,4 @@ DataBuffer& operator>>(DataBuffer& in, VarInt& var) {
|
||||
return in;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const sp::VarInt& a_VarInt) {
|
||||
a_Stream << a_VarInt.GetValue();
|
||||
return a_Stream;
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
|
||||
#include <sp/default/DefaultPacketDispatcher.h>
|
||||
#include <sp/extensions/Extensions.h>
|
||||
#include <sp/protocol/MessagePrinter.h>
|
||||
|
||||
class KeepAliveHandler : public sp::PacketHandler {
|
||||
void Handle(const KeepAlivePacket& packet) {
|
||||
std::cout << "KeepAlive handled !!\n";
|
||||
std::cout << packet << std::endl;
|
||||
std::cout << packet.ToString() << std::endl;
|
||||
}
|
||||
|
||||
void Handle(const DisconnectPacket& packet) {
|
||||
@@ -40,7 +39,7 @@ int main() {
|
||||
auto upgradeTower2 = std::make_unique<UpgradeTowerPacket>();
|
||||
upgradeTower2->Read(buffer);
|
||||
|
||||
std::cout << "Test : " << *upgradeTower2 << "\n";
|
||||
std::cout << "Test : " << msg->ToString() << "\n";
|
||||
|
||||
sp::PacketFactory factory;
|
||||
auto packet = factory.CreateMessage(msgId);
|
||||
|
||||
Reference in New Issue
Block a user