From ea58b9d963be2a358d1dfa672d90a305756f2df6 Mon Sep 17 00:00:00 2001 From: Neargye Date: Mon, 6 Aug 2018 16:01:40 +0500 Subject: [PATCH] clean-up --- example/example.cpp | 2 +- include/nameof.hpp | 126 +++++++++++++++++++------------------------- test/test.cpp | 48 +++++++++++------ 3 files changed, 87 insertions(+), 89 deletions(-) diff --git a/example/example.cpp b/example/example.cpp index 1fc6091..4cdd35d 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -121,7 +121,7 @@ int main() { // Type full name. std::cout << NAMEOF_TYPE_RAW(othervar.ll) << std::endl; // Long::LL - std::cout << NAMEOF_TYPE_RAW(std::declval>()) << std::endl; // SomeClass&& + std::cout << NAMEOF_TYPE_RAW(std::declval>()) << std::endl; // const SomeClass&& // Raw name. std::cout << NAMEOF_RAW(volatile const int) << std::endl; // volatile const int diff --git a/include/nameof.hpp b/include/nameof.hpp index 33d21c8..fa1e7d7 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -51,9 +51,12 @@ struct identity { template struct remove_all_pointers : std::conditional::value, - remove_all_pointers::type>, + remove_all_pointers::type>::type>, identity>::type {}; +template +using Decay = std::remove_reference::type>::type>; + // STD like compile-time string. class cstring final { const char* str_; @@ -150,51 +153,48 @@ class cstring final { }; inline constexpr bool IsLexeme(char s) noexcept { - return !((s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || - (s >= 'A' && s <= 'Z') || s == '_'); + return !((s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || s == '_'); } -inline constexpr cstring NameofBase(const char* name, std::size_t length) noexcept { - for (std::size_t i = length; i > 0; --i) { - if (IsLexeme(name[i - 1])) { - return {&name[i], length - i}; - } - } - - return {name, length}; -} - -inline constexpr cstring NameofTemplate(const char* name, std::size_t length, bool with_suffix) noexcept { +inline constexpr cstring NameofBase(const char* name, std::size_t length, bool with_suffix) noexcept { std::size_t p = 0; - for (std::size_t i = length, h = 0; i > 0; --i) { - if (h == 0 && (name[i - 1] == '&' || name[i - 1] == '*')) { - ++p; - continue; - } + if(IsLexeme(name[length - 1])) { + for (std::size_t i = length, h = 0; i > 0; --i) { + if (h == 0 && (IsLexeme(name[i - 1]) && name[i - 1] != '>')) { + ++p; + continue; + } - if (name[i - 1] == '>') { - ++h; - ++p; - continue; - } + if (name[i - 1] == '>') { + ++h; + ++p; + continue; + } - if (name[i - 1] == '<') { - --h; - ++p; - continue; - } + if (name[i - 1] == '<') { + --h; + ++p; + continue; + } - if (h != 0) { - ++p; - continue; - } + if (h != 0) { + ++p; + continue; + } - if (IsLexeme(name[i - 1]) && h == 0) { - return {&name[i], length - i - (with_suffix ? 0 : p)}; + if (h == 0) { + break; + } } } - return NameofBase(name, length - (with_suffix ? 0 : p)); + for (std::size_t i = length - p; i > 0; --i) { + if (IsLexeme(name[i - 1])) { + return {&name[i], length - i - (with_suffix ? 0 : p)}; + } + } + + return {name, length - (with_suffix ? 0 : p)}; } inline constexpr cstring NameofRaw(const char* name, std::size_t length) noexcept { @@ -206,11 +206,8 @@ inline constexpr cstring NameofRaw(const char* name, std::size_t length) noexcep template ::value && !std::is_void::value>::type> -inline constexpr detail::cstring Nameof(const T&, const char* name, std::size_t length) noexcept { - // TODO: conditional expression is constant - return (std::is_function::value || std::is_member_function_pointer::value) - ? detail::NameofTemplate(name, length, false) - : detail::NameofBase(name, length); +inline constexpr detail::cstring Nameof(const T&, const char* name, std::size_t length, bool with_suffix = false) noexcept { + return detail::NameofBase(name, length, with_suffix); } template -inline constexpr detail::cstring NameofType(bool full = false) noexcept { +inline constexpr detail::cstring NameofTypeRaw() noexcept { #if defined(__clang__) const auto function_name = __PRETTY_FUNCTION__; const auto total_length = sizeof(__PRETTY_FUNCTION__) - 1; - constexpr auto prefix_length = sizeof("nameof::detail::cstring nameof::NameofType(bool) [T = ") - 1; + constexpr auto prefix_length = sizeof("detail::cstring nameof::NameofTypeRaw() [T = ") - 1; constexpr auto suffix_length = sizeof("]") - 1; #elif defined(__GNUC__) const auto function_name = __PRETTY_FUNCTION__; const auto total_length = sizeof(__PRETTY_FUNCTION__) - 1; - constexpr auto prefix_length = sizeof("constexpr nameof::detail::cstring nameof::NameofType(bool) [T = ") - 1; + constexpr auto prefix_length = sizeof("constexpr nameof::detail::cstring nameof::NameofTypeRaw() [with T = ") - 1; constexpr auto suffix_length = sizeof("]") - 1; #elif defined(_MSC_VER) const auto function_name = __FUNCSIG__; const auto total_length = sizeof(__FUNCSIG__) - 1; - constexpr auto prefix_length = sizeof("class nameof::detail::cstring __cdecl nameof::NameofType<") - 1; - constexpr auto suffix_length = sizeof(">(bool) noexcept") - 1; + constexpr auto prefix_length = sizeof("class nameof::detail::cstring __cdecl nameof::NameofTypeRaw<") - 1; + constexpr auto suffix_length = sizeof(">(void) noexcept") - 1; #endif - const auto raw_type_name = detail::cstring{function_name + prefix_length, total_length - prefix_length - suffix_length}; + return {function_name + prefix_length, total_length - prefix_length - suffix_length}; +} - const auto type_name = full ? raw_type_name : detail::NameofTemplate(raw_type_name.begin(), raw_type_name.length(), false); - -#if defined(_MSC_VER) - - constexpr auto class_length = sizeof("class") - 1; - constexpr auto struct_length = sizeof("struct") - 1; - constexpr auto enum_length = sizeof("enum") - 1; - - using D = typename detail::remove_all_pointers::type>::type; - - if (!full && (std::is_class::value || std::is_enum::value) && (std::is_reference::value || std::is_pointer::value)) { - if (std::is_class::value && type_name[0] == 'c' && type_name[1] == 'l' && type_name[2] == 'a' && type_name[3] == 's' && type_name[4] == 's') { - return type_name.remove_prefix(class_length); - } else if (std::is_class::value && type_name[0] == 's' && type_name[1] == 't' && type_name[2] == 'r' && type_name[3] == 'u' && type_name[4] == 'c' && type_name[5] == 't') { - return type_name.remove_prefix(struct_length); - } else if(std::is_enum::value && type_name[0] == 'e' && type_name[1] == 'n' && type_name[2] == 'u' && type_name[3] == 'm') { - return type_name.remove_prefix(enum_length); - } - } - -#endif - - return type_name; +template ::type> +inline constexpr detail::cstring NameofType() noexcept { + const auto raw_type_name = NameofTypeRaw(); + return detail::NameofBase(raw_type_name.begin(), raw_type_name.length(), false); } } // namespace nameof @@ -278,8 +257,11 @@ inline constexpr detail::cstring NameofType(bool full = false) noexcept { // Used to obtain the simple (unqualified) string name of a variable, member, function. #define NAMEOF(name) ::nameof::Nameof(name, #name, (sizeof(#name) / sizeof(char)) - 1) +// Used to obtain the full string name of a variable, member, function. +#define NAMEOF_FULL(name) ::nameof::Nameof(name, #name, (sizeof(#name) / sizeof(char)) - 1, true) + // Used to obtain the simple (unqualified) string name of a type. -#define NAMEOF_TYPE(name) ::nameof::NameofType(false) +#define NAMEOF_TYPE(name) ::nameof::NameofType() // Used to obtain the raw string name of a type. -#define NAMEOF_TYPE_RAW(name) ::nameof::NameofType(true) +#define NAMEOF_TYPE_RAW(name) ::nameof::NameofTypeRaw() diff --git a/test/test.cpp b/test/test.cpp index 6261a23..37c721c 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -50,7 +50,7 @@ template class SomeClass { public: void SomeMethod5() const { - std::cout << nameof::NameofType(false) << std::endl; + std::cout << nameof::NameofType() << std::endl; } template @@ -75,7 +75,7 @@ Long othervar; SomeStruct& refvar = somevar; SomeStruct* ptrvar = &somevar; -#if (__cplusplus >= 201402L || (defined(_MSVC_LANG ) && _MSVC_LANG >= 201402L)) +#if 0 && (__cplusplus >= 201402L || (defined(_MSVC_LANG ) && _MSVC_LANG >= 201402L)) // Compile-time supported by C++14. TEST_CASE("constexpr") { SECTION("NAMEOF") { @@ -120,10 +120,10 @@ TEST_CASE("constexpr") { constexpr auto cx1 = NAMEOF_TYPE(a); static_assert(cx1 == "SomeClass", ""); - constexpr auto cx2 = nameof::NameofType>(false); + constexpr auto cx2 = nameof::NameofType>(); static_assert(cx2 == "SomeClass", ""); - constexpr auto cx3 = nameof::NameofType(false); + constexpr auto cx3 = nameof::NameofType(); static_assert(cx3 == "SomeClass", ""); } @@ -131,8 +131,8 @@ TEST_CASE("constexpr") { SomeClass a; constexpr auto cx1 = NAMEOF_TYPE_RAW(a); - constexpr auto cx2 = nameof::NameofType>(true); - constexpr auto cx3 = nameof::NameofType(true); + constexpr auto cx2 = nameof::NameofTypeRaw>(); + constexpr auto cx3 = nameof::NameofTypeRaw(); #if defined(_MSC_VER) static_assert(cx1 == "class SomeClass", ""); @@ -208,9 +208,6 @@ TEST_CASE("raw name") { REQUIRE(NAMEOF_RAW(&SomeStruct::SomeMethod1) == "&SomeStruct::SomeMethod1"); REQUIRE(NAMEOF_RAW(&SomeStruct::SomeMethod2) == "&SomeStruct::SomeMethod2"); REQUIRE(NAMEOF_RAW(SomeMethod3) == "SomeMethod3"); - REQUIRE(NAMEOF_RAW(SomeMethod4) == "SomeMethod4"); - REQUIRE(NAMEOF_RAW(&SomeClass::SomeMethod5) == "&SomeClass::SomeMethod5"); - REQUIRE(NAMEOF_RAW(&SomeClass::SomeMethod6) == "&SomeClass::SomeMethod6"); } SECTION("enum") { @@ -254,7 +251,19 @@ TEST_CASE("type raw name") { REQUIRE(NAMEOF_TYPE_RAW(Color::RED) == "enum Color"); REQUIRE(NAMEOF_TYPE_RAW(std::declval>()) == "const classSomeClass&&"); -#else +#elif defined(__clang__) + REQUIRE(NAMEOF_TYPE_RAW(somevar) == "SomeStruct"); + REQUIRE(NAMEOF_TYPE_RAW(ptrvar) == "SomeStruct *"); + REQUIRE(NAMEOF_TYPE_RAW(refvar) == "SomeStruct &"); + + REQUIRE(NAMEOF_TYPE_RAW(othervar) == "Long"); + REQUIRE(NAMEOF_TYPE_RAW(othervar.ll) == "Long::LL"); + REQUIRE(NAMEOF_TYPE_RAW(othervar.ll.field) == "int"); + + REQUIRE(NAMEOF_TYPE_RAW(Color::RED) == "Color"); + + REQUIRE(NAMEOF_TYPE_RAW(std::declval>()) == "const SomeClass&&"); +#elif defined(__GNUC__) REQUIRE(NAMEOF_TYPE_RAW(somevar) == "SomeStruct"); REQUIRE(NAMEOF_TYPE_RAW(ptrvar) == "SomeStruct*"); REQUIRE(NAMEOF_TYPE_RAW(refvar) == "SomeStruct&"); @@ -265,23 +274,30 @@ TEST_CASE("type raw name") { REQUIRE(NAMEOF_TYPE_RAW(Color::RED) == "Color"); - REQUIRE(NAMEOF_TYPE_RAW(std::declval>()) == "const SomeClass&&"); + REQUIRE(NAMEOF_TYPE_RAW(std::declval>()) == "const SomeClass &&"); #endif - } TEST_CASE("Spaces and Tabs ignored") { SECTION("Spaces") { REQUIRE(NAMEOF( somevar ) == "somevar"); REQUIRE(NAMEOF_RAW( somevar ) == "somevar"); - REQUIRE(NAMEOF_TYPE( int{} ) == "int"); - REQUIRE(NAMEOF_TYPE_RAW( int{} ) == "int"); + REQUIRE(NAMEOF_TYPE( somevar ) == "SomeStruct"); +#if defined(_MSC_VER) + REQUIRE(NAMEOF_TYPE_RAW( somevar ) == "struct SomeStruct"); +#else + REQUIRE(NAMEOF_TYPE_RAW( somevar ) == "SomeStruct"); +#endif } SECTION("Tabs") { REQUIRE(NAMEOF( somevar ) == "somevar"); REQUIRE(NAMEOF_RAW( somevar ) == "somevar"); - REQUIRE(NAMEOF_TYPE( int{} ) == "int"); - REQUIRE(NAMEOF_TYPE_RAW( int{} ) == "int"); + REQUIRE(NAMEOF_TYPE( somevar ) == "SomeStruct"); +#if defined(_MSC_VER) + REQUIRE(NAMEOF_TYPE_RAW( somevar ) == "struct SomeStruct"); +#else + REQUIRE(NAMEOF_TYPE_RAW( somevar ) == "SomeStruct"); +#endif } }