1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-09 23:34:23 +00:00

improve customize

This commit is contained in:
Daniil Goncharov 2020-09-07 12:55:59 +03:00 committed by GitHub
parent 000551a655
commit 690486e7f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 49 deletions

View file

@ -22,14 +22,14 @@
#include <magic_enum.hpp>
```
* If need another range for specific enum type, add specialization `enum_range` for necessary enum type. Specialization of `enum_range` must be injected in `namespace magic_enum`.
* If need another range for specific enum type, add specialization `enum_range` for necessary enum type. Specialization of `enum_range` must be injected in `namespace magic_enum::customize`.
```cpp
#include <magic_enum.hpp>
enum class number { one = 100, two = 200, three = 300 };
namespace magic_enum {
namespace magic_enum::customize {
template <>
struct enum_range<number> {
static constexpr int min = 100; // Must be greater than `INT16_MIN`.

View file

@ -26,17 +26,46 @@
enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 };
// Сustom definitions of name for enum value.
// Сustom definitions of names for enum.
// Specialization of `enum_name` must be injected in `namespace magic_enum::customize`.
template <>
constexpr auto magic_enum::detail::n<Color, Color::RED>() noexcept {
return std::string_view{"the red color"};
constexpr std::string_view magic_enum::customize::enum_name<Color>(Color value) noexcept {
switch (value) {
case Color::RED:
return "the red color";
case Color::BLUE:
return "The BLUE";
case Color::GREEN:
return {}; // "Empty string for default value."
}
return {}; // "Empty string for unknow value."
}
enum class Numbers : int { One, Two, Three };
// Сustom definitions of names for enum.
// Specialization of `enum_name` must be injected in `namespace magic_enum::customize`.
template <>
constexpr std::string_view magic_enum::customize::enum_name<Numbers>(Numbers value) noexcept {
switch (value) {
case Numbers::One:
return "the one";
default:
return {}; // "Empty string for default or unknow value."
}
}
int main() {
std::cout << magic_enum::enum_name(Color::RED) << std::endl; // "the red color"
std::cout << magic_enum::enum_name(Color::BLUE) << std::endl; // "The BLUE"
std::cout << magic_enum::enum_name(Color::GREEN) << std::endl; // "GREEN"
std::cout << std::boolalpha;
std::cout << (magic_enum::enum_cast<Color>("the red color").value() == Color::RED) << std::endl; // "true"
std::cout << magic_enum::enum_name(Numbers::One) << std::endl; // "the one"
std::cout << magic_enum::enum_name(Numbers::Two) << std::endl; // "Two"
std::cout << magic_enum::enum_name(Numbers::Three) << std::endl; // "Three"
return 0;
}

View file

@ -91,25 +91,6 @@
namespace magic_enum {
// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128.
// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.
// If need another range for specific enum type, add specialization enum_range for necessary enum type.
template <typename E>
struct enum_range {
static_assert(std::is_enum_v<E>, "magic_enum::enum_range requires enum type.");
inline static constexpr int min = MAGIC_ENUM_RANGE_MIN;
inline static constexpr int max = MAGIC_ENUM_RANGE_MAX;
static_assert(max > min, "magic_enum::enum_range requires max > min.");
};
static_assert(MAGIC_ENUM_RANGE_MIN <= 0, "MAGIC_ENUM_RANGE_MIN must be less or equals than 0.");
static_assert(MAGIC_ENUM_RANGE_MIN > (std::numeric_limits<std::int16_t>::min)(), "MAGIC_ENUM_RANGE_MIN must be greater than INT16_MIN.");
static_assert(MAGIC_ENUM_RANGE_MAX > 0, "MAGIC_ENUM_RANGE_MAX must be greater than 0.");
static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits<std::int16_t>::max)(), "MAGIC_ENUM_RANGE_MAX must be less than INT16_MAX.");
static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL.
#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
MAGIC_ENUM_USING_ALIAS_OPTIONAL
@ -132,6 +113,37 @@ MAGIC_ENUM_USING_ALIAS_STRING
using string = std::string;
#endif
namespace customize {
// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128.
// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.
// If need another range for specific enum type, add specialization enum_range for necessary enum type.
template <typename E>
struct enum_range {
static_assert(std::is_enum_v<E>, "magic_enum::customize::enum_range requires enum type.");
inline static constexpr int min = MAGIC_ENUM_RANGE_MIN;
inline static constexpr int max = MAGIC_ENUM_RANGE_MAX;
static_assert(max > min, "magic_enum::customize::enum_range requires max > min.");
};
static_assert(MAGIC_ENUM_RANGE_MIN <= 0, "MAGIC_ENUM_RANGE_MIN must be less or equals than 0.");
static_assert(MAGIC_ENUM_RANGE_MIN > (std::numeric_limits<std::int16_t>::min)(), "MAGIC_ENUM_RANGE_MIN must be greater than INT16_MIN.");
static_assert(MAGIC_ENUM_RANGE_MAX > 0, "MAGIC_ENUM_RANGE_MAX must be greater than 0.");
static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits<std::int16_t>::max)(), "MAGIC_ENUM_RANGE_MAX must be less than INT16_MAX.");
static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
// If need cunstom names for enum type, add specialization enum_name for necessary enum type.
template <typename E>
constexpr string_view enum_name(E) noexcept {
static_assert(std::is_enum_v<E>, "magic_enum::customize::enum_name requires enum type.");
return {};
}
} // namespace magic_enum::customize
namespace detail {
template <typename T>
@ -306,16 +318,23 @@ inline constexpr auto type_name_v = n<E>();
template <typename E, E V>
constexpr auto n() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");
constexpr auto custom_name = customize::enum_name<E>(V);
if constexpr (custom_name.empty()) {
static_cast<void>(custom_name);
#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED
# if defined(__clang__) || defined(__GNUC__)
constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});
constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});
# elif defined(_MSC_VER)
constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});
constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});
# endif
return static_string<name.size()>{name};
return static_string<name.size()>{name};
#else
return string_view{}; // Unsupported compiler.
return string_view{}; // Unsupported compiler.
#endif
} else {
return static_string<custom_name.size()>{custom_name};
}
}
template <typename E, E V>
@ -335,7 +354,7 @@ constexpr int reflected_min() noexcept {
if constexpr (IsFlags) {
return 0;
} else {
constexpr auto lhs = enum_range<E>::min;
constexpr auto lhs = customize::enum_range<E>::min;
static_assert(lhs > (std::numeric_limits<std::int16_t>::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN.");
constexpr auto rhs = (std::numeric_limits<U>::min)();
@ -354,7 +373,7 @@ constexpr int reflected_max() noexcept {
if constexpr (IsFlags) {
return std::numeric_limits<U>::digits - 1;
} else {
constexpr auto lhs = enum_range<E>::max;
constexpr auto lhs = customize::enum_range<E>::max;
static_assert(lhs < (std::numeric_limits<std::int16_t>::max)(), "magic_enum::enum_range requires max must be less than INT16_MAX.");
constexpr auto rhs = (std::numeric_limits<U>::max)();

View file

@ -54,7 +54,7 @@ enum number : unsigned long {
#endif
};
namespace magic_enum {
namespace magic_enum::customize {
template <>
struct enum_range<number> {
static constexpr int min = 100;
@ -62,13 +62,23 @@ struct enum_range<number> {
};
} // namespace magic_enum
template <>
constexpr std::string_view magic_enum::customize::enum_name<Color>(Color value) noexcept {
switch (value) {
case Color::RED:
return "red";
default:
return {};
}
}
using namespace magic_enum;
static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
TEST_CASE("enum_cast") {
SECTION("string") {
constexpr auto cr = enum_cast<Color>("RED");
constexpr auto cr = enum_cast<Color>("red");
REQUIRE(cr.value() == Color::RED);
REQUIRE(enum_cast<Color&>("GREEN").value() == Color::GREEN);
REQUIRE(enum_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
@ -257,7 +267,7 @@ TEST_CASE("enum_contains") {
}
SECTION("string") {
constexpr auto cr = "RED";
constexpr auto cr = "red";
REQUIRE(enum_contains<Color>(cr));
REQUIRE(enum_contains<Color&>("GREEN"));
REQUIRE(enum_contains<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
@ -345,7 +355,7 @@ TEST_CASE("enum_name") {
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(cr_name == "red");
REQUIRE(enum_name<Color&>(cb) == "BLUE");
REQUIRE(enum_name(cm[1]) == "GREEN");
REQUIRE(enum_name(static_cast<Color>(0)).empty());
@ -380,7 +390,7 @@ TEST_CASE("enum_name") {
constexpr Color cr = Color::RED;
constexpr auto cr_name = enum_name<cr>();
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
REQUIRE(cr_name == "RED");
REQUIRE(cr_name == "red");
REQUIRE(enum_name<Color::BLUE>() == "BLUE");
REQUIRE(enum_name<cm[1]>() == "GREEN");
@ -411,7 +421,7 @@ TEST_CASE("enum_names") {
REQUIRE(std::is_same_v<decltype(magic_enum::enum_names<Color>()), const std::array<std::string_view, 3>&>);
constexpr auto& s1 = enum_names<Color&>();
REQUIRE(s1 == std::array<std::string_view, 3>{{"RED", "GREEN", "BLUE"}});
REQUIRE(s1 == std::array<std::string_view, 3>{{"red", "GREEN", "BLUE"}});
constexpr auto& s2 = enum_names<Numbers>();
REQUIRE(s2 == std::array<std::string_view, 3>{{"one", "two", "three"}});
@ -427,7 +437,7 @@ TEST_CASE("enum_entries") {
REQUIRE(std::is_same_v<decltype(magic_enum::enum_entries<Color>()), const std::array<std::pair<Color, std::string_view>, 3>&>);
constexpr auto& s1 = enum_entries<Color&>();
REQUIRE(s1 == std::array<std::pair<Color, std::string_view>, 3>{{{Color::RED, "RED"}, {Color::GREEN, "GREEN"}, {Color::BLUE, "BLUE"}}});
REQUIRE(s1 == std::array<std::pair<Color, std::string_view>, 3>{{{Color::RED, "red"}, {Color::GREEN, "GREEN"}, {Color::BLUE, "BLUE"}}});
constexpr auto& s2 = enum_entries<Numbers>();
REQUIRE(s2 == std::array<std::pair<Numbers, std::string_view>, 3>{{{Numbers::one, "one"}, {Numbers::two, "two"}, {Numbers::three, "three"}}});
@ -447,7 +457,7 @@ TEST_CASE("ostream_operators") {
REQUIRE(ss.str() == name);
};
test_ostream(std::make_optional(Color::RED), "RED");
test_ostream(std::make_optional(Color::RED), "red");
test_ostream(Color::GREEN, "GREEN");
test_ostream(Color::BLUE, "BLUE");
test_ostream(static_cast<Color>(0), "0");
@ -619,45 +629,45 @@ TEST_CASE("extrema") {
REQUIRE_FALSE(magic_enum::enum_contains<BadColor>(BadColor::NONE));
SECTION("min") {
REQUIRE(magic_enum::enum_range<BadColor>::min == MAGIC_ENUM_RANGE_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::min_v<BadColor> == 0);
REQUIRE(magic_enum::enum_range<Color>::min == MAGIC_ENUM_RANGE_MIN);
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::min_v<Color> == -12);
REQUIRE(magic_enum::enum_range<Numbers>::min == MAGIC_ENUM_RANGE_MIN);
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::min_v<Numbers> == 1);
REQUIRE(magic_enum::enum_range<Directions>::min == MAGIC_ENUM_RANGE_MIN);
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::min_v<Directions> == -120);
REQUIRE(magic_enum::enum_range<number>::min == 100);
REQUIRE(magic_enum::customize::enum_range<number>::min == 100);
REQUIRE(magic_enum::detail::reflected_min_v<number> == 100);
REQUIRE(magic_enum::detail::min_v<number> == 100);
}
SECTION("max") {
REQUIRE(magic_enum::enum_range<BadColor>::max == MAGIC_ENUM_RANGE_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::max_v<BadColor> == 2);
REQUIRE(magic_enum::enum_range<Color>::max == MAGIC_ENUM_RANGE_MAX);
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::max_v<Color> == 15);
REQUIRE(magic_enum::enum_range<Numbers>::max == MAGIC_ENUM_RANGE_MAX);
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::max_v<Numbers> == 3);
REQUIRE(magic_enum::enum_range<Directions>::max == MAGIC_ENUM_RANGE_MAX);
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::max_v<Directions> == 120);
REQUIRE(magic_enum::enum_range<number>::max == 300);
REQUIRE(magic_enum::customize::enum_range<number>::max == 300);
REQUIRE(magic_enum::detail::reflected_max_v<number> == 300);
REQUIRE(magic_enum::detail::max_v<number> == 300);
}

View file

@ -69,7 +69,7 @@ enum number : unsigned long {
#endif
};
namespace magic_enum {
namespace magic_enum::customize {
template <>
struct enum_range<number> {
static constexpr int min = 100;