From 6a976ef47249194fec36456c87a76fbbe877adfd Mon Sep 17 00:00:00 2001 From: neargye Date: Sun, 15 Sep 2019 03:19:34 +0500 Subject: [PATCH] less bin size nameof & nameof_type --- example/example.cpp | 30 +++---- include/nameof.hpp | 207 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 179 insertions(+), 58 deletions(-) diff --git a/example/example.cpp b/example/example.cpp index dc0249f..8433ccd 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -27,18 +27,6 @@ #include #include -std::string operator+(std::string_view lhs, std::string_view rhs) { - return std::string{lhs.data(), lhs.length()}.append(rhs.data(), rhs.length()); -} - -constexpr long double operator"" _deg(long double deg) { - return deg * 3.141592 / 180.0; -} - -std::string operator"" _string(const char* str, std::size_t) { - return std::string{str}; -} - struct SomeStruct { int somefield = 0; @@ -53,7 +41,18 @@ void SomeMethod3() { template std::string SomeMethod4(U value) { - return NAMEOF(SomeMethod4) + "<" + NAMEOF_TYPE(T) + ", " + NAMEOF_TYPE(U) + ">(" + NAMEOF_TYPE(U) + " " + NAMEOF(value) + ")"; + auto function_name = std::string{NAMEOF(SomeMethod4)} + .append("<") + .append(NAMEOF_TYPE(T)) + .append(", ") + .append(NAMEOF_TYPE(U)) + .append(">(") + .append(NAMEOF_TYPE(U)) + .append(" ") + .append(NAMEOF(value).data()) + .append(")"); + + return function_name; } template @@ -89,11 +88,13 @@ int main() { constexpr auto name = NAMEOF(structvar); static_assert("structvar" == name); +#if defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) // Nameof enum variable. auto color = Color::RED; std::cout << nameof::nameof_enum(color) << std::endl; // 'RED' std::cout << NAMEOF_ENUM(color) << std::endl; // 'RED' std::cout << nameof::nameof_enum() << std::endl; // 'GREEN' +#endif // Nameof. std::cout << NAMEOF(structvar) << std::endl; // 'structvar' @@ -129,7 +130,6 @@ int main() { // Nameof macro. std::cout << NAMEOF(__LINE__) << std::endl; // '__LINE__' - std::cout << NAMEOF(NAMEOF(structvar)) << std::endl; // 'NAMEOF' // Nameof raw. std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // 'structvar.somefield' @@ -141,7 +141,7 @@ int main() { auto div = [](int x, int y) -> int { if (y == 0) { - throw std::invalid_argument(NAMEOF(y) + " should not be zero!"); + throw std::invalid_argument(std::string{NAMEOF(y)} + " should not be zero!"); } return x / y; }; diff --git a/include/nameof.hpp b/include/nameof.hpp index 1eec9a6..b98e2ac 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -100,35 +101,146 @@ struct nameof_enum_supported final #endif template -struct static_string final { - constexpr static_string(std::string_view str) noexcept : static_string(str, std::make_index_sequence{}) {} +struct [[nodiscard]] static_string final { + constexpr static_string(std::string_view str) noexcept : static_string{str, std::make_index_sequence{}} {} - constexpr operator std::string_view() const noexcept { return {chars.data(), chars.size()}; } + [[nodiscard]] constexpr auto data() const noexcept { return chars.data(); } + + [[nodiscard]] constexpr auto size() const noexcept { return N; } + + [[nodiscard]] constexpr auto begin() const noexcept { return data(); } + + [[nodiscard]] constexpr auto end() const noexcept { return data() + size(); } + + [[nodiscard]] constexpr auto cbegin() const noexcept { return begin(); } + + [[nodiscard]] constexpr auto cend() const noexcept { return end(); } + + [[nodiscard]] constexpr auto rbegin() const noexcept { return std::reverse_iterator{end()}; } + + [[nodiscard]] constexpr auto rend() const noexcept { return std::reverse_iterator{begin()}; } + + [[nodiscard]] constexpr auto crbegin() const noexcept { return rbegin(); } + + [[nodiscard]] constexpr auto crend() const noexcept { return rend(); } + + [[nodiscard]] constexpr auto operator[](std::size_t i) const noexcept { return chars[i]; } + + [[nodiscard]] constexpr auto at(std::size_t i) const { return chars.at(i); } + + [[nodiscard]] constexpr auto front() const noexcept { return chars[0]; } + + [[nodiscard]] constexpr auto back() const noexcept { return chars[N]; } + + [[nodiscard]] constexpr auto length() const noexcept { return size(); } + + [[nodiscard]] constexpr auto empty() const noexcept { return false; } + + [[nodiscard]] constexpr auto compare(std::string_view str) const noexcept { + return std::string_view{data(), size()}.compare(str); + } + + [[nodiscard]] constexpr operator std::string_view() const noexcept { return {data(), size()}; } private: template - constexpr static_string(std::string_view str, std::index_sequence) noexcept : chars{{str[I]...}} {} + constexpr static_string(std::string_view str, std::index_sequence) noexcept : chars{{str[I]..., '\0'}} {} - const std::array chars; + const std::array chars; }; template <> struct static_string<0> final { constexpr static_string(std::string_view) noexcept {} + constexpr const char* data() const noexcept { return nullptr; } + + constexpr std::size_t size() const noexcept { return 0; } + + [[nodiscard]] constexpr int compare(std::string_view str) const noexcept { + return std::string_view{}.compare(str); + } + constexpr operator std::string_view() const noexcept { return {}; } }; +template +[[nodiscard]] constexpr bool operator==(const static_string& lhs, std::string_view rhs) noexcept { + return lhs.compare(rhs) == 0; +} + +template +[[nodiscard]] constexpr bool operator==(std::string_view lhs, const static_string& rhs) noexcept { + return lhs.compare(rhs) == 0; +} + +template +[[nodiscard]] constexpr bool operator!=(const static_string& lhs, std::string_view rhs) noexcept { + return lhs.compare(rhs) != 0; +} + +template +[[nodiscard]] constexpr bool operator!=(std::string_view lhs, const static_string& rhs) noexcept { + return lhs.compare(rhs) != 0; +} + +template +[[nodiscard]] constexpr bool operator>(const static_string& lhs, std::string_view rhs) noexcept { + return lhs.compare(rhs) > 0; +} + +template +[[nodiscard]] constexpr bool operator>(std::string_view lhs, const static_string& rhs) noexcept { + return lhs.compare(rhs) > 0; +} + +template +[[nodiscard]] constexpr bool operator>=(const static_string& lhs, std::string_view rhs) noexcept { + return lhs.compare(rhs) >= 0; +} + +template +[[nodiscard]] constexpr bool operator>=(std::string_view lhs, const static_string& rhs) noexcept { + return lhs.compare(rhs) >= 0; +} + +template +[[nodiscard]] constexpr bool operator<(const static_string& lhs, std::string_view rhs) noexcept { + return lhs.compare(rhs) < 0; +} + +template +[[nodiscard]] constexpr bool operator<(std::string_view lhs, const static_string& rhs) noexcept { + return lhs.compare(rhs) < 0; +} + +template +[[nodiscard]] constexpr bool operator<=(const static_string& lhs, std::string_view rhs) noexcept { + return lhs.compare(rhs) <= 0; +} + +template +[[nodiscard]] constexpr bool operator<=(std::string_view lhs, const static_string& rhs) noexcept { + return lhs.compare(rhs) <= 0; +} + +template +std::basic_ostream& operator<<(std::basic_ostream& os, const static_string& srt) { + for (auto c : std::string_view{srt}) { + os.put(c); + } + + return os; +} + template using remove_cvref_t = std::remove_cv_t>; template using enable_if_enum_t = std::enable_if_t, R>; -template -[[nodiscard]] constexpr std::string_view nameof(std::string_view name, bool remove_template_suffix = true) noexcept { - static_assert(std::is_void_v, "nameof::detail::nameof requires void type."); - if (name.size() >= 1 && (name.front() == '"' || name.front() == '\'')) { +constexpr std::string_view pretty_name(std::string_view name, bool remove_template_suffix = true) noexcept { + if (name.size() >= 1 && (name[0] == '"' || name[0] == '\'')) { return {}; // Narrow multibyte string literal. } else if (name.size() >= 2 && name[0] == 'R' && (name[1] == '"' || name[1] == '\'')) { return {}; // Raw string literal. @@ -140,7 +252,7 @@ template return {}; // UTF-16 encoded string literal. } else if (name.size() >= 3 && name[0] == 'u' && name[1] == '8' && (name[2] == '"' || name[2] == '\'')) { return {}; // UTF-8 encoded string literal. - } else if (name.size() >= 1 && (name.front() >= '0' && name.front() <= '9')) { + } else if (name.size() >= 1 && (name[0] >= '0' && name[0] <= '9')) { return {}; // Invalid name. } @@ -206,20 +318,13 @@ template return {}; // Invalid name. } -template -[[nodiscard]] constexpr std::string_view nameof_raw(std::string_view name) noexcept { - static_assert(std::is_void_v, "nameof::detail::nameof_raw requires void type."); - - return name; -} - template constexpr auto n() noexcept { - static_assert(std::is_enum_v, "nameof::detail::nameof_enum requires enum type."); + static_assert(std::is_enum_v, "nameof::detail::n requires enum type."); #if defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 9 - constexpr auto name = nameof({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); + constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); #elif defined(_MSC_VER) - constexpr auto name = nameof({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); + constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); #else static_assert(nameof_enum_supported::value, "nameof::nameof_enum: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); return std::string_view{}; // Unsupported compiler. @@ -248,23 +353,16 @@ constexpr auto n() noexcept { constexpr std::string_view name{__PRETTY_FUNCTION__ + 46, sizeof(__PRETTY_FUNCTION__) - 49}; #elif defined(_MSC_VER) constexpr std::string_view name{__FUNCSIG__ + 63, sizeof(__FUNCSIG__) - 81 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)}; -#else - static_assert(nameof_type_supported::value, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); - return std::string_view{}; // Unsupported compiler. #endif -#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) - return static_string{name}; -#endif + if constexpr (nameof_type_supported::value) { + return static_string{name}; + } else { + static_assert(nameof_type_supported::value, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); + return std::string_view{}; // Unsupported compiler. + } } -#if defined(_MSC_VER) -template > -#else -template -#endif -inline constexpr auto nameof_type_v = n(); - } // namespace nameof::detail // Checks is nameof_type supported compiler. @@ -305,26 +403,49 @@ template // Obtains string name of type, reference and cv-qualifiers are ignored. template -[[nodiscard]] constexpr std::string_view nameof_type() noexcept { - return detail::nameof_type_v>; +[[nodiscard]] constexpr auto nameof_type() noexcept { +#if defined(_MSC_VER) + return detail::n>>(); +#else + return detail::n>(); +#endif } // Obtains string name of full type, with reference and cv-qualifiers. template -[[nodiscard]] constexpr std::string_view nameof_full_type() noexcept { - return detail::nameof_type_v; +[[nodiscard]] constexpr auto nameof_full_type() noexcept { +#if defined(_MSC_VER) + return detail::n>(); +#else + return detail::n(); +#endif } } // namespace nameof -// Obtains simple (unqualified) string name of variable, function, enum, macro. -#define NAMEOF(...) ::nameof::detail::nameof<::std::void_t>(#__VA_ARGS__, true) +// Obtains simple (unqualified) string name of variable, function, macro. +#define NAMEOF(...) []() constexpr noexcept { \ + ::std::void_t(); \ + constexpr auto name = ::nameof::detail::pretty_name(#__VA_ARGS__, true); \ + static_assert(!name.empty(), "Expression does not have a name."); \ + constexpr auto size = name.size(); \ + return ::nameof::detail::static_string{name}; }() -// Obtains simple (unqualified) full (with template suffix) string name of variable, function, enum, macro. -#define NAMEOF_FULL(...) ::nameof::detail::nameof<::std::void_t>(#__VA_ARGS__, false) +// Obtains simple (unqualified) full (with template suffix) string name of variable, function, macro. +#define NAMEOF_FULL(...) []() constexpr noexcept { \ + ::std::void_t(); \ + constexpr auto name = ::nameof::detail::pretty_name(#__VA_ARGS__, false); \ + static_assert(!name.empty(), "Expression does not have a name."); \ + constexpr auto size = name.size(); \ + return ::nameof::detail::static_string{name}; }() -// Obtains raw string name of variable, function, enum, macro. -#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw<::std::void_t>(#__VA_ARGS__) +// Obtains raw string name of variable, function, macro. +#define NAMEOF_RAW(...) []() constexpr noexcept { \ + ::std::void_t(); \ + constexpr auto name = ::std::string_view{#__VA_ARGS__}; \ + static_assert(!name.empty(), "Expression does not have a name."); \ + constexpr auto size = name.size(); \ + return ::nameof::detail::static_string{name}; }() // Obtains simple (unqualified) string enum name of enum variable. #define NAMEOF_ENUM(...) ::nameof::nameof_enum(__VA_ARGS__)