diff --git a/include/nameof.hpp b/include/nameof.hpp index fc72a3e..649ca31 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -83,32 +83,11 @@ static_assert(NAMEOF_ENUM_RANGE_MAX < (std::numeric_limits::max)() static_assert(NAMEOF_ENUM_RANGE_MAX > NAMEOF_ENUM_RANGE_MIN, "NAMEOF_ENUM_RANGE_MAX must be greater than NAMEOF_ENUM_RANGE_MIN."); -namespace detail { - -template -struct identity final { - using type = T; -}; - -template -struct nameof_type_supported final -#if defined(NAMEOF_TYPE_SUPPORTED) && NAMEOF_TYPE_SUPPORTED - : std::true_type {}; -#else - : std::false_type {}; -#endif - -template -struct nameof_enum_supported final -#if defined(NAMEOF_ENUM_SUPPORTED) && NAMEOF_ENUM_SUPPORTED - : std::true_type {}; -#else - : std::false_type {}; -#endif - template -struct [[nodiscard]] static_string final { - constexpr static_string(std::string_view str) noexcept : static_string{str, std::make_index_sequence{}} {} +struct [[nodiscard]] cstring final { + static_assert(N > 0, "Expression does not have a name."); + + constexpr cstring(std::string_view str) noexcept : cstring{str, std::make_index_sequence{}} {} [[nodiscard]] constexpr auto data() const noexcept { return chars.data(); } @@ -150,88 +129,73 @@ struct [[nodiscard]] static_string final { private: template - constexpr static_string(std::string_view str, std::index_sequence) noexcept : chars{{str[I]..., '\0'}} {} + constexpr cstring(std::string_view str, std::index_sequence) noexcept : chars{{str[I]..., '\0'}} {} const std::array chars; }; -template <> -struct [[nodiscard]] static_string<0> final { - constexpr static_string(std::string_view) noexcept {} - - [[nodiscard]] constexpr const char* data() const noexcept { return nullptr; } - - [[nodiscard]] 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); - } - - [[nodiscard]] constexpr operator std::string_view() const noexcept { return {}; } -}; - template -[[nodiscard]] constexpr bool operator==(const static_string& lhs, std::string_view rhs) noexcept { +[[nodiscard]] constexpr bool operator==(const cstring& 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 { +[[nodiscard]] constexpr bool operator==(std::string_view lhs, const cstring& rhs) noexcept { return lhs.compare(rhs) == 0; } template -[[nodiscard]] constexpr bool operator!=(const static_string& lhs, std::string_view rhs) noexcept { +[[nodiscard]] constexpr bool operator!=(const cstring& 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 { +[[nodiscard]] constexpr bool operator!=(std::string_view lhs, const cstring& rhs) noexcept { return lhs.compare(rhs) != 0; } template -[[nodiscard]] constexpr bool operator>(const static_string& lhs, std::string_view rhs) noexcept { +[[nodiscard]] constexpr bool operator>(const cstring& 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 { +[[nodiscard]] constexpr bool operator>(std::string_view lhs, const cstring& rhs) noexcept { return lhs.compare(rhs) > 0; } template -[[nodiscard]] constexpr bool operator>=(const static_string& lhs, std::string_view rhs) noexcept { +[[nodiscard]] constexpr bool operator>=(const cstring& 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 { +[[nodiscard]] constexpr bool operator>=(std::string_view lhs, const cstring& rhs) noexcept { return lhs.compare(rhs) >= 0; } template -[[nodiscard]] constexpr bool operator<(const static_string& lhs, std::string_view rhs) noexcept { +[[nodiscard]] constexpr bool operator<(const cstring& 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 { +[[nodiscard]] constexpr bool operator<(std::string_view lhs, const cstring& rhs) noexcept { return lhs.compare(rhs) < 0; } template -[[nodiscard]] constexpr bool operator<=(const static_string& lhs, std::string_view rhs) noexcept { +[[nodiscard]] constexpr bool operator<=(const cstring& 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 { +[[nodiscard]] constexpr bool operator<=(std::string_view lhs, const cstring& rhs) noexcept { return lhs.compare(rhs) <= 0; } template -std::basic_ostream& operator<<(std::basic_ostream& os, const static_string& srt) { +std::basic_ostream& operator<<(std::basic_ostream& os, const cstring& srt) { for (auto c : std::string_view{srt}) { os.put(c); } @@ -239,14 +203,65 @@ std::basic_ostream& operator<<(std::basic_ostream& o return os; } +namespace detail { + +template +struct identity final { + using type = T; +}; + +template +struct nameof_type_supported final +#if defined(NAMEOF_TYPE_SUPPORTED) && NAMEOF_TYPE_SUPPORTED + : std::true_type {}; +#else + : std::false_type {}; +#endif + +template +struct nameof_enum_supported final +#if defined(NAMEOF_ENUM_SUPPORTED) && NAMEOF_ENUM_SUPPORTED + : std::true_type {}; +#else + : std::false_type {}; +#endif + +template +struct static_string final { + constexpr static_string(std::string_view str) noexcept : static_string{str, std::make_index_sequence{}} {} + + constexpr const char* data() const noexcept { return chars.data(); } + + constexpr std::size_t size() const noexcept { return chars.size(); } + + 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]...}} {} + + 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; } + + constexpr operator std::string_view() const noexcept { return {}; } +}; + template using remove_cvref_t = std::remove_cv_t>; template using enable_if_enum_t = std::enable_if_t, R>; -template -inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; +template +inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; constexpr std::string_view pretty_name(std::string_view name, bool remove_template_suffix = true) noexcept { if (name.size() >= 1 && (name[0] == '"' || name[0] == '\'')) { @@ -360,12 +375,13 @@ inline constexpr int reflected_max_v = static_cast(enum_range::max < (st template constexpr std::size_t reflected_size() { - static_assert(is_enum_v, "nameof::detail::range_size requires enum type."); + static_assert(is_enum_v, "nameof::detail::reflected_size requires enum type."); static_assert(reflected_min_v > (std::numeric_limits::min)(), "nameof::enum_range requires min must be greater than INT16_MIN."); static_assert(reflected_max_v < (std::numeric_limits::max)(), "nameof::enum_range requires max must be less than INT16_MAX."); static_assert(reflected_max_v > reflected_min_v, "nameof::enum_range requires max > min."); constexpr auto size = reflected_max_v - reflected_min_v + 1; static_assert(size > 0, "nameof::enum_range requires valid size."); + static_assert(size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); return static_cast(size); } @@ -399,6 +415,7 @@ constexpr std::size_t range_size() noexcept { static_assert(is_enum_v, "nameof::detail::range_size requires enum type."); constexpr auto size = max_v - min_v + 1; static_assert(size > 0, "nameof::enum_range requires valid size."); + static_assert(size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); return static_cast(size); } @@ -519,7 +536,7 @@ constexpr auto n() noexcept { # elif defined(_MSC_VER) constexpr std::string_view name{__FUNCSIG__ + 63, sizeof(__FUNCSIG__) - 81 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)}; # endif - return static_string{name}; + return cstring{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. @@ -575,7 +592,7 @@ template 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}; }() + return ::nameof::cstring{name}; }() // Obtains simple (unqualified) full (with template suffix) string name of variable, function, macro. #define NAMEOF_FULL(...) []() constexpr noexcept { \ @@ -583,7 +600,7 @@ template 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}; }() + return ::nameof::cstring{name}; }() // Obtains raw string name of variable, function, macro. #define NAMEOF_RAW(...) []() constexpr noexcept { \ @@ -591,7 +608,7 @@ template 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}; }() + return ::nameof::cstring{name}; }() // Obtains simple (unqualified) string enum name of enum variable. #define NAMEOF_ENUM(...) ::nameof::nameof_enum(__VA_ARGS__)