All checks were successful
Linux arm64 / Build (push) Successful in 16s
Reviewed-on: #14 Co-authored-by: Persson-dev <sim16.prib@gmail.com> Co-committed-by: Persson-dev <sim16.prib@gmail.com>
179 lines
4.9 KiB
C++
179 lines
4.9 KiB
C++
#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::ostream& OpOutImpl(std::ostream& a_Stream) const override{
|
|
return a_Stream << static_cast<const TActual&>(*this);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
// ID information chunk
|
|
template <typename TBase, std::intmax_t TId>
|
|
class MessageImplStaticNumIdBase : public TBase {
|
|
public:
|
|
// Reuse the message ID type defined in the interface
|
|
using MsgIdType = typename TBase::MsgIdType;
|
|
|
|
protected:
|
|
virtual MsgIdType GetIdImpl() const override {
|
|
return static_cast<MsgIdType>(TId);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
// Dispatch implementation chunk
|
|
template <typename TBase, typename TActual>
|
|
class MessageImplDispatchBase : public TBase {
|
|
public:
|
|
// Reuse the Handler type defined in the interface class
|
|
using Handler = typename TBase::HandlerType;
|
|
|
|
protected:
|
|
virtual void DispatchImpl(Handler& handler) const override {
|
|
handler.Handle(static_cast<const TActual&>(*this));
|
|
}
|
|
};
|
|
|
|
|
|
|
|
template <typename TBase, typename TFields>
|
|
class MessageImplFieldsBase : public TBase {
|
|
public:
|
|
using AllFields = typename details::FieldsBuilder<TFields>::Type;
|
|
|
|
template <typename... Args>
|
|
void Construct(Args... args) {
|
|
m_Fields = std::make_tuple(args...);
|
|
}
|
|
|
|
AllFields& GetFields() {
|
|
return m_Fields;
|
|
}
|
|
|
|
const AllFields& GetFields() const {
|
|
return m_Fields;
|
|
}
|
|
|
|
template <std::size_t FIndex>
|
|
auto& GetField() {
|
|
return std::get<FIndex>(GetFields()).GetValue();
|
|
}
|
|
|
|
template <std::size_t FIndex>
|
|
const auto& GetField() const {
|
|
return std::get<FIndex>(GetFields()).GetValue();
|
|
}
|
|
|
|
// allow use of enums
|
|
template <typename E, E FIndex>
|
|
const auto& GetField() const {
|
|
return std::get<static_cast<std::size_t>(FIndex)>(this->GetFields()).GetValue();
|
|
}
|
|
|
|
private:
|
|
AllFields m_Fields;
|
|
};
|
|
|
|
template <typename TBase>
|
|
class MessageImplFieldsReadBase : public TBase {
|
|
private:
|
|
// normal reading
|
|
template <typename TField>
|
|
void ReadField(Field<TField, 0>& field, DataBuffer& buffer) {
|
|
this->ReadData(field.GetValue(), buffer);
|
|
}
|
|
|
|
// reading field in bitfield
|
|
template <typename TFieldType, typename TField, std::size_t IAlignment>
|
|
void ReadField(Field<TField, IAlignment>& 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
|
|
field.GetValue() = (data >> TotalBitCount - IAlignment - offset) & ((1 << IAlignment) - 1);
|
|
}
|
|
|
|
// reading bitfield
|
|
template <typename TContainer, typename TFirst, typename... TFields>
|
|
void ReadField(Field<BitField<TContainer, TFirst, TFields...>, 0>& field, DataBuffer& buffer) {
|
|
TContainer data;
|
|
this->ReadData(data, buffer);
|
|
std::size_t offset = 0;
|
|
TupleForEach(
|
|
[data, this, &offset](auto& field) {
|
|
this->ReadField(field, data, offset);
|
|
offset += field.GetAlignment();
|
|
},
|
|
field.GetValue().GetFields());
|
|
}
|
|
|
|
void ReadImpl(DataBuffer& buffer) override {
|
|
auto& allFields = this->GetFields();
|
|
TupleForEach([&buffer, this](auto& field) { this->ReadField(field, buffer); }, allFields);
|
|
}
|
|
};
|
|
|
|
template <typename TBase>
|
|
class MessageImplFieldsWriteBase : public TBase {
|
|
private:
|
|
// normal writing
|
|
template <typename TField>
|
|
void WriteField(const Field<TField, 0>& field, DataBuffer& buffer) const {
|
|
this->WriteData(field.GetValue(), buffer);
|
|
}
|
|
|
|
// writing field in bitfield
|
|
template <typename TFieldType, typename TField, std::size_t IAlignment>
|
|
void WriteField(const Field<TField, IAlignment>& 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
|
|
data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset;
|
|
}
|
|
|
|
// writing bitfield
|
|
template <typename TContainer, typename TFirst, typename... TFields>
|
|
void WriteField(const Field<BitField<TContainer, TFirst, TFields...>, 0>& field, DataBuffer& buffer) const {
|
|
TContainer data = 0;
|
|
std::size_t offset = 0;
|
|
TupleForEach(
|
|
[&data, this, &offset](auto& field) {
|
|
this->WriteField(field, data, offset);
|
|
offset += field.GetAlignment();
|
|
},
|
|
field.GetValue().GetFields());
|
|
this->WriteData(data, buffer);
|
|
}
|
|
|
|
void WriteImpl(DataBuffer& buffer) const override {
|
|
auto& allFields = this->GetFields();
|
|
TupleForEach([&buffer, this](const auto& field) { this->WriteField(field, buffer); }, allFields);
|
|
}
|
|
};
|
|
|
|
template <typename TBase>
|
|
class MessageImplFieldsValidBase : public TBase {
|
|
protected:
|
|
bool ValidImpl() const override {
|
|
// Access fields via interface provided in previous chunk
|
|
// auto& allFields = TBase::GetFields();
|
|
//... // validate all the fields
|
|
return true;
|
|
}
|
|
};
|
|
|
|
} // namespace details
|
|
} // namespace sp
|