mirror of
https://github.com/Neargye/magic_enum.git
synced 2026-01-10 23:44:29 +00:00
New enum-flags API (#120)
This commit is contained in:
parent
6a1db3b8b6
commit
aecf0db795
7 changed files with 336 additions and 477 deletions
|
|
@ -57,38 +57,33 @@ enum number : unsigned long {
|
|||
_4 = four
|
||||
#endif
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
|
||||
enum class MaxUsedAsInvalid : std::uint8_t {
|
||||
ONE,
|
||||
TWO,
|
||||
INVALID = std::numeric_limits<std::uint8_t>::max()
|
||||
ONE,
|
||||
TWO,
|
||||
INVALID = std::numeric_limits<std::uint8_t>::max()
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<MaxUsedAsInvalid> {
|
||||
static constexpr int min = 0;
|
||||
static constexpr int max = 64;
|
||||
};
|
||||
|
||||
enum class Binary : bool {
|
||||
ONE,
|
||||
TWO
|
||||
};
|
||||
|
||||
namespace magic_enum::customize {
|
||||
template <>
|
||||
struct enum_range<MaxUsedAsInvalid> {
|
||||
static constexpr int min = 0;
|
||||
static constexpr int max = 64;
|
||||
struct magic_enum::customize::enum_range<Binary> {
|
||||
static constexpr int min = 0;
|
||||
static constexpr int max = 64;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct enum_range<Binary> {
|
||||
static constexpr int min = 0;
|
||||
static constexpr int max = 64;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
} // namespace magic_enum
|
||||
|
||||
template <>
|
||||
constexpr std::string_view magic_enum::customize::enum_name<Color>(Color value) noexcept {
|
||||
switch (value) {
|
||||
|
|
@ -847,69 +842,69 @@ TEST_CASE("extrema") {
|
|||
|
||||
SECTION("min") {
|
||||
REQUIRE(magic_enum::customize::enum_range<BadColor>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<BadColor> == 0);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<BadColor, false> == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<BadColor> == 0);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Color>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Color> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Color, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Color> == -12);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Numbers>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Numbers> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Numbers, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Numbers> == 1);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Directions>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Directions> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Directions, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Directions> == -120);
|
||||
|
||||
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||
REQUIRE(magic_enum::customize::enum_range<Language>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Language> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Language, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Language> == 10);
|
||||
#endif
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<number>::min == 100);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<number> == 100);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<number, false> == 100);
|
||||
REQUIRE(magic_enum::detail::min_v<number> == 100);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Binary> == 0);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Binary, false> == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<Binary> == false);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<MaxUsedAsInvalid> == 0);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<MaxUsedAsInvalid,false> == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<MaxUsedAsInvalid> == 0);
|
||||
}
|
||||
|
||||
SECTION("max") {
|
||||
REQUIRE(magic_enum::customize::enum_range<BadColor>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<BadColor> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<BadColor, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<BadColor> == 2);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Color>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Color> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Color, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Color> == 15);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Numbers>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Numbers> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Numbers, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Numbers> == 3);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Directions>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Directions> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Directions, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Directions> == 120);
|
||||
|
||||
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||
REQUIRE(magic_enum::customize::enum_range<Language>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Language> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Language, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Language> == 40);
|
||||
#endif
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<number>::max == 300);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<number> == 300);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<number, false> == 300);
|
||||
REQUIRE(magic_enum::detail::max_v<number> == 300);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Binary> == 1);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Binary, false> == 1);
|
||||
REQUIRE(magic_enum::detail::max_v<Binary> == true);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<MaxUsedAsInvalid> == 64);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<MaxUsedAsInvalid, false> == 64);
|
||||
REQUIRE(magic_enum::detail::max_v<MaxUsedAsInvalid> == 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
#include <sstream>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::is_flags_enum<Color> : std::true_type {};
|
||||
|
||||
enum class Numbers : int {
|
||||
one = 1 << 1,
|
||||
|
|
@ -77,16 +79,13 @@ enum number : unsigned long {
|
|||
_4 = four
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace magic_enum::customize {
|
||||
template <>
|
||||
struct enum_range<number> {
|
||||
struct magic_enum::customize::enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
} // namespace magic_enum
|
||||
|
||||
using namespace magic_enum::flags;
|
||||
using namespace magic_enum;
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
|
||||
TEST_CASE("enum_cast") {
|
||||
|
|
@ -453,39 +452,39 @@ TEST_CASE("enum_count") {
|
|||
TEST_CASE("enum_name") {
|
||||
SECTION("automatic storage") {
|
||||
constexpr Color cr = Color::RED;
|
||||
auto cr_name = enum_name(cr);
|
||||
constexpr auto cr_name = enum_name(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
Color cb = Color::BLUE;
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(enum_name<Color&>(cb) == "BLUE");
|
||||
REQUIRE(enum_name(cm[1]) == "GREEN");
|
||||
REQUIRE(enum_name(Color::RED | Color{0}) == "RED");
|
||||
REQUIRE(enum_name(Color::RED | Color::GREEN) == "RED|GREEN");
|
||||
REQUIRE(enum_name(Color::RED | Color::GREEN).empty());
|
||||
REQUIRE(enum_name(Color::RED | Color{8}).empty());
|
||||
REQUIRE(enum_name(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
auto no_name = enum_name(no);
|
||||
constexpr auto no_name = enum_name(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(enum_name(Numbers::two) == "two");
|
||||
REQUIRE(enum_name(Numbers::three) == "three");
|
||||
REQUIRE(enum_name(Numbers::many) == "many");
|
||||
REQUIRE(enum_name(Numbers::many | Numbers::two) == "two|many");
|
||||
REQUIRE(enum_name(Numbers::many | Numbers::two).empty());
|
||||
REQUIRE(enum_name(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
auto dr_name = enum_name(dr);
|
||||
constexpr auto dr_name = enum_name(dr);
|
||||
Directions du = Directions::Up;
|
||||
REQUIRE(enum_name<Directions&>(du) == "Up");
|
||||
REQUIRE(enum_name<const Directions>(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(enum_name(Directions::Left) == "Left");
|
||||
REQUIRE(enum_name(Directions::Right | Directions::Up | Directions::Left | Directions::Down) == "Left|Down|Up|Right");
|
||||
REQUIRE(enum_name(Directions::Right | Directions::Up | Directions::Left | Directions::Down).empty());
|
||||
REQUIRE(enum_name(static_cast<Directions>(0)).empty());
|
||||
|
||||
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||
constexpr Language lang = Language::日本語;
|
||||
auto lang_name = enum_name(lang);
|
||||
constexpr auto lang_name = enum_name(lang);
|
||||
Language lk = Language::한국어;
|
||||
REQUIRE(enum_name<Language&>(lk) == "한국어");
|
||||
REQUIRE(enum_name<const Language>(Language::English) == "English");
|
||||
|
|
@ -495,16 +494,69 @@ TEST_CASE("enum_name") {
|
|||
#endif
|
||||
|
||||
constexpr number nto = number::three | number::one;
|
||||
auto nto_name = enum_name(nto);
|
||||
constexpr auto nto_name = enum_name(nto);
|
||||
REQUIRE(enum_name(number::one) == "one");
|
||||
REQUIRE(enum_name(number::two) == "two");
|
||||
REQUIRE(enum_name(number::three) == "three");
|
||||
REQUIRE(enum_name(number::four) == "four");
|
||||
REQUIRE(nto_name == "one|three");
|
||||
REQUIRE(nto_name.empty());
|
||||
REQUIRE(enum_name(static_cast<number>(0)).empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_flags_name") {
|
||||
constexpr Color cr = Color::RED;
|
||||
auto cr_name = enum_flags_name(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
Color cb = Color::BLUE;
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(enum_flags_name<Color&>(cb) == "BLUE");
|
||||
REQUIRE(enum_flags_name(cm[1]) == "GREEN");
|
||||
REQUIRE(enum_flags_name(Color::RED | Color{0}) == "RED");
|
||||
REQUIRE(enum_flags_name(Color::RED | Color::GREEN) == "RED|GREEN");
|
||||
REQUIRE(enum_flags_name(Color::RED | Color{8}).empty());
|
||||
REQUIRE(enum_flags_name(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
auto no_name = enum_flags_name(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(enum_flags_name(Numbers::two) == "two");
|
||||
REQUIRE(enum_flags_name(Numbers::three) == "three");
|
||||
REQUIRE(enum_flags_name(Numbers::many) == "many");
|
||||
REQUIRE(enum_flags_name(Numbers::many | Numbers::two) == "two|many");
|
||||
REQUIRE(enum_flags_name(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
auto dr_name = enum_flags_name(dr);
|
||||
Directions du = Directions::Up;
|
||||
REQUIRE(enum_flags_name<Directions&>(du) == "Up");
|
||||
REQUIRE(enum_flags_name<const Directions>(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(enum_flags_name(Directions::Left) == "Left");
|
||||
REQUIRE(enum_flags_name(Directions::Right | Directions::Up | Directions::Left | Directions::Down) == "Left|Down|Up|Right");
|
||||
REQUIRE(enum_flags_name(static_cast<Directions>(0)).empty());
|
||||
|
||||
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||
constexpr Language lang = Language::日本語;
|
||||
auto lang_name = enum_flags_name(lang);
|
||||
Language lk = Language::한국어;
|
||||
REQUIRE(enum_flags_name<Language&>(lk) == "한국어");
|
||||
REQUIRE(enum_flags_name<const Language>(Language::English) == "English");
|
||||
REQUIRE(lang_name == "日本語");
|
||||
REQUIRE(enum_flags_name(Language::😃) == "😃");
|
||||
REQUIRE(enum_flags_name(static_cast<Language>(0)).empty());
|
||||
#endif
|
||||
|
||||
constexpr number nto = number::three | number::one;
|
||||
auto nto_name = enum_flags_name(nto);
|
||||
REQUIRE(enum_flags_name(number::one) == "one");
|
||||
REQUIRE(enum_flags_name(number::two) == "two");
|
||||
REQUIRE(enum_flags_name(number::three) == "three");
|
||||
REQUIRE(enum_flags_name(number::four) == "four");
|
||||
REQUIRE(nto_name == "one|three");
|
||||
REQUIRE(enum_flags_name(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("enum_names") {
|
||||
REQUIRE(std::is_same_v<decltype(magic_enum::enum_names<Color>()), const std::array<std::string_view, 3>&>);
|
||||
|
||||
|
|
@ -549,7 +601,7 @@ TEST_CASE("enum_entries") {
|
|||
|
||||
TEST_CASE("ostream_operators") {
|
||||
auto test_ostream = [](auto e, std::string_view name) {
|
||||
using namespace magic_enum::flags::ostream_operators;
|
||||
using namespace magic_enum::ostream_operators;
|
||||
std::stringstream ss;
|
||||
ss << e;
|
||||
REQUIRE(ss.str() == name);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue