feat: add alignment
This commit is contained in:
@@ -5,13 +5,68 @@
|
||||
|
||||
namespace sp {
|
||||
|
||||
template <typename ValueType>
|
||||
/**
|
||||
* \brief Example usage :
|
||||
* sp::BitField<std::uint16_t, sp::Field<std::uint16_t, 12>, sp::Field<std::uint8_t, 4>>;
|
||||
*/
|
||||
template <typename TContainer, typename... TFields>
|
||||
class BitField {
|
||||
using AllFields = std::tuple<TFields...>;
|
||||
|
||||
public:
|
||||
template <typename... T>
|
||||
BitField(const std::tuple<T...>& args) {
|
||||
Apply<0, T...>(args);
|
||||
}
|
||||
|
||||
BitField() {}
|
||||
|
||||
template <typename... T>
|
||||
BitField& operator=(const std::tuple<T...>& args) {
|
||||
Apply<0, T...>(args);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AllFields& GetFields() {
|
||||
return m_Fields;
|
||||
}
|
||||
|
||||
const AllFields& GetFields() const {
|
||||
return m_Fields;
|
||||
}
|
||||
|
||||
template <std::size_t FIndex>
|
||||
auto& GetField() {
|
||||
return std::get<FIndex>(this->GetFields()).GetValue();
|
||||
}
|
||||
|
||||
private:
|
||||
template <int IOffset, typename... T, std::enable_if_t<IOffset >= sizeof...(T), bool> = true>
|
||||
void Apply(const std::tuple<T...>& args) {}
|
||||
|
||||
template <int IOffset, typename... T, std::enable_if_t<!(IOffset >= sizeof...(T)), bool> = true>
|
||||
void Apply(const std::tuple<T...>& args) {
|
||||
this->GetField<IOffset>() = std::get<IOffset>(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 <typename ValueType, int IAlignment>
|
||||
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<std::tuple<TFields...>> {
|
||||
|
||||
template <typename TField, typename... TFields>
|
||||
struct FieldsBuilder<TField, TFields...> {
|
||||
using Type = sp::tuple_cat_t<std::tuple<Field<TField>>, typename FieldsBuilder<TFields...>::Type>;
|
||||
using Type = sp::tuple_cat_t<std::tuple<Field<TField, 0>>, typename FieldsBuilder<TFields...>::Type>;
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
|
||||
@@ -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 <typename TBase>
|
||||
class MessageImplFieldsReadBase : public TBase {
|
||||
protected:
|
||||
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, int 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();
|
||||
std::apply([&buffer, this](auto& field) {
|
||||
this->ReadData(field.GetValue(), buffer);
|
||||
}, allFields);
|
||||
TupleForEach([&buffer, this](auto& field) { this->ReadField(field, buffer); }, allFields);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TBase>
|
||||
class MessageImplFieldsWriteBase : public TBase {
|
||||
protected:
|
||||
private:
|
||||
// normal writing
|
||||
template <typename TField>
|
||||
void WriteField(Field<TField, 0>& field, DataBuffer& buffer) {
|
||||
this->WriteData(field.GetValue(), buffer);
|
||||
}
|
||||
|
||||
// writing field in bitfield
|
||||
template <typename TFieldType, typename TField, int IAlignment>
|
||||
void WriteField(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
|
||||
data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset;
|
||||
}
|
||||
|
||||
// writing bitfield
|
||||
template <typename TContainer, typename TFirst, typename... TFields>
|
||||
void WriteField(Field<BitField<TContainer, TFirst, TFields...>, 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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user