v2.0 #15

Merged
Persson-dev merged 9 commits from v2.0 into main 2025-07-10 13:15:42 +00:00
11 changed files with 168 additions and 178 deletions
Showing only changes of commit 073872df94 - Show all commits

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,7 +0,0 @@
#pragma once
#include <sp/protocol/MessageFactory.h>
namespace sp {
using PacketFactory = sp::MessageFactory<sp::PacketMessage, AllPackets>;
} // namespace sp

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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
View 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>();