based

Opinionated utility library
git clone git://git.dimitrijedobrota.com/based.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit 31eba4c2cd13a3c48329fec3c6cbdb7fa993381b
parent 7083865ed7f62a4e3c428ecd93da9fd611c58a9f
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Tue, 17 Jun 2025 00:14:34 +0200

Remove enum_type subclass for streamlined usage

Diffstat:
M include/based/enum/enum.hpp | +++++++++++++++++++++++++++++++++++ ----------------------------------------
M include/based/enum/enum_flag.hpp | ++++++++++++++++++++++++++++++++++++++++ ------------------------------------------
M test/source/enum_flag_test.cpp | +++++++ -------
M test/source/enum_test.cpp | +++++++++++ -----------

4 files changed, 157 insertions(+), 165 deletions(-)


diff --git a/ include/based/enum/enum.hpp b/ include/based/enum/enum.hpp

@@ -17,29 +17,29 @@

#define BASED_E_DETAIL_LIST_STR(...) \
BASED_FOREACH(BASED_E_DETAIL_LIST_ELEM_STR, __VA_ARGS__)

// NOLINTNEXTLINE(*macro-parentheses*)
#define BASED_E_DETAIL_SET(var, val) decltype(var) var = decltype(var) {val};
#define BASED_E_DETAIL_SET(Var, Value) \
/* NOLINTNEXTLINE(*macro-parentheses*) */ \
decltype(Var) Var = decltype(Var) {Value};

#define BASED_E_DETAIL_DECLARE_VAL(Name, Index) static const enum_type Name;
#define BASED_E_DETAIL_DECLARE_VAL(Name, Var, Index) static const Name Var;

#define BASED_E_DETAIL_DECLARE_CASE(Qualifier, Name, Index) \
case Qualifier::Name.value: \
return Name;
#define BASED_E_DETAIL_DECLARE_CASE(Qualifier, Var, Index) \
case Qualifier::Var.value: \
return Var;

#define BASED_E_DETAIL_DEFINE_VAL(Qualifier, Initial, Name, Index) \
#define BASED_E_DETAIL_DEFINE_VAL(Qualifier, Initial, Var, Index) \
inline constexpr BASED_E_DETAIL_SET( \
Qualifier::Name, \
Qualifier::enum_type::value_type {Initial} + Qualifier::enum_type::size \
- (Index) - 1 \
Qualifier::Var, \
Qualifier::value_type {Initial} + Qualifier::size - (Index) - 1 \
)

#define BASED_E_DETAIL_DEFINE_NAMES(Qualifier, ...) \
inline constexpr BASED_E_DETAIL_SET( \
Qualifier::enum_type::names, BASED_E_DETAIL_LIST_STR(__VA_ARGS__) \
Qualifier::names, BASED_E_DETAIL_LIST_STR(__VA_ARGS__) \
)

