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:
parent
84efdbd2bf
commit
60de6bff8c
5 changed files with 74 additions and 48 deletions
1
.github/workflows/windows.yml
vendored
1
.github/workflows/windows.yml
vendored
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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).");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue