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

new customize (#166)

This commit is contained in:
Daniil Goncharov 2022-03-18 13:58:07 +04:00 committed by GitHub
parent 84efdbd2bf
commit 60de6bff8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 48 deletions

View file

@ -9,7 +9,6 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
config: config:
- { os: windows-2016, vs: "Visual Studio 2017" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2016-Readme.md#visual-studio-enterprise-2017
- { os: windows-2019, vs: "Visual Studio 2019" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019 - { os: windows-2019, vs: "Visual Studio 2019" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019
- { os: windows-2022, vs: "Visual Studio 2022" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022 - { os: windows-2022, vs: "Visual Studio 2022" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022
build: [Debug, Release] build: [Debug, Release]

View file

@ -259,7 +259,7 @@ enum class Color { RED = 2, BLUE = 4, GREEN = 8 };
## Compiler compatibility ## Compiler compatibility
* Clang/LLVM >= 5 * Clang/LLVM >= 6
* MSVC++ >= 14.11 / Visual Studio >= 2017 * MSVC++ >= 14.11 / Visual Studio >= 2017
* Xcode >= 10 * Xcode >= 10
* GCC >= 9 * GCC >= 9

View file

@ -29,16 +29,16 @@ enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 };
// Сustom definitions of names for enum. // Сustom definitions of names for enum.
// Specialization of `enum_name` must be injected in `namespace magic_enum::customize`. // Specialization of `enum_name` must be injected in `namespace magic_enum::customize`.
template <> template <>
constexpr std::string_view magic_enum::customize::enum_name<Color>(Color value) noexcept { constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<Color>(Color value) noexcept {
switch (value) { switch (value) {
case Color::RED: case Color::RED:
return "the red color"; return "the red color";
case Color::BLUE: case Color::BLUE:
return "The BLUE"; return "The BLUE";
case Color::GREEN: case Color::GREEN:
return {}; // Empty string for default value. return invalid_tag;
} }
return {}; // Empty string for unknow value. return default_tag;
} }
enum class Numbers : int { One, Two, Three }; enum class Numbers : int { One, Two, Three };
@ -46,26 +46,26 @@ enum class Numbers : int { One, Two, Three };
// Сustom definitions of names for enum. // Сustom definitions of names for enum.
// Specialization of `enum_name` must be injected in `namespace magic_enum::customize`. // Specialization of `enum_name` must be injected in `namespace magic_enum::customize`.
template <> template <>
constexpr std::string_view magic_enum::customize::enum_name<Numbers>(Numbers value) noexcept { constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<Numbers>(Numbers value) noexcept {
switch (value) { switch (value) {
case Numbers::One: case Numbers::One:
return "the one"; return "the one";
default: default:
return {}; // Empty string for default or unknow value. return default_tag;
} }
} }
int main() { int main() {
std::cout << magic_enum::enum_name(Color::RED) << std::endl; // the red color 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::BLUE) << std::endl; // 'The BLUE'
std::cout << magic_enum::enum_name(Color::GREEN) << std::endl; // GREEN std::cout << magic_enum::enum_name(Color::GREEN) << std::endl; // ''
std::cout << std::boolalpha; 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_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::One) << std::endl; // 'the one'
std::cout << magic_enum::enum_name(Numbers::Two) << std::endl; // Two std::cout << magic_enum::enum_name(Numbers::Two) << std::endl; // 'Two'
std::cout << magic_enum::enum_name(Numbers::Three) << std::endl; // Three std::cout << magic_enum::enum_name(Numbers::Three) << std::endl; // 'Three'
return 0; return 0;
} }

View file

@ -44,6 +44,7 @@
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <variant>
#if defined(MAGIC_ENUM_CONFIG_FILE) #if defined(MAGIC_ENUM_CONFIG_FILE)
#include MAGIC_ENUM_CONFIG_FILE #include MAGIC_ENUM_CONFIG_FILE
@ -134,10 +135,28 @@ struct enum_range {
static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits<std::uint16_t>::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX."); static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits<std::uint16_t>::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX.");
namespace detail {
enum class default_customize_tag {};
enum class invalid_customize_tag {};
} // namespace magic_enum::customize::detail
using customize_t = std::variant<string_view, detail::default_customize_tag, detail::invalid_customize_tag>;
// Default customize.
inline constexpr auto default_tag = detail::default_customize_tag{};
// Invalid customize.
inline constexpr auto invalid_tag = detail::invalid_customize_tag{};
// If need custom names for enum, add specialization enum_name for necessary enum type. // If need custom names for enum, add specialization enum_name for necessary enum type.
template <typename E> template <typename E>
constexpr string_view enum_name(E) noexcept { constexpr customize_t enum_name(E) noexcept {
return {}; return default_tag;
}
// If need custom type name for enum, add specialization enum_type_name for necessary enum type.
template <typename E>
constexpr customize_t enum_type_name() noexcept {
return default_tag;
} }
} // namespace magic_enum::customize } // namespace magic_enum::customize
@ -196,6 +215,8 @@ class static_string {
template <> template <>
class static_string<0> { class static_string<0> {
public: public:
constexpr explicit static_string() = default;
constexpr explicit static_string(string_view) noexcept {} constexpr explicit static_string(string_view) noexcept {}
constexpr const char* data() const noexcept { return nullptr; } constexpr const char* data() const noexcept { return nullptr; }
@ -343,7 +364,13 @@ template <typename E>
constexpr auto n() noexcept { constexpr auto n() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");
if constexpr (supported<E>::value) { [[maybe_unused]] constexpr auto custom = customize::enum_type_name<E>();
static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
if constexpr (custom.index() == 0) {
constexpr auto name = std::get<string_view>(custom);
static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
return static_string<name.size()>{name};
} else if constexpr (custom.index() == 1 && supported<E>::value) {
#if defined(__clang__) || defined(__GNUC__) #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) #elif defined(_MSC_VER)
@ -353,7 +380,7 @@ constexpr auto n() noexcept {
#endif #endif
return static_string<name.size()>{name}; return static_string<name.size()>{name};
} else { } else {
return string_view{}; // Unsupported compiler. return static_string<0>{}; // Unsupported compiler or Invalid customize.
} }
} }
@ -363,23 +390,24 @@ inline constexpr auto type_name_v = n<E>();
template <typename E, E V> template <typename E, E V>
constexpr auto n() noexcept { constexpr auto n() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");
[[maybe_unused]] constexpr auto custom_name = customize::enum_name<E>(V);
if constexpr (custom_name.empty()) { [[maybe_unused]] constexpr auto custom = customize::enum_name<E>(V);
if constexpr (supported<E>::value) { static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
if constexpr (custom.index() == 0) {
constexpr auto name = std::get<string_view>(custom);
static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
return static_string<name.size()>{name};
} else if constexpr (custom.index() == 1 && supported<E>::value) {
#if defined(__clang__) || defined(__GNUC__) #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) #elif defined(_MSC_VER)
constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});
#else #else
constexpr auto name = string_view{}; constexpr auto name = string_view{};
#endif #endif
return static_string<name.size()>{name}; return static_string<name.size()>{name};
} else {
return string_view{}; // Unsupported compiler.
}
} else { } else {
return static_string<custom_name.size()>{custom_name}; return static_string<0>{}; // Unsupported compiler or Invalid customize.
} }
} }
@ -943,7 +971,7 @@ template <auto V>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, string_view> { [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, string_view> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
if (const auto index = enum_index(value); index.has_value()) { if (const auto index = enum_index(value)) {
return detail::names_v<D>[*index]; return detail::names_v<D>[*index];
} }
return {}; return {};
@ -1089,7 +1117,7 @@ template <typename E, typename BinaryPredicate = std::equal_to<char>>
template <auto V> template <auto V>
[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_enum_t<decltype(V), std::size_t> { [[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_enum_t<decltype(V), std::size_t> {
constexpr auto index = enum_index<std::decay_t<decltype(V)>>(V); constexpr auto index = enum_index<std::decay_t<decltype(V)>>(V);
static_assert(index.has_value(), "magic_enum::enum_index enum value does not have a index."); static_assert(index, "magic_enum::enum_index enum value does not have a index.");
return *index; return *index;
} }
@ -1100,13 +1128,13 @@ template <typename E>
using D = std::decay_t<E>; using D = std::decay_t<E>;
using U = underlying_type_t<D>; using U = underlying_type_t<D>;
return enum_cast<D>(static_cast<U>(value)).has_value(); return static_cast<bool>(enum_cast<D>(static_cast<U>(value)));
} }
// Checks whether enum contains enumerator with such integer value. // Checks whether enum contains enumerator with such integer value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, bool> {
return enum_cast<std::decay_t<E>>(value).has_value(); return static_cast<bool>(enum_cast<std::decay_t<E>>(value));
} }
// Checks whether enum contains enumerator with such name. // Checks whether enum contains enumerator with such name.
@ -1114,15 +1142,15 @@ template <typename E, typename BinaryPredicate = std::equal_to<char>>
[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, bool> {
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_contains requires bool(char, char) invocable predicate."); static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_contains requires bool(char, char) invocable predicate.");
return enum_cast<std::decay_t<E>>(value, std::move_if_noexcept(p)).has_value(); return static_cast<bool>(enum_cast<std::decay_t<E>>(value, std::move_if_noexcept(p)));
} }
namespace detail { namespace detail {
template <typename E> template <typename E>
constexpr optional<std::uintmax_t> fuse_one_enum(optional<std::uintmax_t> hash, E value) noexcept { constexpr optional<std::uintmax_t> fuse_one_enum(optional<std::uintmax_t> hash, E value) noexcept {
if (hash.has_value()) { if (hash) {
if (const auto index = enum_index(value); index.has_value()) { if (const auto index = enum_index(value)) {
return (*hash << log2(enum_count<E>() + 1)) | *index; return (*hash << log2(enum_count<E>() + 1)) | *index;
} }
} }
@ -1143,7 +1171,7 @@ template <typename... Es>
constexpr auto typesafe_fuse_enum(Es... values) noexcept { constexpr auto typesafe_fuse_enum(Es... values) noexcept {
enum class enum_fuse_t : std::uintmax_t; enum class enum_fuse_t : std::uintmax_t;
const auto fuse = fuse_enum(values...); const auto fuse = fuse_enum(values...);
if (fuse.has_value()) { if (fuse) {
return optional<enum_fuse_t>{static_cast<enum_fuse_t>(*fuse)}; return optional<enum_fuse_t>{static_cast<enum_fuse_t>(*fuse)};
} }
return optional<enum_fuse_t>{}; return optional<enum_fuse_t>{};
@ -1162,7 +1190,7 @@ template <typename... Es>
#else #else
const auto fuse = detail::typesafe_fuse_enum<std::decay_t<Es>...>(values...); const auto fuse = detail::typesafe_fuse_enum<std::decay_t<Es>...>(values...);
#endif #endif
return assert(fuse.has_value()), fuse; return assert(fuse), fuse;
} }
namespace ostream_operators { namespace ostream_operators {
@ -1185,7 +1213,7 @@ std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& o
template <typename Char, typename Traits, typename E, detail::enable_if_enum_t<E, int> = 0> template <typename Char, typename Traits, typename E, detail::enable_if_enum_t<E, int> = 0>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) { std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) {
return value.has_value() ? (os << *value) : os; return value ? (os << *value) : os;
} }
} // namespace magic_enum::ostream_operators } // namespace magic_enum::ostream_operators

View file

@ -35,6 +35,15 @@
#include <sstream> #include <sstream>
enum class Color { RED = -12, GREEN = 7, BLUE = 15 }; enum class Color { RED = -12, GREEN = 7, BLUE = 15 };
template <>
constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<Color>(Color value) noexcept {
switch (value) {
case Color::RED:
return "red";
default:
return default_tag;
}
}
enum class Numbers : int { one = 1, two, three, many = 127 }; enum class Numbers : int { one = 1, two, three, many = 127 };
@ -94,16 +103,6 @@ struct magic_enum::customize::enum_range<Binary> {
static constexpr int max = 64; static constexpr int max = 64;
}; };
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; using namespace magic_enum;
static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");