#pragma once #include #include namespace sp { /** * \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(); } template const auto& GetField() const { return std::get(this->GetFields()).GetValue(); } // allow use of enums template const auto& GetField() const { return std::get(FIndex)>(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: using StorageType = ValueType; static constexpr std::size_t AlignmentValue = IAlignment; // Provide an access to the stored value StorageType& GetValue() { return m_Value; } const StorageType& GetValue() const { return m_Value; } Field& operator=(const StorageType& value) { m_Value = value; return *this; } constexpr std::size_t GetAlignment() const { return IAlignment; } private: StorageType m_Value; }; namespace details { template struct FieldsBuilder {}; template <> struct FieldsBuilder<> { using Type = std::tuple<>; }; template struct FieldsBuilder> { using Type = typename FieldsBuilder::Type; }; template struct FieldsBuilder { using Type = sp::tuple_cat_t>, typename FieldsBuilder::Type>; }; } // namespace details } // namespace sp