120 lines
2.5 KiB
C++
120 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include <sp/common/DataBuffer.h>
|
|
#include <sp/common/Templates.h>
|
|
|
|
namespace sp {
|
|
|
|
/**
|
|
* \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();
|
|
}
|
|
|
|
template <std::size_t FIndex>
|
|
const auto& GetField() const {
|
|
return std::get<FIndex>(this->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:
|
|
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;
|
|
}
|
|
|
|
Field& operator=(const ValueType& value) {
|
|
m_Value = value;
|
|
return *this;
|
|
}
|
|
|
|
constexpr int GetAlignment() const {
|
|
return IAlignment;
|
|
}
|
|
|
|
private:
|
|
ValueType m_Value;
|
|
};
|
|
|
|
namespace details {
|
|
|
|
template <typename... TFields>
|
|
struct FieldsBuilder {};
|
|
|
|
template <>
|
|
struct FieldsBuilder<> {
|
|
using Type = std::tuple<>;
|
|
};
|
|
|
|
template <typename... TFields>
|
|
struct FieldsBuilder<std::tuple<TFields...>> {
|
|
using Type = typename FieldsBuilder<TFields...>::Type;
|
|
};
|
|
|
|
template <typename TField, typename... TFields>
|
|
struct FieldsBuilder<TField, TFields...> {
|
|
using Type = sp::tuple_cat_t<std::tuple<Field<TField, 0>>, typename FieldsBuilder<TFields...>::Type>;
|
|
};
|
|
} // namespace details
|
|
|
|
} // namespace sp
|