#define BASED_E_DETAIL_DEFINE_GET(Qualifier, Type, ...) \
inline const Qualifier::enum_type& Qualifier::enum_type::get(Type idx) \
inline const Qualifier& Qualifier::get(Type idx) \
{ \
/* NOLINTNEXTLINE(*paths-covered*) */ \
switch (idx) { \

@@ -57,9 +57,9 @@


#define BASED_DECLARE_ARRAY(Name, Initial) \
template<typename T> \
class array : public std::array<T, Name::enum_type::size> \
class array : public std::array<T, Name::size> \
{ \
using enum_type = Name::enum_type; \
using enum_type = Name; \
using base = std::array<T, enum_type::size>; \
using base::operator[]; \
using base::at; \

@@ -102,41 +102,36 @@

#define BASED_DECLARE_ENUM(Name, Type, Initial, ...) \
struct Name \
{ \
class enum_type \
constexpr explicit Name(Type enum_value) \
: value(enum_value) \
{ \
friend Name; \
\
constexpr explicit enum_type(Type enum_value) \
: value(enum_value) \
{ \
} \
} \
\
public: \
using value_type = Type; \
using size_type = Type; \
public: \
using value_type = Type; \
using size_type = Type; \
\
static constexpr size_type size = \
BASED_E_DETAIL_NUMARGS(BASED_E_DETAIL_LIST_STR(__VA_ARGS__)); \
static constexpr size_type size = \
BASED_E_DETAIL_NUMARGS(BASED_E_DETAIL_LIST_STR(__VA_ARGS__)); \
\
BASED_DECLARE_ARRAY(Name, Initial) \
static const array<const char*> names; \
BASED_DECLARE_ARRAY(Name, Initial) \
static const array<const char*> names; \
\
static const enum_type& get(Type idx); \
static const Name& get(Type idx); \
\
constexpr Type operator()() const \
{ \
return value; \
} \
constexpr Type operator()() const \
{ \
return value; \
} \
\
friend bool operator==(enum_type lhs, enum_type rhs) \
{ \
return lhs.value == rhs.value; \
} \
friend bool operator==(Name lhs, Name rhs) \
{ \
return lhs.value == rhs.value; \
} \
\
Type value; \
}; \
Type value; \
\
BASED_FOREACH(BASED_E_DETAIL_DECLARE_VAL, __VA_ARGS__) \
BASED_FOREACH_1(Name, 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

@@ -14,21 +14,22 @@

#define BASED_EF_DETAIL_LIST_STR(...) \
BASED_FOREACH(BASED_EF_DETAIL_LIST_ELEM_STR, __VA_ARGS__)

// NOLINTNEXTLINE(*macro-parentheses*)
#define BASED_EF_DETAIL_SET(var, val) decltype(var) var = decltype(var) {val};
#define BASED_EF_DETAIL_SET(Var, Value) \
/* NOLINTNEXTLINE(*macro-parentheses*) */ \
decltype(Var) Var = decltype(Var) {Value};

#define BASED_EF_DETAIL_DECLARE_ENUM_VAL(Name, Index) \
static const enum_type Name;
#define BASED_EF_DETAIL_DECLARE_ENUM_VAL(Name, Var, Index) \
static const Name Var;

#define BASED_EF_DETAIL_DECLARE_ENUM_CASE(Qualifier, Name, Index) \
case Qualifier::Name.value: \
return Name;
#define BASED_EF_DETAIL_DECLARE_ENUM_CASE(Qualifier, Var, Index) \
case Qualifier::Var.value: \
return Var;

#define BASED_EF_DETAIL_DEFINE_VAL(Qualifier, Name, Index) \
#define BASED_EF_DETAIL_DEFINE_VAL(Qualifier, Var, Index) \
inline constexpr BASED_EF_DETAIL_SET( \
Qualifier::Name, \
Qualifier::enum_type::value_type {1} << Qualifier::enum_type:: \
value_type {Qualifier::enum_type::size - (Index) - 2} \
Qualifier::Var, \
Qualifier::value_type {1} \
<< Qualifier::value_type {Qualifier::size - (Index) - 2} \
)

#define BASED_EF_DETAIL_DEFINE_VALS(Qualifier, First, ...) \

@@ -36,7 +37,7 @@

inline constexpr BASED_EF_DETAIL_SET(Qualifier::First, 0)

#define BASED_EF_DETAIL_DEFINE_GET(Qualifier, Type, ...) \
inline const Qualifier::enum_type& Qualifier::enum_type::get(Type idx) \
inline const Qualifier& Qualifier::get(Type idx) \
{ \
/* NOLINTNEXTLINE(*paths-covered*) */ \
switch (idx) { \

@@ -56,102 +57,98 @@

#define BASED_DECLARE_ENUM_FLAG(Name, Type, ...) \
struct Name \
{ \
class enum_type \
friend struct based::enum_flag_wrapper<Name>; \
\
constexpr explicit Name(Type enum_value) \
: value(enum_value) \
{ \
} \
\
public: \
using value_type = Type; \
using size_type = Type; \
\
static constexpr size_type size = \
BASED_EF_DETAIL_NUMARGS(BASED_EF_DETAIL_LIST_STR(__VA_ARGS__)); \
\
static const Name& get(Type idx); \
\
Name& set(Name val) \
{ \
return *this |= val; \
} \
\
Name& mask(Name val) \
{ \
return *this &= val; \
} \
\
Name& tgl(Name val) \
{ \
return *this ^= val; \
} \
\
Name& neg() \
{ \
return *this = ~*this; \
} \
\
Name& clear(Name val) \
{ \
return *this &= ~val; \
} \
\
bool test(Name val) const \
{ \
return (*this & val) == val; \
} \
\
friend bool operator==(Name lhs, Name rhs) \
{ \
friend Name; \
friend struct based::enum_flag_wrapper<enum_type>; \
\
constexpr explicit enum_type(Type enum_value) \
: value(enum_value) \
{ \
} \
\
public: \
using value_type = Type; \
using size_type = Type; \
\
static constexpr size_type size = \
BASED_EF_DETAIL_NUMARGS(BASED_EF_DETAIL_LIST_STR(__VA_ARGS__)); \
\
static const enum_type& get(Type idx); \
\
enum_type& set(enum_type val) \
{ \
return *this |= val; \
} \
\
enum_type& mask(enum_type val) \
{ \
return *this &= val; \
} \
\
enum_type& tgl(enum_type val) \
{ \
return *this ^= val; \
} \
\
enum_type& neg() \
{ \
return *this = ~*this; \
} \
\
enum_type& clear(enum_type val) \
{ \
return *this &= ~val; \
} \
\
bool test(enum_type val) const \
{ \
return (*this & val) == val; \
} \
\
friend bool operator==(enum_type lhs, enum_type rhs) \
{ \
return lhs.value == rhs.value; \
} \
\
friend enum_type operator|(enum_type lhs, enum_type rhs) \
{ \
return enum_type(lhs.value | rhs.value); \
} \
\
friend enum_type operator&(enum_type lhs, enum_type rhs) \
{ \
return enum_type(lhs.value & rhs.value); \
} \
\
friend enum_type operator^(enum_type lhs, enum_type rhs) \
{ \
return enum_type(lhs.value ^ rhs.value); \
} \
\
enum_type operator~() const \
{ \
return enum_type(~value); \
} \
\
enum_type& operator|=(enum_type rhs) \
{ \
value |= rhs.value; \
return *this; \
} \
\
enum_type& operator&=(enum_type rhs) \
{ \
value &= rhs.value; \
return *this; \
} \
\
enum_type& operator^=(enum_type rhs) \
{ \
value ^= rhs.value; \
return *this; \
} \
\
Type value; \
}; \
\
BASED_FOREACH(BASED_EF_DETAIL_DECLARE_ENUM_VAL, __VA_ARGS__) \
return lhs.value == rhs.value; \
} \
\
friend Name operator|(Name lhs, Name rhs) \
{ \
return Name(lhs.value | rhs.value); \
} \
\
friend Name operator&(Name lhs, Name rhs) \
{ \
return Name(lhs.value & rhs.value); \
} \
\
friend Name operator^(Name lhs, Name rhs) \
{ \
return Name(lhs.value ^ rhs.value); \
} \
\
Name operator~() const \
{ \
return Name(~value); \
} \
\
Name& operator|=(Name rhs) \
{ \
value |= rhs.value; \
return *this; \
} \
\
Name& operator&=(Name rhs) \
{ \
value &= rhs.value; \
return *this; \
} \
\
Name& operator^=(Name rhs) \
{ \
value ^= rhs.value; \
return *this; \
} \
\
Type value; \
\
BASED_FOREACH_1(Name, BASED_EF_DETAIL_DECLARE_ENUM_VAL, __VA_ARGS__) \
};

#define BASED_DEFINE_ENUM_FLAG(Name, Type, ...) \

diff --git a/ test/source/enum_flag_test.cpp b/ test/source/enum_flag_test.cpp

@@ -22,7 +22,7 @@ TEST_CASE("types", "[enum/enum_flag]")

STATIC_REQUIRE(requires { var::a; });
STATIC_REQUIRE(requires { var::b; });
STATIC_REQUIRE(requires { var::c; });
STATIC_REQUIRE(var::enum_type::size == 4);
STATIC_REQUIRE(var::size == 4);
STATIC_REQUIRE(var::empty.value == 0);
STATIC_REQUIRE(var::a.value == 1);
STATIC_REQUIRE(var::b.value == 2);

@@ -35,11 +35,11 @@ TEST_CASE("operations", "[enum/enum_flag]")


SECTION("COMPARE")
{
STATIC_REQUIRE(based::EqualityComparable<var::enum_type>);
STATIC_REQUIRE(!based::LessComparable<var::enum_type>);
STATIC_REQUIRE(!based::GreaterComparable<var::enum_type>);
STATIC_REQUIRE(!based::LessEqualComparable<var::enum_type>);
STATIC_REQUIRE(!based::GreaterEqualComparable<var::enum_type>);
STATIC_REQUIRE(based::EqualityComparable<var>);
STATIC_REQUIRE(!based::LessComparable<var>);
STATIC_REQUIRE(!based::GreaterComparable<var>);
STATIC_REQUIRE(!based::LessEqualComparable<var>);
STATIC_REQUIRE(!based::GreaterEqualComparable<var>);
}

SECTION("functions")

@@ -75,7 +75,7 @@ TEST_CASE("enum_flag_wrapper", "[enum/enum_flag_wrapper]")

based::bu8 flags = 0;

{
auto wrapper = based::enum_flag_wrapper<var::enum_type>(flags);
auto wrapper = based::enum_flag_wrapper<var>(flags);

wrapper |= var::a;
wrapper |= var::c;

diff --git a/ test/source/enum_test.cpp b/ test/source/enum_test.cpp

@@ -17,7 +17,7 @@ struct test

{
BASED_DECLARE_ENUM(var, based::bu8, 0, a, b, c)

[[nodiscard]] int get_var(var::enum_type req) const;
[[nodiscard]] int get_var(var req) const;

private:
int m_a = 1;

@@ -27,7 +27,7 @@ private:


BASED_DEFINE_ENUM_CLASS(test, var, based::bu8, 0, a, b, c)

inline int test::get_var(var::enum_type req) const
inline int test::get_var(var req) const
{
switch (req()) {
case var::a():

@@ -47,7 +47,7 @@ TEST_CASE("types", "[enum/enum]")

STATIC_REQUIRE(requires { test::var::a; });
STATIC_REQUIRE(requires { test::var::b; });
STATIC_REQUIRE(requires { test::var::c; });
STATIC_REQUIRE(test::var::enum_type::size == 3);
STATIC_REQUIRE(test::var::size == 3);
STATIC_REQUIRE(test::var::a() == 0);
STATIC_REQUIRE(test::var::b() == 1);
STATIC_REQUIRE(test::var::c() == 2);

@@ -67,18 +67,18 @@ TEST_CASE("safety", "[enum/enum]")


TEST_CASE("names", "[enum/enum]")
{
REQUIRE(std::strcmp(test::var::enum_type::names[test::var::a], "a") == 0);
REQUIRE(std::strcmp(test::var::enum_type::names[test::var::b], "b") == 0);
REQUIRE(std::strcmp(test::var::enum_type::names[test::var::c], "c") == 0);
REQUIRE(std::strcmp(test::var::names[test::var::a], "a") == 0);
REQUIRE(std::strcmp(test::var::names[test::var::b], "b") == 0);
REQUIRE(std::strcmp(test::var::names[test::var::c], "c") == 0);
}

TEST_CASE("operations", "[enum/enum]")
{
using based::SameAs;

STATIC_REQUIRE(based::EqualityComparable<test::var::enum_type>);
STATIC_REQUIRE(!based::LessComparable<test::var::enum_type>);
STATIC_REQUIRE(!based::GreaterComparable<test::var::enum_type>);
STATIC_REQUIRE(!based::LessEqualComparable<test::var::enum_type>);
STATIC_REQUIRE(!based::GreaterEqualComparable<test::var::enum_type>);
STATIC_REQUIRE(based::EqualityComparable<test::var>);
STATIC_REQUIRE(!based::LessComparable<test::var>);
STATIC_REQUIRE(!based::GreaterComparable<test::var>);
STATIC_REQUIRE(!based::LessEqualComparable<test::var>);
STATIC_REQUIRE(!based::GreaterEqualComparable<test::var>);
}