basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 5c92017e0635dd36a1a92271dd85edcfd7217415 |
parent | 60fb6e4800f2059f967fc494477beb52aa08199e |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Sat, 10 May 2025 19:43:53 +0200 |
Add enum_flag_wrapper for dealing with legacy
M | include/based/enum/enum.hpp | | | ++++++++++++++++ ------------------ |
M | include/based/enum/enum_flag.hpp | | | ++++++++++++++++++++++++++++++++++ |
M | test/source/enum_flag_test.cpp | | | ++++++++++++++ |
3 files changed, 64 insertions(+), 18 deletions(-)
diff --git a/ include/based/enum/enum.hpp b/ include/based/enum/enum.hpp
@@ -14,7 +14,7 @@
#define BASED_E_DETAIL_LIST_ELEM_STR(Name, Index) #Name,
#define BASED_E_DETAIL_LIST_STR(...) \
#define BASED_E_DETAIL_LIST_STR(...) \
BASED_FOREACH(BASED_E_DETAIL_LIST_ELEM_STR, __VA_ARGS__)
// NOLINTNEXTLINE(*macro-parentheses*)
@@ -22,40 +22,38 @@
#define BASED_E_DETAIL_DECLARE_VAL(Name, Index) static const type Name;
#define BASED_E_DETAIL_DECLARE_CASE(Qualifier, Name, Index) \
#define BASED_E_DETAIL_DECLARE_CASE(Qualifier, Name, Index) \
case Qualifier::Name.value: \
return Name;
#define BASED_E_DETAIL_DEFINE_VAL(Qualifier, Initial, Name, Index) \
inline constexpr BASED_E_DETAIL_SET( \
#define BASED_E_DETAIL_DEFINE_VAL(Qualifier, Initial, Name, Index) \
inline constexpr BASED_E_DETAIL_SET( \
Qualifier::Name, (Initial) + Qualifier::type::size - (Index) - 1 \
)
#define BASED_E_DETAIL_DEFINE_NAMES(Qualifier, ...) \
inline constexpr BASED_E_DETAIL_SET( \
Qualifier::type::names, BASED_E_DETAIL_LIST_STR(__VA_ARGS__) \
#define BASED_E_DETAIL_DEFINE_NAMES(Qualifier, ...) \
inline constexpr BASED_E_DETAIL_SET( \
Qualifier::type::names, BASED_E_DETAIL_LIST_STR(__VA_ARGS__) \
)
#define BASED_E_DETAIL_DEFINE_GET(Qualifier, Type, ...) \
#define BASED_E_DETAIL_DEFINE_GET(Qualifier, Type, ...) \
inline const Qualifier::type& Qualifier::type::get(Type idx) \
{ \
/* NOLINTNEXTLINE(*paths-covered*) */ \
switch (idx) { \
BASED_FOREACH_1(Qualifier, BASED_E_DETAIL_DECLARE_CASE, __VA_ARGS__) \
BASED_FOREACH_1(Qualifier, BASED_E_DETAIL_DECLARE_CASE, __VA_ARGS__) \
default: \
break; \
} \
assert(0); /* NOLINT(*assert*,cert-dcl03-c) */ \
}
#define BASED_E_DETAIL_DEFINE(Qualifier, Type, Initial, ...) \
BASED_FOREACH_2( \
Qualifier, Initial, BASED_E_DETAIL_DEFINE_VAL, __VA_ARGS__ \
) \
BASED_E_DETAIL_DEFINE_NAMES(Qualifier, __VA_ARGS__) \
#define BASED_E_DETAIL_DEFINE(Qualifier, Type, Initial, ...) \
BASED_FOREACH_2(Qualifier, Initial, BASED_E_DETAIL_DEFINE_VAL, __VA_ARGS__) \
BASED_E_DETAIL_DEFINE_NAMES(Qualifier, __VA_ARGS__) \
BASED_E_DETAIL_DEFINE_GET(Qualifier, Type, __VA_ARGS__)
#define BASED_DECLARE_ARRAY(Name, Initial) \
#define BASED_DECLARE_ARRAY(Name, Initial) \
template<typename T> \
class array : public std::array<T, Name::type::size> \
{ \
@@ -115,9 +113,9 @@
using size_type = Type; \
\
static constexpr size_type size = \
BASED_E_DETAIL_NUMARGS(BASED_E_DETAIL_LIST_STR(__VA_ARGS__)); \
BASED_E_DETAIL_NUMARGS(BASED_E_DETAIL_LIST_STR(__VA_ARGS__)); \
\
BASED_DECLARE_ARRAY(Name, Initial) \
BASED_DECLARE_ARRAY(Name, Initial) \
static const array<const char*> names; \
\
static const type& get(Type idx); \
@@ -130,7 +128,7 @@
Type value; \
}; \
\
BASED_FOREACH(BASED_E_DETAIL_DECLARE_VAL, __VA_ARGS__) \
BASED_FOREACH(BASED_E_DETAIL_DECLARE_VAL, __VA_ARGS__) \
};
#define BASED_DEFINE_ENUM(Name, Type, Initial, ...) \
diff --git a/ include/based/enum/enum_flag.hpp b/ include/based/enum/enum_flag.hpp
@@ -158,4 +158,38 @@
#define BASED_DEFINE_ENUM_FLAG_CLASS(Class, Name, Type, ...) \
BASED_EF_DETAIL_DEFINE(Class::Name, Type, __VA_ARGS__)
namespace based
{
template<class FlagType>
struct enum_flag_wrapper : public FlagType
{
using value_type = FlagType::value_type;
explicit enum_flag_wrapper(value_type& value)
: FlagType(value)
, m_value(&value)
{
}
enum_flag_wrapper& operator=(FlagType flag)
{
*m_value = flag.value;
return *this;
}
~enum_flag_wrapper() { *m_value = FlagType::value; }
enum_flag_wrapper(const enum_flag_wrapper&) = delete;
enum_flag_wrapper& operator=(const enum_flag_wrapper&) = delete;
enum_flag_wrapper(enum_flag_wrapper&&) = default;
enum_flag_wrapper& operator=(enum_flag_wrapper&&) = default;
private:
value_type* m_value;
};
} // namespace based
// NOLINTEND(*macro-usage*)
diff --git a/ test/source/enum_flag_test.cpp b/ test/source/enum_flag_test.cpp
@@ -69,3 +69,17 @@
TEST_CASE("operations", "[enum/enum_flag]")
REQUIRE(var4.test(var::c));
}
}
TEST_CASE("enum_flag_wrapper", "[enum/enum_flag_wrapper]")
{
based::u8 flags = 0;
{
auto wrapper = based::enum_flag_wrapper<var::type>(flags);
wrapper |= var::a;
wrapper |= var::c;
}
REQUIRE(flags == 0x5);
}