diff --git a/include/nameof.hpp b/include/nameof.hpp index df868a3..d053a43 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -45,6 +45,7 @@ #include #include #include +#include #if !defined(NAMEOF_USING_ALIAS_STRING) #include @@ -980,10 +981,8 @@ inline constexpr bool is_nameof_member_supported = detail::nameof_member_support inline constexpr bool is_nameof_enum_supported = detail::nameof_enum_supported::value; // Obtains simple (unqualified) name of enum variable. -template +template , typename U = std::underlying_type_t> [[nodiscard]] constexpr auto nameof_enum(E value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - using U = std::underlying_type_t; static_assert(detail::nameof_enum_supported::value, "nameof::nameof_enum unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); static_assert(detail::count_v > 0, "nameof::nameof_enum requires enum implementation and valid max and min."); @@ -1002,11 +1001,29 @@ template return {}; // Value out of range. } + +template , typename U = std::underlying_type_t> +[[nodiscard]] constexpr auto nameof_enum_or(E value) noexcept -> detail::enable_if_enum_t { + static_assert(detail::nameof_enum_supported::value, "nameof::nameof_enum unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); + static_assert(detail::count_v > 0, "nameof::nameof_enum requires enum implementation and valid max and min."); + + const bool valid = static_cast(value) >= static_cast(detail::min_v) && static_cast(value) <= static_cast(detail::max_v); + if (const auto i = static_cast(value) - detail::min_v; valid) { + if constexpr (detail::is_sparse_v) { + if (const auto idx = detail::indexes_v[i]; idx != detail::invalid_index_v) { + return detail::strings_v[idx]; + } + } else { + return detail::strings_v[static_cast(i)]; + } + } + + return std::to_string(static_cast(value)); // Value out of range. +} + // Obtains simple (unqualified) name of enum-flags variable. -template +template , typename U = std::underlying_type_t> [[nodiscard]] auto nameof_enum_flag(E value) -> detail::enable_if_enum_t { - using D = std::decay_t; - using U = std::underlying_type_t; static_assert(detail::nameof_enum_supported::value, "nameof::nameof_enum_flag unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); static_assert(detail::count_v > 0, "nameof::nameof_enum_flag requires enum-flags implementation."); constexpr auto size = detail::is_sparse_v ? detail::count_v : detail::range_size_v; @@ -1038,9 +1055,8 @@ template // Obtains simple (unqualified) name of static storage enum variable. // This version is much lighter on the compile times and is not restricted to the enum_range limitation. -template +template > [[nodiscard]] constexpr auto nameof_enum() noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; static_assert(detail::nameof_enum_supported::value, "nameof::nameof_enum unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); constexpr string_view name = detail::enum_name_v; static_assert(name.size() > 0, "Enum value does not have a name."); @@ -1049,10 +1065,9 @@ template } // Obtains name of type, reference and cv-qualifiers are ignored. -template +template >> [[nodiscard]] constexpr string_view nameof_type() noexcept { static_assert(detail::nameof_type_supported::value, "nameof::nameof_type unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); - using U = detail::identity>; constexpr string_view name = detail::type_name_v; static_assert(name.size() > 0, "Type does not have a name."); @@ -1060,10 +1075,9 @@ template } // Obtains full name of type, with reference and cv-qualifiers. -template +template > [[nodiscard]] constexpr string_view nameof_full_type() noexcept { static_assert(detail::nameof_type_supported::value, "nameof::nameof_type unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); - using U = detail::identity; constexpr string_view name = detail::type_name_v; static_assert(name.size() > 0, "Type does not have a full name."); @@ -1071,10 +1085,9 @@ template } // Obtains short name of type. -template +template >> [[nodiscard]] constexpr auto nameof_short_type() noexcept -> detail::enable_if_has_short_name_t { static_assert(detail::nameof_type_supported::value, "nameof::nameof_type unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); - using U = detail::identity>; constexpr string_view name = detail::pretty_name(detail::type_name_v); static_assert(name.size() > 0, "Type does not have a short name."); @@ -1123,6 +1136,9 @@ template // Obtains name of enum variable. #define NAMEOF_ENUM(...) ::nameof::nameof_enum<::std::decay_t>(__VA_ARGS__) +// Obtains name of enum variable or stringified number if out of range. +#define NAMEOF_ENUM_OR(...) ::nameof::nameof_enum_or<::std::decay_t>(__VA_ARGS) + // Obtains name of static storage enum variable. // This version is much lighter on the compile times and is not restricted to the enum_range limitation. #define NAMEOF_ENUM_CONST(...) ::nameof::nameof_enum<__VA_ARGS__>() diff --git a/test/test.cpp b/test/test.cpp index a7d2d0a..76238db 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -79,6 +79,8 @@ struct Long { enum class Color { RED = -12, GREEN = 7, BLUE = 15 }; +enum class OutOfRange { too_low = NAMEOF_ENUM_RANGE_MIN - 1, required_to_work = 0, too_high = NAMEOF_ENUM_RANGE_MAX + 1 }; + enum class Numbers : int { one = 1, two, three, many = 127 }; enum Directions { Up = 85, Down = -42, Right = 120, Left = -120 }; @@ -287,6 +289,17 @@ TEST_CASE("nameof_enum") { NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast(0)).empty()); } + SECTION("automatic storage _or") { + constexpr OutOfRange low = OutOfRange::too_low; + constexpr OutOfRange high = OutOfRange::too_high; + auto low_name = nameof::nameof_enum_or(low); + auto high_name = nameof::nameof_enum_or(high); + constexpr OutOfRange oor[] = {OutOfRange::too_high, OutOfRange::too_low}; + REQUIRE(low_name == "-121"); + REQUIRE(high_name == "121"); + REQUIRE(nameof::nameof_enum_or(oor[0]) == "121"); + } + SECTION("static storage") { constexpr Color cr = Color::RED; constexpr auto cr_name = nameof::nameof_enum();