From 80a3e6d3e3cba8ae1593d470199ef9f8d33d8bdf Mon Sep 17 00:00:00 2001 From: neargye Date: Wed, 20 Mar 2019 21:41:51 +0500 Subject: [PATCH] wip v0.6.0 --- .appveyor.yml | 1 - .travis.yml | 104 ---------- CMakeLists.txt | 2 +- LICENSE | 2 +- README.md | 28 +-- example/CMakeLists.txt | 3 +- example/example.cpp | 26 ++- include/nameof.hpp | 417 ++++++++++------------------------------- test/CMakeLists.txt | 14 -- test/test.cpp | 76 ++++---- 10 files changed, 175 insertions(+), 498 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5cf0a17..ba4aa6d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,7 +19,6 @@ build: environment: matrix: - GENERATOR: "Visual Studio 15 2017" - - GENERATOR: "Visual Studio 14 2015" before_build: - if exist build RMDIR /S /Q build diff --git a/.travis.yml b/.travis.yml index 5a85a30..9b26b79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,50 +9,6 @@ git: matrix: include: - - os: linux - compiler: g++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 - env: - - CXX_COMPILER=g++-4.8 CC_COMPILER=gcc-4.8 - - - os: linux - compiler: g++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.9 - env: - - CXX_COMPILER=g++-4.9 CC_COMPILER=gcc-4.9 - - - os: linux - compiler: g++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-5 - env: - - CXX_COMPILER=g++-5 CC_COMPILER=gcc-5 - - - os: linux - compiler: g++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - env: - - CXX_COMPILER=g++-6 CC_COMPILER=gcc-6 - - os: linux compiler: g++ addons: @@ -75,66 +31,6 @@ matrix: env: - CXX_COMPILER=g++-8 CC_COMPILER=gcc-8 - - os: linux - compiler: clang++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.6 - packages: - - clang-3.6 - env: - - CXX_COMPILER=clang++-3.6 CC_COMPILER=clang-3.6 - - - os: linux - compiler: clang++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.7 - packages: - - clang-3.7 - env: - - CXX_COMPILER=clang++-3.7 CC_COMPILER=clang-3.7 - - - os: linux - compiler: clang++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.8 - packages: - - clang-3.8 - env: - - CXX_COMPILER=clang++-3.8 CC_COMPILER=clang-3.8 - - - os: linux - compiler: clang++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.9 - packages: - - clang-3.9 - env: - - CXX_COMPILER=clang++-3.9 CC_COMPILER=clang-3.9 - - - os: linux - compiler: clang++ - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-4.0 - packages: - - clang-4.0 - env: - - CXX_COMPILER=clang++-4.0 CC_COMPILER=clang-4.0 - - os: linux compiler: clang++ addons: diff --git a/CMakeLists.txt b/CMakeLists.txt index d9b687e..f21e131 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.6) -project(nameof VERSION "0.3.0" LANGUAGES CXX) +project(nameof VERSION "0.6.0" LANGUAGES CXX) option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ON) option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ON) diff --git a/LICENSE b/LICENSE index cd842fb..4802734 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016, 2018 Daniil Goncharov +Copyright (c) 2016, 2018 - 2019 Daniil Goncharov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index be82855..6f4b2a5 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Before, you had to use string literals to refer to definitions, which is brittle ## Features -* C++11 +* C++17 * Header-only * Dependency-free * Compile-time @@ -43,11 +43,10 @@ NAMEOF(person.address.zip_code) -> "zip_code" NAMEOF(SomeMethod) -> "SomeMethod" NAMEOF_FULL(SomeMethod) -> "SomeMethod4" // Name of enum -NAMEOF(SomeEnum::RED) -> "RED" -auto e = SomeEnum::RED; -NAMEOF_ENUM(e) -> "RED" +auto c = Color::RED; +NAMEOF_ENUM(c) -> "RED" // Name of type -NAMEOF_TYPE(SomeEnum::RED) -> "SomeEnum" +NAMEOF_TYPE(Color::RED) -> "Color" NAMEOF_TYPE_T(int) -> "int" // Name of macros NAMEOF(__LINE__) -> "__LINE__" @@ -57,7 +56,7 @@ NAMEOF(__LINE__) -> "__LINE__" ```cpp constexpr auto cx = NAMEOF(somevar); -> "somevar" -static_assert(cx == "somevar", "Wrong name!"); +static_assert("somevar" == cx, "Wrong name!"); ``` * Compilation check @@ -102,6 +101,8 @@ void f() { ## Remarks +* Nameof return std::string_view. + * The argument expression identifies a code definition, but it is never evaluated. * If you need raw fully-qualified name, use NAMEOF_RAW(). @@ -114,24 +115,23 @@ NAMEOF_RAW(&SomeStruct::SomeMethod) -> "&SomeStruct::SomeMethod" * Instead of macros NAMEOF_ENUM, you can use the function nameof::NameofEnum(). ```cpp -nameof::NameofEnum(SomeEnum::RED) -> "RED" -auto e = SomeEnum::RED; -nameof::NameofEnum(e) -> "RED" +nameof::NameofEnum(Color::RED) -> "RED" +auto c = Color::RED; +nameof::NameofEnum(c) -> "RED" ``` * Instead of macros NAMEOF_TYPE, you can use the function nameof::NameofType<>. ```cpp -nameof::NameofType() -> "SomeEnum" +nameof::NameofType() -> "Color" nameof::NameofType -> "int" ``` * NAMEOF_ENUM does not work on the GCC. ```cpp -// On GCC. -auto e = SomeEnum::RED; -NAMEOF_ENUM(e) -> "(SomeEnum)0" +auto c = Color::RED; +NAMEOF_ENUM(c) -> "(Color)0" ``` * Spaces and Tabs ignored @@ -143,7 +143,7 @@ NAMEOF( somevar ) -> "somevar" ## Integration -You should add required file [nameof.hpp](include/nameof.hpp) and switch to C++11. +You should add required file [nameof.hpp](include/nameof.hpp). ## Compiler compatibility diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 975e54b..39b73ee 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -5,12 +5,13 @@ set(OPTIONS "") if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) set(CMAKE_VERBOSE_MAKEFILE ON) set(OPTIONS -Wall -Wextra -pedantic-errors) - set(OPTIONS ${OPTIONS} -std=c++11) + set(OPTIONS ${OPTIONS} -std=c++17) elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(OPTIONS /W4) if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.11) set(OPTIONS ${OPTIONS} /permissive-) endif() + set(OPTIONS ${OPTIONS} /std:c++17) endif() add_executable(example diff --git a/example/example.cpp b/example/example.cpp index 82e3c3c..7aa3b49 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -1,7 +1,6 @@ -// nameof example -// // Licensed under the MIT License . -// Copyright (c) 2018 Daniil Goncharov . +// SPDX-License-Identifier: MIT +// Copyright (c) 2018 - 2019 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -50,14 +49,25 @@ void SomeMethod3() { template std::string SomeMethod4(U value) { - return NAMEOF(SomeMethod4) + "<" + NAMEOF_TYPE_T(T) + ", " + NAMEOF_TYPE_T(U) + ">(" + NAMEOF_TYPE_T(U) + " " + NAMEOF(value) + ")"; + std::string s; + s += NAMEOF(SomeMethod4); + s += "<"; + s += NAMEOF_TYPE_T(T); + s += ", "; + s += NAMEOF_TYPE_T(U); + s += ">("; + s += NAMEOF_TYPE_T(U); + s += " "; + s += NAMEOF(value); + s += ")"; + return s; } template class SomeClass { public: void SomeMethod5() const { - std::cout << nameof::NameofType() << std::endl; + std::cout << nameof::nameof_type() << std::endl; } template @@ -75,7 +85,7 @@ struct Long { LL ll; }; -enum class Color { RED, GREEN, BLUE }; +enum class Color { RED = -10, GREEN, BLUE }; SomeStruct structvar; Long othervar; @@ -84,14 +94,14 @@ SomeStruct* ptrvar = &structvar; int main() { // Compile-time nameof. constexpr auto constexpr_work_fine = NAMEOF(structvar); - static_assert("structvar" == constexpr_work_fine, ""); + static_assert("structvar" == constexpr_work_fine); // 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 + std::cout << nameof::nameof_enum(color) << std::endl; // RED // Variable name. std::cout << NAMEOF(structvar) << std::endl; // structvar diff --git a/include/nameof.hpp b/include/nameof.hpp index c98cdad..d8802ce 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -8,7 +8,8 @@ // vesion 0.5.0 // // Licensed under the MIT License . -// Copyright (c) 2016, 2018 Daniil Goncharov . +// SPDX-License-Identifier: MIT +// Copyright (c) 2016, 2018 - 2019 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,21 +33,7 @@ #include #include -#include -#include -#include -#include - -#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304L -# define NAMEOF_HAS_CONSTEXPR14 1 -#endif - -#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(_MSC_VER) -# define NAMEOF_HAS_CONSTEXPR 1 -# define NAMEOF_CONSTEXPR constexpr -#else -# define NAMEOF_CONSTEXPR inline -#endif +#include #if !defined(NAMEOF_ENUM_MAX_SEARCH_DEPTH) # define NAMEOF_ENUM_MAX_SEARCH_DEPTH 64 @@ -56,159 +43,22 @@ namespace nameof { namespace detail { -namespace nstd { - template struct identity { using type = T; }; -} // namespace nstd - -#if !defined(NAMEOF_HAS_CONSTEXPR14) -constexpr int CharCompare(char lhs, char rhs) { - return (lhs > rhs) ? 1 : ((lhs < rhs) ? -1 : 0); -} -#endif - -constexpr int StrCompare(const char* lhs, const char* rhs, std::size_t size) { -#if !defined(_MSC_VER) && __cplusplus >= 201703L - return std::char_traits::compare(lhs, rhs, size); -#elif defined(NAMEOF_HAS_CONSTEXPR14) - for (std::size_t i = 0; i < size; ++i) { - if (lhs[i] > rhs[i]) { - return 1; - } - if (lhs[i] < rhs[i]) { - return -1; - } - } - return 0; -#else - return (size == 0) ? CharCompare(lhs[0], rhs[0]) - : (CharCompare(lhs[size - 1], rhs[size - 1]) == 0) - ? StrCompare(lhs, rhs, size - 1) - : CharCompare(lhs[size - 1], rhs[size - 1]); -#endif -} - -} // namespace detail - -// std::string like compile-time const char* string. -class cstring final { - const char* str_; - std::size_t size_; - - public: - constexpr cstring(const char* str, std::size_t size, std::size_t prefix = 0, std::size_t suffix = 0) noexcept - : str_{str + prefix}, - size_{size - prefix - suffix} {} - - template - constexpr cstring(const char (&str)[N]) noexcept : cstring{str, N - 1, 0, 0} {} - - constexpr cstring() noexcept : cstring{nullptr, 0, 0, 0} {} - - cstring(const std::string& str) noexcept : cstring{str.data(), str.size(), 0, 0} {} - - constexpr cstring(const cstring&) = default; - - cstring& operator=(const cstring&) = default; - - constexpr std::size_t size() const noexcept { return size_; } - - constexpr std::size_t length() const noexcept { return size_; } - - constexpr std::size_t max_size() const noexcept { - return (std::numeric_limits::max)(); - } - - constexpr bool empty() const noexcept { return size_ == 0; } - - constexpr const char* begin() const noexcept { return str_; } - - constexpr const char* end() const noexcept { return str_ + size_; } - - constexpr const char* cbegin() const noexcept { return begin(); } - - constexpr const char* cend() const noexcept { return end(); } - - constexpr const char& operator[](std::size_t i) const { return str_[i]; } - - constexpr const char& at(std::size_t i) const { - return (i < size_) ? str_[i] - : (throw std::out_of_range{"cstring::at"}, str_[0]); - } - - constexpr const char& front() const { return str_[0]; } - - constexpr const char& back() const { return str_[size_ - 1]; } - - constexpr const char* data() const noexcept { return str_; } - - constexpr cstring remove_prefix(std::size_t n) const { - return {str_ + n, size_ - n}; - } - - constexpr cstring add_prefix(std::size_t n) const { - return {str_ - n, size_ + n}; - } - - constexpr cstring remove_suffix(std::size_t n) const { - return {str_, size_ - n}; - } - - constexpr cstring add_suffix(std::size_t n) const { - return {str_, size_ + n}; - } - - constexpr cstring substr(std::size_t pos, std::size_t n) const { - return {str_ + pos, n}; - } - - constexpr int compare(cstring other) const { - return (size_ == other.size_) ? detail::StrCompare(str_, other.str_, size_) - : ((size_ > other.size_) ? 1 : -1); - } - - friend constexpr bool operator==(cstring lhs, cstring rhs) { - return lhs.compare(rhs) == 0; - } - - friend constexpr bool operator!=(cstring lhs, cstring rhs) { - return !(lhs == rhs); - } - - std::string append(cstring s) const { - return std::string{str_, size_}.append(s.str_, s.size_); - } - - friend std::string operator+(cstring lhs, cstring rhs) { - return std::string{lhs.str_, lhs.size_} + std::string{rhs.str_, rhs.size_}; - } - - friend std::ostream& operator<<(std::ostream& os, cstring str) { - os.write(str.str_, str.size_); - return os; - } - - operator std::string() const { return std::string{str_, size_}; } -}; - -namespace detail { - -constexpr bool IsLexeme(char s) noexcept { +constexpr bool is_lexeme(char s) noexcept { return !((s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || s == '_'); } -constexpr bool IsBracket(char s) noexcept { +constexpr bool is_bracket(char s) noexcept { return s == ')' || s == '}' || s == '>' || s == '(' || s == '{' || s == '<'; } -#if defined(NAMEOF_HAS_CONSTEXPR14) -constexpr cstring NameofPretty(cstring name, bool with_suffix) { +constexpr std::string_view pretty_name(std::string_view name, bool with_suffix) { for (std::size_t i = name.size(), h = 0, s = 0; i > 0; --i) { - if (h == 0 && IsLexeme(name[i - 1]) && !IsBracket(name[i - 1])) { + if (h == 0 && is_lexeme(name[i - 1]) && !is_bracket(name[i - 1])) { ++s; continue; } @@ -224,7 +74,7 @@ constexpr cstring NameofPretty(cstring name, bool with_suffix) { } if (h == 0) { - name = name.remove_suffix(s); + name.remove_suffix(s); break; } else { ++s; @@ -253,183 +103,121 @@ constexpr cstring NameofPretty(cstring name, bool with_suffix) { } for (std::size_t i = name.size() - s; i > 0; --i) { - if (IsLexeme(name[i - 1])) { - return name.remove_prefix(i).remove_suffix(with_suffix ? 0 : s); + if (is_lexeme(name[i - 1])) { + name.remove_prefix(i); + break; } } + name.remove_suffix(with_suffix ? 0 : s); - return name.remove_suffix(with_suffix ? 0 : s); + return name; } -#else -constexpr cstring RemoveSuffix(cstring name, std::size_t h = 0) { - return (h == 0 && IsLexeme(name.back()) && !IsBracket(name.back())) - ? RemoveSuffix(name.remove_suffix(1), h) - : (name.back() == ')' || name.back() == '}') - ? RemoveSuffix(name.remove_suffix(1), h + 1) - : (name.back() == '(' || name.back() == '{') - ? RemoveSuffix(name.remove_suffix(1), h - 1) - : (h == 0) ? name - : RemoveSuffix(name.remove_suffix(1), h); -} - -constexpr std::size_t FindSuffix(cstring name, std::size_t h = 0, std::size_t s = 0) { - return (name[name.size() - 1 - s] == '>') - ? FindSuffix(name, h + 1, s + 1) - : (name[name.size() - 1 - s] == '<') - ? FindSuffix(name, h - 1, s + 1) - : (h == 0) ? s : FindSuffix(name, h, s + 1); -} - -constexpr cstring RemovePrefix(cstring name, const std::size_t p = 0) { - return p == name.size() ? name : IsLexeme(name[name.size() - 1 - p]) - ? name.remove_prefix(name.size() - p) - : RemovePrefix(name, p + 1); -} - -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 NameofPrettyImpl1(name, FindSuffix(name), with_suffix); -} - -constexpr cstring NameofPretty(cstring name, bool with_suffix) { - return NameofPrettyImpl(RemoveSuffix(name), with_suffix); -} -#endif - -#if defined(_MSC_VER) -constexpr cstring RemoveSpaceSuffix(cstring name) { - return (name.back() == ' ') ? RemoveSpaceSuffix(name.remove_suffix(1)) : name; -} - -constexpr cstring RemoveClassPrefix(cstring name) { - return (name.size() > sizeof("class") && name[0] == 'c' && name[1] == 'l' && - name[2] == 'a' && name[3] == 's' && name[4] == 's' && name[5] == ' ') - ? name.remove_prefix(sizeof("class")) - : name; -} - -constexpr cstring RemoveEnumPrefix(cstring name) { - return (name.size() > sizeof("enum") && name[0] == 'e' && name[1] == 'n' && - name[2] == 'u' && name[3] == 'm' && name[4] == ' ') - ? name.remove_prefix(sizeof("enum")) - : name; -} - -constexpr cstring RemoveStructPrefix(cstring name) { - return (name.size() > sizeof("struct") && name[0] == 's' && name[1] == 't' && - name[2] == 'r' && name[3] == 'u' && name[4] == 'c' && - name[5] == 't' && name[6] == ' ') - ? name.remove_prefix(sizeof("struct")) - : name; -} - -constexpr cstring NameofTypePretty(cstring name) { - return RemoveClassPrefix(RemoveStructPrefix(RemoveEnumPrefix(RemoveSpaceSuffix(name)))); -} -#elif defined(__clang__) || defined(__GNUC__) -constexpr cstring NameofTypePretty(const char* str, std::size_t size, std::size_t prefix, std::size_t suffix) { - return {str, size, prefix, suffix + ((str[size - suffix - 1] == ' ') ? 1 : 0)}; -} -#endif template -NAMEOF_CONSTEXPR int NameofEnumImpl1() { +constexpr int nameof_enum_impl_() { #if defined(__clang__) - return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::NameofEnumImpl1() [T = ") - sizeof("]") + 1; + return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::nameof_enum_impl_() [T = ") - sizeof("]") + 1; #elif defined(__GNUC__) -# if defined(NAMEOF_HAS_CONSTEXPR) - return sizeof(__PRETTY_FUNCTION__) - sizeof("constexpr int nameof::detail::NameofEnumImpl1() [with T = ") - sizeof("]") + 1; -# else - return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::NameofEnumImpl1() [with T = ") - sizeof("]") + 1; -# endif + return sizeof(__PRETTY_FUNCTION__) - sizeof("constexpr int nameof::detail::nameof_enum_impl_() [with T = ") - sizeof("]") + 1; #elif defined(_MSC_VER) - return sizeof(__FUNCSIG__) - sizeof("int __cdecl nameof::detail::NameofEnumImpl1<") - sizeof(">(void)") + 1; + return sizeof(__FUNCSIG__) - sizeof("int __cdecl nameof::detail::nameof_enum_impl_<") - sizeof(">(void)") + 1; #else return 0; #endif } template -NAMEOF_CONSTEXPR cstring NameofEnumImpl2() { +constexpr std::string_view nameof_enum_impl() { #if defined(__clang__) - return {__PRETTY_FUNCTION__, - sizeof(__PRETTY_FUNCTION__) - 1, - sizeof("nameof::cstring nameof::detail::NameofEnumImpl2() [T = ") + NameofEnumImpl1() + sizeof("; V = ") - 2, - sizeof("]") - 1}; + const auto str = __PRETTY_FUNCTION__; + const auto size = sizeof(__PRETTY_FUNCTION__) - 1; + const auto prefix = sizeof("std::string_view nameof::detail::nameof_enum_impl() [T = ") + nameof_enum_impl_() + sizeof("; V = ") - 2; + const auto suffix = sizeof("]") - 1; + return {str + prefix, size - prefix - suffix}; #elif defined(__GNUC__) - return {__PRETTY_FUNCTION__, - sizeof(__PRETTY_FUNCTION__) - 1, -# if defined(NAMEOF_HAS_CONSTEXPR) - sizeof("constexpr nameof::cstring nameof::detail::NameofEnumImpl2() [with T = ") + NameofEnumImpl1() + sizeof("; T V = ") - 2, -# else - sizeof("nameof::cstring nameof::detail::NameofEnumImpl2() [with T = ") + NameofEnumImpl1() + sizeof("; T V = ") - 2, -# endif - sizeof("]") - 1}; + const auto str = __PRETTY_FUNCTION__; + const auto size = sizeof(__PRETTY_FUNCTION__) - 1; + const auto prefix = sizeof("constexpr std::string_view nameof::detail::nameof_enum_impl() [with T = ") + nameof_enum_impl_() + sizeof("; V = "); + const auto suffix = sizeof("; std::string_view = std::basic_string_view]") - 1; + return {str + prefix, size - prefix - suffix}; #elif defined(_MSC_VER) - return {__FUNCSIG__, - sizeof(__FUNCSIG__) - 1, - sizeof("class nameof::cstring __cdecl nameof::detail::NameofEnumImpl2<") + NameofEnumImpl1(), - sizeof(">(void)") - 1}; + const auto str = __FUNCSIG__; + const auto size = sizeof(__FUNCSIG__) - 1; + const auto prefix = sizeof("class std::basic_string_view > __cdecl nameof::detail::nameof_enum_impl<") + nameof_enum_impl_(); + const auto suffix = sizeof(">(void)") - 1; + return {str + prefix, size - prefix - suffix}; #else return {}; #endif } template -struct NameofEnumImpl { - NAMEOF_CONSTEXPR cstring operator()(int value) const { +struct nameof_enum_t { + constexpr std::string_view operator()(int value) const { return (value - I == 0) - ? NameofEnumImpl2() + ? nameof_enum_impl() : (value - I == 1) - ? NameofEnumImpl2() + ? nameof_enum_impl() : (value - I == 2) - ? NameofEnumImpl2() + ? nameof_enum_impl() : (value - I == 3) - ? NameofEnumImpl2() + ? nameof_enum_impl() : (value - I == 4) - ? NameofEnumImpl2() + ? nameof_enum_impl() : (value - I == 5) - ? NameofEnumImpl2() + ? nameof_enum_impl() : (value - I == 6) - ? NameofEnumImpl2() + ? nameof_enum_impl() : (value - I == 7) - ? NameofEnumImpl2() - : NameofEnumImpl{}(value); + ? nameof_enum_impl() + : nameof_enum_t{}(value); } }; template -struct NameofEnumImpl { - NAMEOF_CONSTEXPR cstring operator()(int) const { return {}; } +struct nameof_enum_t { + constexpr std::string_view operator()(int) const { return {"nameof_enum::out_of_range"}; } }; +constexpr std::string_view nameof_type_impl_(std::string_view name) { +#if defined(_MSC_VER) + if (name.size() > sizeof("enum") && name[0] == 'e' && name[1] == 'n' && name[2] == 'u' && name[3] == 'm' && name[4] == ' ') { + name.remove_prefix(sizeof("enum")); + } + if (name.size() > sizeof("class") && name[0] == 'c' && name[1] == 'l' && name[2] == 'a' && name[3] == 's' && name[4] == 's' && name[5] == ' ') { + name.remove_prefix(sizeof("class")); + } + if (name.size() > sizeof("struct") && name[0] == 's' && name[1] == 't' && name[2] == 'r' && name[3] == 'u' && name[4] == 'c' && name[5] == 't' && name[6] == ' ') { + name.remove_prefix(sizeof("struct")); + } +#endif + while (name.back() == ' ') { + name.remove_suffix(1); + } + + return name; +} + template -NAMEOF_CONSTEXPR cstring NameofType() { +constexpr std::string_view nameof_type_impl() { #if defined(__clang__) - return NameofTypePretty( - __PRETTY_FUNCTION__, - sizeof(__PRETTY_FUNCTION__) - 1, - sizeof("nameof::cstring nameof::detail::NameofType() [T = nameof::detail::nstd::identity<") - 1, - sizeof(">]") - 1); + const auto str = __PRETTY_FUNCTION__; + const auto size = sizeof(__PRETTY_FUNCTION__) - 1; + const auto prefix = sizeof("std::string_view nameof::detail::nameof_type_impl() [T = nameof::detail::identity<") - 1; + const auto suffix = sizeof(">]") - 1; + return nameof_type_impl_({str + prefix, size - prefix - suffix}); #elif defined(__GNUC__) - return NameofTypePretty( - __PRETTY_FUNCTION__, - sizeof(__PRETTY_FUNCTION__) - 1, -# if defined(NAMEOF_HAS_CONSTEXPR) - sizeof("constexpr nameof::cstring nameof::detail::NameofType() [with T = nameof::detail::nstd::identity<") - 1, -# else - sizeof("nameof::cstring nameof::detail::NameofType() [with T = nameof::detail::nstd::identity<") - 1, -# endif - sizeof(">]") - 1); + const auto str = __PRETTY_FUNCTION__; + const auto size = sizeof(__PRETTY_FUNCTION__) - 1; + const auto prefix = sizeof("constexpr std::string_view nameof::detail::nameof_type_impl() [with T = nameof::detail::identity<") - 1; + const auto suffix = sizeof(">; std::string_view = std::basic_string_view]") - 1; + return nameof_type_impl_({str + prefix, size - prefix - suffix}); #elif defined(_MSC_VER) - return NameofTypePretty( - {__FUNCSIG__, - sizeof(__FUNCSIG__) - 1, - sizeof("class nameof::cstring __cdecl nameof::detail::NameofType>(void)") - 1}); + const auto str = __FUNCSIG__; + const auto size = sizeof(__FUNCSIG__) - 1; + const auto prefix = sizeof("class std::basic_string_view > __cdecl nameof::detail::nameof_type_impl>(void)") - 1; + return nameof_type_impl_({str + prefix, size - prefix - suffix}); #else return {}; #endif @@ -439,49 +227,48 @@ NAMEOF_CONSTEXPR cstring NameofType() { template ::value>::type> -constexpr cstring Nameof(const char* name, std::size_t size, bool with_suffix = false) { - return detail::NameofPretty({name, size}, with_suffix); +constexpr std::string_view nameof(std::string_view name, bool with_suffix = false) { + return detail::pretty_name(name, with_suffix); } template ::type, - typename U = typename std::underlying_type::type, - typename S = typename std::is_signed::type, - typename = typename std::enable_if::value>::type> -NAMEOF_CONSTEXPR cstring NameofEnum(D value) { + typename = typename std::enable_if::type>::value>::type> +constexpr std::string_view nameof_enum(T value) { + constexpr auto s = std::is_signed::type>::type>::value; + const auto name = detail::nameof_enum_t::type, s ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast(value)); #if defined(__clang__) || defined(_MSC_VER) - return detail::NameofPretty( - detail::NameofEnumImpl{}(static_cast(value)), - false); + return detail::pretty_name(name, false); #elif defined(__GNUC__) - return detail::NameofEnumImpl{}(static_cast(value)); + return name; #else return {}; #endif } -template > -NAMEOF_CONSTEXPR cstring NameofType() { - return true ? detail::NameofType() : detail::NameofType(); +template +constexpr std::string_view nameof_type() { + return detail::nameof_type_impl>(); } template -constexpr cstring NameofRaw(const char* name, std::size_t size) { - return {name, size}; +constexpr std::string_view nameof_raw(std::string_view name) { + return name; } } // namespace nameof // 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) +#define NAMEOF(...) ::nameof::nameof(#__VA_ARGS__, false) + // 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) +#define NAMEOF_FULL(...) ::nameof::nameof(#__VA_ARGS__, true) + // 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) +#define NAMEOF_RAW(...) ::nameof::nameof_raw(#__VA_ARGS__) // Used to obtain the simple (unqualified) string name of a enum variable. -#define NAMEOF_ENUM(...) ::nameof::NameofEnum(__VA_ARGS__) +#define NAMEOF_ENUM(...) ::nameof::nameof_enum(__VA_ARGS__) // Used to obtain the string name of a type. -#define NAMEOF_TYPE(...) ::nameof::NameofType() -#define NAMEOF_TYPE_T(...) ::nameof::NameofType<__VA_ARGS__>() +#define NAMEOF_TYPE(...) ::nameof::nameof_type() +#define NAMEOF_TYPE_T(...) ::nameof::nameof_type<__VA_ARGS__>() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1b736e2..dc57320 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -68,20 +68,6 @@ function(make_target target std) endif() endfunction() -if(HAS_CPP11_FLAG) - if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - make_target(${CMAKE_PROJECT_NAME}-cpp11.t "") - else() - make_target(${CMAKE_PROJECT_NAME}-cpp11.t c++11) - endif() - add_test(NAME ${CMAKE_PROJECT_NAME}-cpp11.t COMMAND ${CMAKE_PROJECT_NAME}-cpp11.t) -endif() - -if(HAS_CPP14_FLAG) - make_target(${CMAKE_PROJECT_NAME}-cpp14.t c++14) - add_test(NAME ${CMAKE_PROJECT_NAME}-cpp14.t COMMAND ${CMAKE_PROJECT_NAME}-cpp14.t) -endif() - if(HAS_CPP17_FLAG) set(std17 c++17) if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") diff --git a/test/test.cpp b/test/test.cpp index f5e679d..25d3cbd 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,7 +1,6 @@ -// nameof test -// // Licensed under the MIT License . -// Copyright (c) 2018 Daniil Goncharov . +// SPDX-License-Identifier: MIT +// Copyright (c) 2018 - 2019 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -38,12 +37,12 @@ struct SomeStruct { }; void SomeMethod3() { - std::cout << NAMEOF(SomeMethod3) << " no called!" << std::endl; + throw std::runtime_error{"should not be called!"}; } template -std::string SomeMethod4(U value) { - return NAMEOF(SomeMethod4) + "<" + NAMEOF_TYPE_T(T) + ", " + NAMEOF_TYPE_T(U) + ">(" + NAMEOF_TYPE_T(U) + " " + NAMEOF(value) + ")"; +std::string SomeMethod4(U) { + throw std::runtime_error{"should not be called!"}; } template @@ -87,101 +86,102 @@ TEST_CASE("constexpr") { SECTION("NAMEOF") { // variable constexpr auto cx1 = NAMEOF(struct_var); - static_assert(cx1 == "struct_var", ""); + static_assert(cx1 == "struct_var"); REQUIRE(cx1 == "struct_var"); // member constexpr auto cx2 = NAMEOF((&struct_var)->somefield); - static_assert(cx2 == "somefield", ""); + static_assert(cx2 == "somefield"); REQUIRE(cx2 == "somefield"); // function constexpr auto cx3 = NAMEOF(&SomeClass::SomeMethod6); - static_assert(cx3 == "SomeMethod6", ""); + static_assert(cx3 == "SomeMethod6"); REQUIRE(cx3 == "SomeMethod6"); // enum constexpr auto cx4 = NAMEOF(Color::RED); - static_assert(cx4 == "RED", ""); + static_assert(cx4 == "RED"); REQUIRE(cx4 == "RED"); } SECTION("NAMEOF_FULL") { // variable constexpr auto cx1 = NAMEOF_FULL(struct_var); - static_assert(cx1 == "struct_var", ""); + static_assert(cx1 == "struct_var"); REQUIRE(cx1 == "struct_var"); // member constexpr auto cx2 = NAMEOF_FULL((&struct_var)->somefield); - static_assert(cx2 == "somefield", ""); + static_assert(cx2 == "somefield"); REQUIRE(cx2 == "somefield"); // function constexpr auto cx3 = NAMEOF_FULL(&SomeClass::SomeMethod6); - static_assert(cx3 == "SomeMethod6", ""); + static_assert(cx3 == "SomeMethod6"); REQUIRE(cx3 == "SomeMethod6"); // enum constexpr auto cx4 = NAMEOF_FULL(Color::RED); - static_assert(cx4 == "RED", ""); + static_assert(cx4 == "RED"); REQUIRE(cx4 == "RED"); } SECTION("NAMEOF_RAW") { // variable constexpr auto cx1 = NAMEOF_RAW(struct_var); - static_assert(cx1 == "struct_var", ""); + static_assert(cx1 == "struct_var"); REQUIRE(cx1 == "struct_var"); // member constexpr auto cx2 = NAMEOF_RAW((&struct_var)->somefield); - static_assert(cx2 == "(&struct_var)->somefield", ""); + static_assert(cx2 == "(&struct_var)->somefield"); REQUIRE(cx2 == "(&struct_var)->somefield"); // function constexpr auto cx4 = NAMEOF_RAW(&SomeStruct::SomeMethod2); - static_assert(cx4 == "&SomeStruct::SomeMethod2", ""); + static_assert(cx4 == "&SomeStruct::SomeMethod2"); REQUIRE(cx4 == "&SomeStruct::SomeMethod2"); // enum constexpr auto cx5 = NAMEOF_RAW(Color::RED); - static_assert(cx5 == "Color::RED", ""); + static_assert(cx5 == "Color::RED"); REQUIRE(cx5 == "Color::RED"); // macros constexpr auto cx6 = NAMEOF_RAW(__cplusplus); - static_assert(cx6 == "__cplusplus", ""); + static_assert(cx6 == "__cplusplus"); REQUIRE(cx6 == "__cplusplus"); } -#if defined(NAMEOF_HAS_CONSTEXPR) SECTION("NAMEOF_ENUM") { constexpr auto cx = NAMEOF_ENUM(color); -# if defined(__clang__) || defined(_MSC_VER) - static_assert(cx == "RED", ""); +#if defined(__clang__) || defined(_MSC_VER) + static_assert(cx == "RED"); REQUIRE(cx == "RED"); -# elif defined(__GNUC__) +#elif defined(__GNUC__) + static_assert(cx == "(Color)-1"); REQUIRE(cx == "(Color)-1"); -# endif +#endif } SECTION("NAMEOF_TYPE") { constexpr auto cx = NAMEOF_TYPE(ptr_c); -# if defined(__clang__) - static_assert(cx == "const volatile SomeClass *", ""); +#if defined(__clang__) + static_assert(cx == "const volatile SomeClass *"); REQUIRE(cx == "const volatile SomeClass *"); -# elif defined(__GNUC__) +#elif defined(__GNUC__) + static_assert(cx == "const volatile SomeClass*"); REQUIRE(cx == "const volatile SomeClass*"); -# elif defined(_MSC_VER) - static_assert(cx == "SomeClass const volatile *", ""); +#elif defined(_MSC_VER) + static_assert(cx == "SomeClass const volatile *"); REQUIRE(cx == "SomeClass const volatile *"); -# endif +#endif } SECTION("NAMEOF_TYPE_T") { constexpr auto cx = NAMEOF_TYPE_T(const SomeClass volatile *); -# if defined(__clang__) - static_assert(cx == "const volatile SomeClass *", ""); +#if defined(__clang__) + static_assert(cx == "const volatile SomeClass *"); REQUIRE(cx == "const volatile SomeClass *"); -# elif defined(__GNUC__) +#elif defined(__GNUC__) + static_assert(cx == "const volatile SomeClass*"); REQUIRE(cx == "const volatile SomeClass*"); -# elif defined(_MSC_VER) - static_assert(cx == "SomeClass const volatile *", ""); +#elif defined(_MSC_VER) + static_assert(cx == "SomeClass const volatile *"); REQUIRE(cx == "SomeClass const volatile *"); -# endif - } #endif + } } TEST_CASE("NAMEOF") { @@ -461,5 +461,3 @@ TEST_CASE("Spaces and Tabs ignored") { REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct"); } } - -TEST_CASE("cstring") {}