From 462086b13cc2ef96ae1b2df2e37f4e7342bc52f2 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 8 Feb 2025 19:45:45 +0100 Subject: [PATCH] feat: add alignment --- include/sp/protocol/Field.h | 63 +++++++++++++++++++++++++++- include/sp/protocol/MessageBase.h | 69 +++++++++++++++++++++++++++---- 2 files changed, 122 insertions(+), 10 deletions(-) diff --git a/include/sp/protocol/Field.h b/include/sp/protocol/Field.h index 57c9042..6bafa85 100644 --- a/include/sp/protocol/Field.h +++ b/include/sp/protocol/Field.h @@ -5,13 +5,68 @@ namespace sp { -template +/** + * \brief Example usage : + * sp::BitField, sp::Field>; + */ +template +class BitField { + using AllFields = std::tuple; + + public: + template + BitField(const std::tuple& args) { + Apply<0, T...>(args); + } + + BitField() {} + + template + BitField& operator=(const std::tuple& args) { + Apply<0, T...>(args); + return *this; + } + + AllFields& GetFields() { + return m_Fields; + } + + const AllFields& GetFields() const { + return m_Fields; + } + + template + auto& GetField() { + return std::get(this->GetFields()).GetValue(); + } + + private: + template = sizeof...(T), bool> = true> + void Apply(const std::tuple& args) {} + + template = sizeof...(T)), bool> = true> + void Apply(const std::tuple& args) { + this->GetField() = std::get(args); + Apply<1 + IOffset, T...>(args); + } + + TContainer m_Value; + AllFields m_Fields; +}; + +/** + * + * \tparam ValueType the type of the value to store + * \tparam IAlignment 0 means no alignment + */ +template class Field { public: // Provide an access to the stored value ValueType& GetValue() { return m_Value; } + const ValueType& GetValue() const { return m_Value; } @@ -21,6 +76,10 @@ class Field { return *this; } + constexpr int GetAlignment() const { + return IAlignment; + } + private: ValueType m_Value; }; @@ -42,7 +101,7 @@ struct FieldsBuilder> { template struct FieldsBuilder { - using Type = sp::tuple_cat_t>, typename FieldsBuilder::Type>; + using Type = sp::tuple_cat_t>, typename FieldsBuilder::Type>; }; } // namespace details diff --git a/include/sp/protocol/MessageBase.h b/include/sp/protocol/MessageBase.h index fe02a38..a489b7b 100644 --- a/include/sp/protocol/MessageBase.h +++ b/include/sp/protocol/MessageBase.h @@ -104,6 +104,7 @@ class MessageImplFieldsBase : public TBase { AllFields& GetFields() { return m_Fields; } + const AllFields& GetFields() const { return m_Fields; } @@ -119,23 +120,75 @@ class MessageImplFieldsBase : public TBase { template class MessageImplFieldsReadBase : public TBase { - protected: + private: + // normal reading + template + void ReadField(Field& field, DataBuffer& buffer) { + this->ReadData(field.GetValue(), buffer); + } + + // reading field in bitfield + template + void ReadField(Field& 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 + void ReadField(Field, 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(); - std::apply([&buffer, this](auto& field) { - this->ReadData(field.GetValue(), buffer); - }, allFields); + TupleForEach([&buffer, this](auto& field) { this->ReadField(field, buffer); }, allFields); } }; template class MessageImplFieldsWriteBase : public TBase { - protected: + private: + // normal writing + template + void WriteField(Field& field, DataBuffer& buffer) { + this->WriteData(field.GetValue(), buffer); + } + + // writing field in bitfield + template + void WriteField(Field& 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 + data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset; + } + + // writing bitfield + template + void WriteField(Field, 0>& field, DataBuffer& buffer) { + 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) override { auto& allFields = this->GetFields(); - std::apply([&buffer, this](auto& field) { - this->WriteData(field.GetValue(), buffer); - }, allFields); + TupleForEach([&buffer, this](auto& field) { this->WriteField(field, buffer); }, allFields); } };