From ddc79d8d3e50625b41bd0a74a6767babdf327287 Mon Sep 17 00:00:00 2001 From: Neargye Date: Sat, 1 Sep 2018 18:27:49 +0500 Subject: [PATCH] add nameof enum --- README.md | 2 ++ example/example.cpp | 8 ++++-- include/nameof.hpp | 70 ++++++++++++++++++++++++++++++++++++++++----- test/test.cpp | 36 +++++++++++++++++++++++ 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5db9013..067ad42 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ NAMEOF(SomeMethod) -> "SomeMethod" NAMEOF_FULL(SomeMethod) -> "SomeMethod4" // Name of enum NAMEOF(SomeEnum::RED) -> "RED" +SomeEnum e = SomeEnum::RED; +NAMEOF_ENUM(e) -> "RED" // Name of type NAMEOF_TYPE(SomeEnum::RED) -> "SomeEnum" NAMEOF_TYPE_T(int) -> "int" diff --git a/example/example.cpp b/example/example.cpp index b4fb5a4..82e3c3c 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -86,10 +86,12 @@ int main() { constexpr auto constexpr_work_fine = NAMEOF(structvar); static_assert("structvar" == constexpr_work_fine, ""); - std::cout << SomeMethod4(structvar) << std::endl; // SomeMethod4(SomeStruct value) - // Enum name. std::cout << NAMEOF(Color::RED) << std::endl; // RED + std::cout << NAMEOF_ENUM(Color::RED) << std::endl; // RED + auto color = Color::RED; + std::cout << NAMEOF(color) << std::endl; // color + std::cout << NAMEOF_ENUM(color) << std::endl; // RED // Variable name. std::cout << NAMEOF(structvar) << std::endl; // structvar @@ -129,6 +131,8 @@ int main() { std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // structvar.somefield std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // &SomeStruct::SomeMethod1 + std::cout << SomeMethod4(structvar) << std::endl; // SomeMethod4(SomeStruct value) + const auto div = [](int x, int y) -> int { if (y == 0) { throw std::invalid_argument(std::string(NAMEOF(y)).append(" should not be zero!")); diff --git a/include/nameof.hpp b/include/nameof.hpp index 939296c..2389e04 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -297,12 +297,12 @@ constexpr cstring RemovePrefix(cstring name, const std::size_t p = 0) { : RemovePrefix(name, p + 1); } -constexpr cstring NameofPrettyImpl_(cstring name, std::size_t s, bool with_suffix) { +constexpr cstring NameofPrettyImpl1(cstring name, std::size_t s, bool with_suffix) { return RemovePrefix(name.remove_suffix(s)).add_suffix(with_suffix ? s : 0); } constexpr cstring NameofPrettyImpl(cstring name, bool with_suffix) { - return NameofPrettyImpl_(name, FindSuffix(name), with_suffix); + return NameofPrettyImpl1(name, FindSuffix(name), with_suffix); } constexpr cstring NameofPretty(cstring name, bool with_suffix) { @@ -346,6 +346,55 @@ constexpr cstring NameofTypePretty(const char* str, std::size_t size, std::size_ } #endif +template +constexpr int NameofEnumImpl1() { +#if defined(__clang__) + return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::NameofEnumImpl1() [T = ") - sizeof("]") + 1; +#elif defined(__GNUC__) + return sizeof(__PRETTY_FUNCTION__) - sizeof("constexpr int nameof::detail::NameofEnumImpl1() [with T = ") - sizeof("]") + 1; +#elif defined(_MSC_VER) + return sizeof(__FUNCSIG__) - sizeof("int __cdecl nameof::detail::NameofEnumImpl1<") - sizeof(">(void)") + 1; +#else + return 0; +#endif +} + +template +constexpr nameof::cstring NameofEnumImpl2() { +#if defined(__clang__) + return {__PRETTY_FUNCTION__, + sizeof(__PRETTY_FUNCTION__) - 1, + sizeof("nameof::cstring nameof::detail::NameofEnumImpl2() [T = ") + NameofEnumImpl1() + sizeof("; V = ") - 2, + sizeof("]") - 1}; +#elif defined(__GNUC__) + return {__PRETTY_FUNCTION__, + sizeof(__PRETTY_FUNCTION__) - 1, + sizeof("constexpr nameof::cstring nameof::detail::NameofEnumImpl2() [with T = ") + NameofEnumImpl1() + sizeof("; T V = ") - 2, + sizeof("]") - 1}; +#elif defined(_MSC_VER) + return {__FUNCSIG__, + sizeof(__FUNCSIG__) - 1, + sizeof("class nameof::cstring __cdecl nameof::detail::NameofEnumImpl2<") + NameofEnumImpl1(), + sizeof(">(void)") - 1}; +#else + return {}; +#endif +} + +template +struct NameofEnumImpl { + constexpr nameof::cstring operator()(T value) const noexcept { + return (static_cast(value) - I == 0) + ? NameofEnumImpl2() + : NameofEnumImpl{}(value); + } +}; + +template +struct NameofEnumImpl { + constexpr nameof::cstring operator()(T) const noexcept { return {}; } +}; + template NAMEOF_TYPE_CONSTEXPR cstring NameofType() { #if defined(__clang__) @@ -383,6 +432,12 @@ constexpr cstring Nameof(const char* name, std::size_t size, bool with_suffix = return detail::NameofPretty({name, size}, with_suffix); } +template ::value && std::is_enum::value>::type> +constexpr cstring NameofEnum(T value) { + return detail::NameofPretty(detail::NameofEnumImpl{}(value), false); +} + template NAMEOF_TYPE_CONSTEXPR cstring NameofType() { return true ? detail::NameofType>() : detail::NameofType>(); @@ -395,15 +450,16 @@ constexpr cstring NameofRaw(const char* name, std::size_t size) { } // namespace nameof -// Used to obtain the simple (unqualified) string name of a variable, member, function, macros. +// Used to obtain the simple (unqualified) string name of a variable, member, function, enum, macros. #define NAMEOF(...) ::nameof::Nameof(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1, false) - -// Used to obtain the full string name of a variable, member, function, macros. +// Used to obtain the full string name of a variable, member, function, enum, macros. #define NAMEOF_FULL(...) ::nameof::Nameof(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1, true) - -// Used to obtain the raw string name of a variable, member, function, macros. +// Used to obtain the raw string name of a variable, member, function, enum, macros. #define NAMEOF_RAW(...) ::nameof::NameofRaw(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1) +// Used to obtain the simple (unqualified) string name of a enum variable. +#define NAMEOF_ENUM(...) ::nameof::NameofEnum(__VA_ARGS__) + // Used to obtain the string name of a type. #define NAMEOF_TYPE(...) ::nameof::NameofType() #define NAMEOF_TYPE_T(...) ::nameof::NameofType<__VA_ARGS__>() diff --git a/test/test.cpp b/test/test.cpp index 05912a9..3e2b513 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -70,6 +70,8 @@ struct Long { enum class Color { RED, GREEN, BLUE }; +enum Directions { Up, Down, Right, Left}; + SomeStruct struct_var; Long othervar; SomeStruct * ptr_s = &struct_var; @@ -78,6 +80,9 @@ SomeStruct & ref_s = struct_var; SomeClass class_var; const SomeClass volatile * ptr_c = nullptr; +const Color color = Color::RED; +const Directions directions = Directions::Right; + TEST_CASE("constexpr") { SECTION("NAMEOF") { // variable @@ -140,6 +145,17 @@ TEST_CASE("constexpr") { REQUIRE(cx6 == "__cplusplus"); } + SECTION("NAMEOF_ENUM") { + constexpr auto cx = NAMEOF_ENUM(color); +# if defined(__clang__) || defined(_MSC_VER) + static_assert(cx == "RED", ""); + REQUIRE(cx == "RED"); +# elif defined(__GNUC__) + //static_assert(cx == "(Color)0", ""); + REQUIRE(cx == "(Color)0"); +# endif + } + #if defined(NAMEOF_TYPE_HAS_CONSTEXPR) SECTION("NAMEOF_TYPE") { constexpr auto cx = NAMEOF_TYPE(ptr_c); @@ -290,6 +306,22 @@ TEST_CASE("NAMEOF_RAW") { } } +TEST_CASE("NAMEOF_ENUM") { +# if defined(__clang__) || defined(_MSC_VER) + REQUIRE(NAMEOF_ENUM(Color::RED) == "RED"); + REQUIRE(NAMEOF_ENUM(color) == "RED"); + + REQUIRE(NAMEOF_ENUM(Directions::Right) == "Right"); + REQUIRE(NAMEOF_ENUM(directions) == "Right"); +# elif defined(__GNUC__) + REQUIRE(NAMEOF_ENUM(Color::RED) == "(Color)0"); + REQUIRE(NAMEOF_ENUM(color) == "0"); + + REQUIRE(NAMEOF_ENUM(Directions::Right) == "2"); + REQUIRE(NAMEOF_ENUM(directions) == "2"); +# endif +} + TEST_CASE("NAMEOF_TYPE") { #if defined(__clang__) REQUIRE(NAMEOF_TYPE(struct_var) == "SomeStruct"); @@ -397,6 +429,8 @@ TEST_CASE("Spaces and Tabs ignored") { REQUIRE(NAMEOF_FULL( struct_var ) == "struct_var"); REQUIRE(NAMEOF_RAW( struct_var ) == "struct_var"); + REQUIRE(NAMEOF_ENUM( color ) == "RED"); + REQUIRE(NAMEOF_TYPE( struct_var ) == "SomeStruct"); REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct"); } @@ -406,6 +440,8 @@ TEST_CASE("Spaces and Tabs ignored") { REQUIRE(NAMEOF_FULL( struct_var ) == "struct_var"); REQUIRE(NAMEOF_RAW( struct_var ) == "struct_var"); + REQUIRE(NAMEOF_ENUM( color ) == "RED"); + REQUIRE(NAMEOF_TYPE( struct_var ) == "SomeStruct"); REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct"); }