feat: add streams
All checks were successful
Linux arm64 / Build (push) Successful in 16s

This commit is contained in:
2025-06-26 19:17:52 +02:00
parent 59bedd6482
commit 0d26879152
25 changed files with 385 additions and 778 deletions

View File

@@ -1,7 +1,7 @@
#pragma once
#include <sp/protocol/MessageBase.h>
#include <sp/protocol/MessageIO.h>
#include <sp/io/MessageIO.h>
namespace sp {
@@ -9,7 +9,6 @@ template <typename TData, typename TMessageID, TMessageID ID, typename THandler>
class ConcreteMessage : public MessageBase<TMessageID, THandler> {
public:
using DataType = TData;
using ThisType = ConcreteMessage<TData, TMessageID, ID, THandler>;
template <typename... T>
ConcreteMessage(const T&... args) : m_Data{args...} {}
@@ -21,15 +20,15 @@ class ConcreteMessage : public MessageBase<TMessageID, THandler> {
}
virtual void Dispatch(THandler& handler) const override {
handler.Handle(static_cast<const ThisType&>(*this));
handler.Handle(static_cast<const DataType&>(m_Data));
}
virtual void Read(std::istream& a_Is) override {
details::ReadMessage(a_Is, m_Data);
virtual void Read(DataBuffer& a_Buffer) override {
details::ReadMessage(a_Buffer, m_Data);
}
virtual void Write(std::ostream& a_Os) const override {
details::WriteMessage(a_Os, m_Data);
virtual DataBuffer Write() const override {
return details::WriteMessage(m_Data);
}
private:

View File

@@ -1,139 +0,0 @@
#pragma once
#include <tuple>
namespace sp
{
// This class is inspired by https://arobenko.gitbooks.io/comms-protocols-cpp/content/
// TCommon is common interface class for all the messages
// TAll is all the message types, that need to be handled, bundled in std::tuple
template <typename TAll>
class GenericHandler;
// Big boy to process packets 20 by 20, preventing needlessly copying vtable many times at each inheritance stage
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16, typename T17, typename T18, typename T19, typename T20,
typename... TRest>
class GenericHandler<std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T11, T13, T14, T15, T16, T17, T18, T19, T20, TRest...> > : public GenericHandler<std::tuple<TRest...> >
{
using Base = GenericHandler<std::tuple<TRest...> >;
public:
using Base::Handle; // Don't hide all Handle() functions from base classes
virtual void Handle(const T1& msg) {}
virtual void Handle(const T2& msg) {}
virtual void Handle(const T3& msg) {}
virtual void Handle(const T4& msg) {}
virtual void Handle(const T5& msg) {}
virtual void Handle(const T6& msg) {}
virtual void Handle(const T7& msg) {}
virtual void Handle(const T8& msg) {}
virtual void Handle(const T9& msg) {}
virtual void Handle(const T10& msg) {}
virtual void Handle(const T11& msg) {}
virtual void Handle(const T12& msg) {}
virtual void Handle(const T13& msg) {}
virtual void Handle(const T14& msg) {}
virtual void Handle(const T15& msg) {}
virtual void Handle(const T16& msg) {}
virtual void Handle(const T17& msg) {}
virtual void Handle(const T18& msg) {}
virtual void Handle(const T19& msg) {}
virtual void Handle(const T20& msg) {}
};
// 10 by 10
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename... TRest>
class GenericHandler<std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRest...> > : public GenericHandler<std::tuple<TRest...> >
{
using Base = GenericHandler<std::tuple<TRest...> >;
public:
using Base::Handle; // Don't hide all Handle() functions from base classes
virtual void Handle(const T1& msg) {}
virtual void Handle(const T2& msg) {}
virtual void Handle(const T3& msg) {}
virtual void Handle(const T4& msg) {}
virtual void Handle(const T5& msg) {}
virtual void Handle(const T6& msg) {}
virtual void Handle(const T7& msg) {}
virtual void Handle(const T8& msg) {}
virtual void Handle(const T9& msg) {}
virtual void Handle(const T10& msg) {}
};
// 5 by 5
template <
typename T1, typename T2, typename T3, typename T4, typename T5,
typename... TRest>
class GenericHandler<std::tuple<T1, T2, T3, T4, T5, TRest...> > : public GenericHandler<std::tuple<TRest...> >
{
using Base = GenericHandler<std::tuple<TRest...> >;
public:
using Base::Handle; // Don't hide all Handle() functions from base classes
virtual void Handle(const T1& msg) {}
virtual void Handle(const T2& msg) {}
virtual void Handle(const T3& msg) {}
virtual void Handle(const T4& msg) {}
virtual void Handle(const T5& msg) {}
};
// Deal with rest with 4 types
template <typename T1, typename T2, typename T3, typename T4>
class GenericHandler<std::tuple<T1, T2, T3, T4> >
{
public:
virtual ~GenericHandler() {}
virtual void Handle(const T1& msg) {}
virtual void Handle(const T2& msg) {}
virtual void Handle(const T3& msg) {}
virtual void Handle(const T4& msg) {}
// virtual void Handle(const TCommon&) {} //Nothing to do
};
// Deal with rest with 3 types
template < typename T1, typename T2, typename T3>
class GenericHandler<std::tuple<T1, T2, T3> >
{
public:
virtual ~GenericHandler() {}
virtual void Handle(const T1& msg) {}
virtual void Handle(const T2& msg) {}
virtual void Handle(const T3& msg) {}
// virtual void Handle(const TCommon&) {} //Nothing to do
};
// Deal with rest with 2 types
template <typename T1, typename T2>
class GenericHandler<std::tuple<T1, T2> >
{
public:
virtual ~GenericHandler() {}
virtual void Handle(const T1& msg) {}
virtual void Handle(const T2& msg) {}
// virtual void Handle(const TCommon&) {} //Nothing to do
};
// Deal with rest with 1 type
template <typename T1>
class GenericHandler<std::tuple<T1> >
{
public:
virtual ~GenericHandler() {}
virtual void Handle(const T1& msg) {}
// virtual void Handle(const TCommon&) {} //Nothing to do
};
// Deal with rest with 0 type
template <>
class GenericHandler<std::tuple<> >
{
public:
virtual ~GenericHandler() {}
// virtual void Handle(const TCommon&) {} //Nothing to do
};
} // sp

View File

@@ -1,6 +1,7 @@
#pragma once
#include <iosfwd>
#include <sp/common/DataBuffer.h>
namespace sp {
@@ -17,8 +18,8 @@ class MessageBase {
virtual void Dispatch(HandlerType& handler) const = 0;
virtual void Read(std::istream& a_Is) = 0;
virtual void Write(std::ostream& a_Os) const = 0;
virtual void Read(DataBuffer& a_Buffer) = 0;
virtual DataBuffer Write() const = 0;
};
} // namespace sp

View File

@@ -12,6 +12,7 @@ template <typename TBase, typename TTMessages>
class MessageFactory {
public:
using IdType = typename TBase::MessageIdType;
using MessageBaseType = TBase;
MessageFactory() {
constexpr std::size_t messageCount = std::tuple_size_v<TTMessages>;

View File

@@ -0,0 +1,133 @@
#pragma once
#include <tuple>
namespace sp
{
// This class is inspired by https://arobenko.gitbooks.io/comms-protocols-cpp/content/
// TAll is all the message types, that need to be handled, bundled in std::tuple
template <typename TAll>
class MessageHandler;
// Big boy to process packets 20 by 20, preventing needlessly copying vtable many times at each inheritance stage
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16, typename T17, typename T18, typename T19, typename T20,
typename... TRest>
class MessageHandler<std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T11, T13, T14, T15, T16, T17, T18, T19, T20, TRest...> > : public MessageHandler<std::tuple<TRest...> >
{
using Base = MessageHandler<std::tuple<TRest...> >;
public:
using Base::Handle; // Don't hide all Handle() functions from base classes
virtual void Handle(const typename T1::DataType& msg) {}
virtual void Handle(const typename T2::DataType& msg) {}
virtual void Handle(const typename T3::DataType& msg) {}
virtual void Handle(const typename T4::DataType& msg) {}
virtual void Handle(const typename T5::DataType& msg) {}
virtual void Handle(const typename T6::DataType& msg) {}
virtual void Handle(const typename T7::DataType& msg) {}
virtual void Handle(const typename T8::DataType& msg) {}
virtual void Handle(const typename T9::DataType& msg) {}
virtual void Handle(const typename T10::DataType& msg) {}
virtual void Handle(const typename T11::DataType& msg) {}
virtual void Handle(const typename T12::DataType& msg) {}
virtual void Handle(const typename T13::DataType& msg) {}
virtual void Handle(const typename T14::DataType& msg) {}
virtual void Handle(const typename T15::DataType& msg) {}
virtual void Handle(const typename T16::DataType& msg) {}
virtual void Handle(const typename T17::DataType& msg) {}
virtual void Handle(const typename T18::DataType& msg) {}
virtual void Handle(const typename T19::DataType& msg) {}
virtual void Handle(const typename T20::DataType& msg) {}
};
// 10 by 10
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename... TRest>
class MessageHandler<std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRest...> > : public MessageHandler<std::tuple<TRest...> >
{
using Base = MessageHandler<std::tuple<TRest...> >;
public:
using Base::Handle; // Don't hide all Handle() functions from base classes
virtual void Handle(const typename T1::DataType& msg) {}
virtual void Handle(const typename T2::DataType& msg) {}
virtual void Handle(const typename T3::DataType& msg) {}
virtual void Handle(const typename T4::DataType& msg) {}
virtual void Handle(const typename T5::DataType& msg) {}
virtual void Handle(const typename T6::DataType& msg) {}
virtual void Handle(const typename T7::DataType& msg) {}
virtual void Handle(const typename T8::DataType& msg) {}
virtual void Handle(const typename T9::DataType& msg) {}
virtual void Handle(const typename T10::DataType& msg) {}
};
// 5 by 5
template <
typename T1, typename T2, typename T3, typename T4, typename T5,
typename... TRest>
class MessageHandler<std::tuple<T1, T2, T3, T4, T5, TRest...> > : public MessageHandler<std::tuple<TRest...> >
{
using Base = MessageHandler<std::tuple<TRest...> >;
public:
using Base::Handle; // Don't hide all Handle() functions from base classes
virtual void Handle(const typename T1::DataType& msg) {}
virtual void Handle(const typename T2::DataType& msg) {}
virtual void Handle(const typename T3::DataType& msg) {}
virtual void Handle(const typename T4::DataType& msg) {}
virtual void Handle(const typename T5::DataType& msg) {}
};
// Deal with rest with 4 types
template <typename T1, typename T2, typename T3, typename T4>
class MessageHandler<std::tuple<T1, T2, T3, T4> >
{
public:
virtual ~MessageHandler() {}
virtual void Handle(const typename T1::DataType& msg) {}
virtual void Handle(const typename T2::DataType& msg) {}
virtual void Handle(const typename T3::DataType& msg) {}
virtual void Handle(const typename T4::DataType& msg) {}
};
// Deal with rest with 3 types
template < typename T1, typename T2, typename T3>
class MessageHandler<std::tuple<T1, T2, T3> >
{
public:
virtual ~MessageHandler() {}
virtual void Handle(const typename T1::DataType& msg) {}
virtual void Handle(const typename T2::DataType& msg) {}
virtual void Handle(const typename T3::DataType& msg) {}
};
// Deal with rest with 2 types
template <typename T1, typename T2>
class MessageHandler<std::tuple<T1, T2> >
{
public:
virtual ~MessageHandler() {}
virtual void Handle(const typename T1::DataType& msg) {}
virtual void Handle(const typename T2::DataType& msg) {}
};
// Deal with rest with 1 type
template <typename T1>
class MessageHandler<std::tuple<T1> >
{
public:
virtual ~MessageHandler() {}
virtual void Handle(const typename T1::DataType& msg) {}
};
// Deal with rest with 0 type
template <>
class MessageHandler<std::tuple<> >
{
public:
virtual ~MessageHandler() {}
};
} // sp

View File

@@ -1,38 +0,0 @@
#pragma once
#include <boost/pfr.hpp>
#include <iostream>
#include <sp/common/ByteSwapping.h>
namespace sp {
namespace details {
template<typename T>
void WriteField(std::ostream& a_Os, const T& a_Data) {
T swapped = a_Data;
ToNetwork(swapped);
a_Os.write(reinterpret_cast<const char*>(&swapped), sizeof(a_Data));
}
template<typename T>
void ReadField(std::istream& a_Is, T& a_Data) {
a_Is.read(reinterpret_cast<char*>(&a_Data), sizeof(a_Data));
FromNetwork(a_Data);
}
template <typename TData>
void WriteMessage(std::ostream& a_Os, const TData& a_MessageData) {
boost::pfr::for_each_field(a_MessageData, [&a_Os](const auto& a_Field) {
WriteField(a_Os, a_Field);
});
}
template <typename TData>
void ReadMessage(std::istream& a_Is, TData& a_MessageData) {
boost::pfr::for_each_field(a_MessageData, [&a_Is](auto& a_Field) {
ReadField(a_Is, a_Field);
});
}
} // namespace details
} // namespace sp