v2.0 #15
@@ -4,8 +4,6 @@
|
||||
|
||||
namespace sp {
|
||||
|
||||
bool IsSystemBigEndian();
|
||||
|
||||
/**
|
||||
* \brief Serialize value to (network byte order) big endian
|
||||
*/
|
||||
@@ -36,19 +34,4 @@ void FromNetwork<std::uint32_t>(std::uint32_t& value);
|
||||
template <>
|
||||
void FromNetwork<std::uint64_t>(std::uint64_t& value);
|
||||
|
||||
/**
|
||||
* \brief Swap bytes if the value is any kind of integer
|
||||
*/
|
||||
template <typename T>
|
||||
void TrySwapBytes(T& value) {}
|
||||
|
||||
template <>
|
||||
void TrySwapBytes<std::uint16_t>(std::uint16_t& value);
|
||||
|
||||
template <>
|
||||
void TrySwapBytes<std::uint32_t>(std::uint32_t& value);
|
||||
|
||||
template <>
|
||||
void TrySwapBytes<std::uint64_t>(std::uint64_t& value);
|
||||
|
||||
} // namespace sp
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <sp/protocol/GenericHandler.h>
|
||||
#include <sp/protocol/Message.h>
|
||||
|
||||
|
||||
namespace sp {
|
||||
class PacketHandler;
|
||||
|
||||
using PacketID = std::uint8_t;
|
||||
|
||||
using PacketMessage = Message<
|
||||
option::MsgIdType<PacketID>, // add id() operation
|
||||
option::Handler<PacketHandler> // add dispatch() operation
|
||||
>;
|
||||
|
||||
#define PacketConstructor(packetName) \
|
||||
packetName##Packet() {} \
|
||||
template <typename... Args> \
|
||||
packetName##Packet(Args... args) { \
|
||||
Construct(args...); \
|
||||
}
|
||||
|
||||
#define DeclarePacket(packetName) \
|
||||
class packetName##Packet : public sp::MessageBase<sp::PacketMessage, \
|
||||
sp::option::DispatchImpl<packetName##Packet>, sp::option::FieldsImpl<packetName##Fields>>, \
|
||||
sp::option::ToStringImpl<packetName##Packet>
|
||||
|
||||
|
||||
|
||||
} // namespace sp
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <sp/default/DefaultPacket.h>
|
||||
#include <sp/default/DefaultPacketHandler.h>
|
||||
#include <sp/protocol/MessageDispatcher.h>
|
||||
|
||||
namespace sp {
|
||||
|
||||
using PacketDispatcher = MessageDispatcher<
|
||||
PacketMessage::ParsedOptions::MsgIdType,
|
||||
PacketMessage,
|
||||
PacketMessage::ParsedOptions::HandlerType::HandlerT
|
||||
>;
|
||||
|
||||
} // namespace sp
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <sp/protocol/MessageFactory.h>
|
||||
|
||||
namespace sp {
|
||||
using PacketFactory = sp::MessageFactory<sp::PacketMessage, AllPackets>;
|
||||
} // namespace sp
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <sp/protocol/GenericHandler.h>
|
||||
|
||||
// the tuple AllPackets must be defined !
|
||||
|
||||
namespace sp {
|
||||
class PacketHandler : public sp::GenericHandler<PacketMessage, AllPackets> {};
|
||||
} // namespace sp
|
||||
@@ -14,7 +14,7 @@ class ConcreteMessage : public MessageBase<TMessageID, THandler> {
|
||||
|
||||
virtual ~ConcreteMessage() {}
|
||||
|
||||
virtual constexpr TMessageID GetId() const override {
|
||||
virtual TMessageID GetId() const override {
|
||||
return ID;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <sp/protocol/Field.h>
|
||||
#include <sp/protocol/message/OstreamFieldIterator.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace sp {
|
||||
|
||||
template <typename T, std::enable_if_t<details::is_primitive<T>::value, bool> = true>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<T>& a_Field) {
|
||||
return a_Stream << std::to_string(a_Field.GetValue());
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<long unsigned int>& a_Field) {
|
||||
return a_Stream << a_Field.GetValue();
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<std::string>& a_Field) {
|
||||
return a_Stream << "\"" << a_Field.GetValue() << "\"";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<std::pair<K, V>>& a_Data);
|
||||
|
||||
template <typename K, typename V>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<std::map<K, V>>& a_Data);
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<std::vector<T>>& a_Data);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<std::pair<K, V>>& a_Data) {
|
||||
return a_Stream << PrintableField<K>(a_Data.GetValue().first) << " => " << PrintableField<V>(a_Data.GetValue().second);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<std::map<K, V>>& a_Data) {
|
||||
a_Stream << "{";
|
||||
std::copy(a_Data.GetValue().begin(), a_Data.GetValue().end(), OstreamFieldIterator<std::pair<K, V>>(std::cout, ", "));
|
||||
return a_Stream << "}";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& a_Stream, const PrintableField<std::vector<T>>& a_Data) {
|
||||
a_Stream << "{";
|
||||
std::copy(a_Data.GetValue().begin(), a_Data.GetValue().end(), OstreamFieldIterator<T>(std::cout, ", "));
|
||||
return a_Stream << "}";
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
@@ -1,27 +1,21 @@
|
||||
#include <sp/common/ByteSwapping.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <endian.h>
|
||||
|
||||
#define htonll htobe64
|
||||
#define ntohll be64toh
|
||||
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace sp {
|
||||
|
||||
template <typename T>
|
||||
void SwapBytes(T& value) {
|
||||
char* ptr = reinterpret_cast<char*>(&value);
|
||||
std::reverse(ptr, ptr + sizeof(T));
|
||||
}
|
||||
|
||||
bool IsSystemBigEndian() {
|
||||
static constexpr std::uint16_t test = 10;
|
||||
static const bool isBigEndian = reinterpret_cast<const std::uint8_t*>(&test)[1] == 10;
|
||||
return isBigEndian;
|
||||
}
|
||||
|
||||
template <>
|
||||
void ToNetwork<std::uint16_t>(std::uint16_t& value) {
|
||||
value = htons(value);
|
||||
@@ -34,9 +28,7 @@ void ToNetwork<std::uint32_t>(std::uint32_t& value) {
|
||||
|
||||
template <>
|
||||
void ToNetwork<std::uint64_t>(std::uint64_t& value) {
|
||||
if (IsSystemBigEndian())
|
||||
return;
|
||||
SwapBytes(value);
|
||||
value = htonll(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -51,24 +43,7 @@ void FromNetwork<std::uint32_t>(std::uint32_t& value) {
|
||||
|
||||
template <>
|
||||
void FromNetwork<std::uint64_t>(std::uint64_t& value) {
|
||||
if (IsSystemBigEndian())
|
||||
return;
|
||||
SwapBytes(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void TrySwapBytes<std::uint16_t>(std::uint16_t& value) {
|
||||
SwapBytes(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void TrySwapBytes<std::uint32_t>(std::uint32_t& value) {
|
||||
SwapBytes(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void TrySwapBytes<std::uint64_t>(std::uint64_t& value) {
|
||||
SwapBytes(value);
|
||||
value = ntohll(value);
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
|
||||
@@ -11,7 +11,7 @@ File::IOInterface(const std::string& a_FilePath, unsigned int a_OpenMode) {
|
||||
}
|
||||
|
||||
File::IOInterface(File&& other) :
|
||||
m_FileOutput(std::move(other.m_FileOutput)), m_FileInput(std::move(other.m_FileInput)) {}
|
||||
m_FileInput(std::move(other.m_FileInput)), m_FileOutput(std::move(other.m_FileOutput)) {}
|
||||
|
||||
DataBuffer File::Read(std::size_t a_Amount) {
|
||||
DataBuffer buffer;
|
||||
|
||||
@@ -37,7 +37,7 @@ using PacketDispatcher = sp::MessageDispatcher<PacketBase>;
|
||||
using PacketFactory = sp::MessageFactory<PacketBase, AllMessages>;
|
||||
|
||||
int main() {
|
||||
KeepAliveMessage m{5U};
|
||||
KeepAliveMessage m{5UL};
|
||||
MyHandler h;
|
||||
PacketDispatcher d;
|
||||
d.RegisterHandler(PacketID::KeepAlive, &h);
|
||||
|
||||
155
test/type_name.hpp
Normal file
155
test/type_name.hpp
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2018 Will Wray https://keybase.io/willwray
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
|
||||
#if __has_include(<cxxabi.h>)
|
||||
# include <cxxabi.h>
|
||||
# include <cstdlib>
|
||||
# include <memory>
|
||||
#endif
|
||||
|
||||
constexpr bool CXXABI
|
||||
{
|
||||
#if __has_include(<cxxabi.h>)
|
||||
true
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
"type_name_rt.hpp": get type names at runtime (hence 'rt')
|
||||
^^^^^^^^^^^^^^^^
|
||||
This header defines, in global scope (i.e. not namespace'd):
|
||||
(1) A function template type_name_str<T>() for extracting a type's name.
|
||||
(2) A variable template type_name_rt<T> initialized to the type's name.
|
||||
(also an incomplete class template IdT<T>, an implementation detail.)
|
||||
The template type parameter T is mapped to a readable name for the type.
|
||||
The work is done at runtime by what is the most standard current method;
|
||||
runtime type information (RTTI) and, on CXXABI, a demangle call
|
||||
(for compile-time alternatives see type_name_pt or type_name_ct).
|
||||
(1) type_name_str<T>()
|
||||
Returns a std::string copy of the demangled typeid name.
|
||||
On each call it does all the work, and cleans it all up
|
||||
(i.e. it frees any demangle allocation once copied from).
|
||||
|
||||
(2) type_name_rt<T>
|
||||
A std::string_view global constant (a view into the
|
||||
demangle buffer, on CXXABI, which is not ever free'd).
|
||||
All work is done in static initialization, before main()
|
||||
|
||||
Failure is signalled by an empty return value; ""
|
||||
(indicates a demangle failure as typeid is assumed fail-safe).
|
||||
Requirements:
|
||||
C++17 for string_view, constexpr-if, CTAD (unique_ptr) and __has_include
|
||||
RTTI, the compiler's runtime type information, must be enabled
|
||||
Dependencies: <string>,<string_view>,<type_traits> for std::conditional
|
||||
<typeinfo> (RTTI)
|
||||
for typeid(T).name(), an implementation-defined name.
|
||||
<cxxabi.h> (on CXXABI platforms only - GCC, Clang, etc.)
|
||||
for abi::__cxa_demangle(name,...)
|
||||
to map typeid(T).name to a human readable name for T.
|
||||
<cstdlib> for std::free, <memory> for std::unique_ptr
|
||||
E.g.
|
||||
int i;
|
||||
std::cout << type_name_rt<decltype(i)> << "\n^^^ tada!";
|
||||
--- stdout ---
|
||||
int
|
||||
^^^ tada!
|
||||
*/
|
||||
|
||||
// IdT<T> wraps T as template param so typeid can't decay ref or cv quals.
|
||||
// An implementation detail; must be a 3-character id, any 3 chars will do.
|
||||
template <typename T> struct IdT {};
|
||||
|
||||
namespace impl
|
||||
{
|
||||
// demangle<bool Free=false>( const char* name)
|
||||
//
|
||||
// (1) On non-CXXABI returns name, regardless of the template parameter.
|
||||
// i.e. the function does nothing but return its parameter, a char*.
|
||||
//
|
||||
// (2) On CXXABI the demangle ABI is called and the result is returned
|
||||
// with return type depending on the boolean template argument:
|
||||
// (a) char* by default (Free=false). Any demangle malloc is not free'd.
|
||||
// (b) unique_ptr<char> (Free=true) to RAII-free any malloc'd chars.
|
||||
//
|
||||
// The input name should be a valid mangled name like typeid(T).name()
|
||||
// Null return value implies demangle fail (no malloc, free is harmless).
|
||||
//
|
||||
template <bool Free = false>
|
||||
auto
|
||||
demangle(char const* name) noexcept(!CXXABI)
|
||||
{
|
||||
if constexpr (!CXXABI) {
|
||||
return name; // NOP: assume already demangled if not on CXXABI
|
||||
} else {
|
||||
auto dmg = abi::__cxa_demangle(name, nullptr, nullptr, nullptr);
|
||||
if constexpr (Free)
|
||||
return std::unique_ptr<char, decltype(std::free)*>( dmg, std::free);
|
||||
else
|
||||
return dmg;
|
||||
}
|
||||
}
|
||||
|
||||
// prefix_len (constant): prefix length of demangled typeid(IdT<T>)
|
||||
// for different compilers (remove 4 chars "int>" from the length)
|
||||
size_t IdT_prefix_len()
|
||||
{
|
||||
static size_t const len = std::strlen(demangle<>(typeid(IdT<int>).name()))
|
||||
- std::strlen("int>");
|
||||
return len;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_cvref_v = !std::is_same_v<T,remove_cvref_t<T>>;
|
||||
|
||||
// type_name_rt<T>() Returns string, frees any malloc from ABI demangle
|
||||
// type_name_rt<T,false>() Returns string_view, does not free demangle malloc
|
||||
//
|
||||
template <typename T, bool Free = true, typename = void>
|
||||
auto
|
||||
type_name_rt() noexcept(!CXXABI) -> std::conditional_t<Free, std::string,
|
||||
std::string_view>
|
||||
{
|
||||
if constexpr (!is_cvref_v<T>)
|
||||
{
|
||||
if (auto dmg = demangle<Free>(typeid(T).name()))
|
||||
{
|
||||
return { &*dmg };
|
||||
}
|
||||
}
|
||||
else // wrap all cvref types for now - maybe only do functions and arrays
|
||||
{
|
||||
if (auto dmg = demangle<Free>(typeid(IdT<T>).name()))
|
||||
{
|
||||
size_t const p = IdT_prefix_len();
|
||||
return { &*dmg + p, std::strlen(&*dmg) - p - 1 };
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
} // namespace impl
|
||||
|
||||
// type_name_str<T>() Returns a std::string copy of the demangled typeid name.
|
||||
//
|
||||
template <typename T>
|
||||
std::string
|
||||
const type_name_str() { return impl::type_name_rt<T>(); }
|
||||
|
||||
// type_name_rt<T> Global constant; "The Demangle that Never Dangles"
|
||||
//
|
||||
template <typename T>
|
||||
inline
|
||||
std::string_view
|
||||
const type_name_rt = impl::type_name_rt<T, false>();
|
||||
Reference in New Issue
Block a user