wip v0.6.0

This commit is contained in:
neargye 2019-03-20 21:41:51 +05:00
parent e5fe4258d6
commit 80a3e6d3e3
10 changed files with 175 additions and 498 deletions

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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

View file

@ -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<int, float>) -> "SomeMethod"
NAMEOF_FULL(SomeMethod<int, float>) -> "SomeMethod4<int, float>"
// 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<decltype(SomeEnum::RED)>() -> "SomeEnum"
nameof::NameofType<decltype(Color::RED)>() -> "Color"
nameof::NameofType<int> -> "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

View file

@ -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

View file

@ -1,7 +1,6 @@
// nameof example
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// Copyright (c) 2018 Daniil Goncharov <neargye@gmail.com>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
//
// 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 <typename T, typename U>
std::string SomeMethod4(U value) {
return NAMEOF(SomeMethod4<T, U>) + "<" + NAMEOF_TYPE_T(T) + ", " + NAMEOF_TYPE_T(U) + ">(" + NAMEOF_TYPE_T(U) + " " + NAMEOF(value) + ")";
std::string s;
s += NAMEOF(SomeMethod4<T, U>);
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 <typename T>
class SomeClass {
public:
void SomeMethod5() const {
std::cout << nameof::NameofType<T>() << std::endl;
std::cout << nameof::nameof_type<T>() << std::endl;
}
template <typename C>
@ -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

View file

@ -8,7 +8,8 @@
// vesion 0.5.0
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// Copyright (c) 2016, 2018 Daniil Goncharov <neargye@gmail.com>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2016, 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
//
// 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 <cstddef>
#include <type_traits>
#include <limits>
#include <stdexcept>
#include <string>
#include <ostream>
#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 <string_view>
#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 <typename T>
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<char>::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 <std::size_t N>
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<std::size_t>::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 <typename T>
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 <typename T, T V>
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<T>() + 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_<T>() + 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<T>() + sizeof("; T V = ") - 2,
# else
sizeof("nameof::cstring nameof::detail::NameofEnumImpl2() [with T = ") + NameofEnumImpl1<T>() + 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_<T>() + sizeof("; V = ");
const auto suffix = sizeof("; std::string_view = std::basic_string_view<char>]") - 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<T>(),
sizeof(">(void)") - 1};
const auto str = __FUNCSIG__;
const auto size = sizeof(__FUNCSIG__) - 1;
const auto prefix = sizeof("class std::basic_string_view<char,struct std::char_traits<char> > __cdecl nameof::detail::nameof_enum_impl<") + nameof_enum_impl_<T>();
const auto suffix = sizeof(">(void)") - 1;
return {str + prefix, size - prefix - suffix};
#else
return {};
#endif
}
template <typename T, int I>
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<T, T(I)>()
? nameof_enum_impl<T, T(I)>()
: (value - I == 1)
? NameofEnumImpl2<T, T(I + 1)>()
? nameof_enum_impl<T, T(I + 1)>()
: (value - I == 2)
? NameofEnumImpl2<T, T(I + 2)>()
? nameof_enum_impl<T, T(I + 2)>()
: (value - I == 3)
? NameofEnumImpl2<T, T(I + 3)>()
? nameof_enum_impl<T, T(I + 3)>()
: (value - I == 4)
? NameofEnumImpl2<T, T(I + 4)>()
? nameof_enum_impl<T, T(I + 4)>()
: (value - I == 5)
? NameofEnumImpl2<T, T(I + 5)>()
? nameof_enum_impl<T, T(I + 5)>()
: (value - I == 6)
? NameofEnumImpl2<T, T(I + 6)>()
? nameof_enum_impl<T, T(I + 6)>()
: (value - I == 7)
? NameofEnumImpl2<T, T(I + 7)>()
: NameofEnumImpl<T, I + 8>{}(value);
? nameof_enum_impl<T, T(I + 7)>()
: nameof_enum_t<T, I + 8>{}(value);
}
};
template <typename T>
struct NameofEnumImpl<T, NAMEOF_ENUM_MAX_SEARCH_DEPTH> {
NAMEOF_CONSTEXPR cstring operator()(int) const { return {}; }
struct nameof_enum_t<T, NAMEOF_ENUM_MAX_SEARCH_DEPTH> {
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 <typename T>
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<char>]") - 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<struct nameof::detail::nstd::identity<") - 1,
sizeof(">>(void)") - 1});
const auto str = __FUNCSIG__;
const auto size = sizeof(__FUNCSIG__) - 1;
const auto prefix = sizeof("class std::basic_string_view<char,struct std::char_traits<char> > __cdecl nameof::detail::nameof_type_impl<struct nameof::detail::identity<") - 1;
const auto suffix = sizeof(">>(void)") - 1;
return nameof_type_impl_({str + prefix, size - prefix - suffix});
#else
return {};
#endif
@ -439,49 +227,48 @@ NAMEOF_CONSTEXPR cstring NameofType() {
template <typename T,
typename = typename std::enable_if<!std::is_reference<T>::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 <typename T,
typename D = typename std::decay<T>::type,
typename U = typename std::underlying_type<D>::type,
typename S = typename std::is_signed<U>::type,
typename = typename std::enable_if<std::is_enum<D>::value>::type>
NAMEOF_CONSTEXPR cstring NameofEnum(D value) {
typename = typename std::enable_if<std::is_enum<typename std::decay<T>::type>::value>::type>
constexpr std::string_view nameof_enum(T value) {
constexpr auto s = std::is_signed<typename std::underlying_type<typename std::decay<T>::type>::type>::value;
const auto name = detail::nameof_enum_t<typename std::decay<T>::type, s ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value));
#if defined(__clang__) || defined(_MSC_VER)
return detail::NameofPretty(
detail::NameofEnumImpl<D, S::value ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value)),
false);
return detail::pretty_name(name, false);
#elif defined(__GNUC__)
return detail::NameofEnumImpl<D, S::value ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value));
return name;
#else
return {};
#endif
}
template <typename T, typename D = detail::nstd::identity<T>>
NAMEOF_CONSTEXPR cstring NameofType() {
return true ? detail::NameofType<D>() : detail::NameofType<D>();
template <typename T>
constexpr std::string_view nameof_type() {
return detail::nameof_type_impl<detail::identity<T>>();
}
template <typename T>
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<decltype(__VA_ARGS__)>(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1, false)
#define NAMEOF(...) ::nameof::nameof<decltype(__VA_ARGS__)>(#__VA_ARGS__, false)
// Used to obtain the full string name of a variable, member, function, enum, macros.
#define NAMEOF_FULL(...) ::nameof::Nameof<decltype(__VA_ARGS__)>(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1, true)
#define NAMEOF_FULL(...) ::nameof::nameof<decltype(__VA_ARGS__)>(#__VA_ARGS__, true)
// Used to obtain the raw string name of a variable, member, function, enum, macros.
#define NAMEOF_RAW(...) ::nameof::NameofRaw<decltype(__VA_ARGS__)>(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1)
#define NAMEOF_RAW(...) ::nameof::nameof_raw<decltype(__VA_ARGS__)>(#__VA_ARGS__)
// Used to obtain the simple (unqualified) string name of a enum variable.
#define NAMEOF_ENUM(...) ::nameof::NameofEnum<decltype(__VA_ARGS__)>(__VA_ARGS__)
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<decltype(__VA_ARGS__)>(__VA_ARGS__)
// Used to obtain the string name of a type.
#define NAMEOF_TYPE(...) ::nameof::NameofType<decltype(__VA_ARGS__)>()
#define NAMEOF_TYPE_T(...) ::nameof::NameofType<__VA_ARGS__>()
#define NAMEOF_TYPE(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>()
#define NAMEOF_TYPE_T(...) ::nameof::nameof_type<__VA_ARGS__>()

View file

@ -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")

View file

@ -1,7 +1,6 @@
// nameof test
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// Copyright (c) 2018 Daniil Goncharov <neargye@gmail.com>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
//
// 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 <typename T, typename U>
std::string SomeMethod4(U value) {
return NAMEOF(SomeMethod4<T, U>) + "<" + 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 <typename T>
@ -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<int>::SomeMethod6<long int>);
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<int>::SomeMethod6<long int>);
static_assert(cx3 == "SomeMethod6<long int>", "");
static_assert(cx3 == "SomeMethod6<long int>");
REQUIRE(cx3 == "SomeMethod6<long int>");
// 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<int> *", "");
#if defined(__clang__)
static_assert(cx == "const volatile SomeClass<int> *");
REQUIRE(cx == "const volatile SomeClass<int> *");
# elif defined(__GNUC__)
#elif defined(__GNUC__)
static_assert(cx == "const volatile SomeClass<int>*");
REQUIRE(cx == "const volatile SomeClass<int>*");
# elif defined(_MSC_VER)
static_assert(cx == "SomeClass<int> const volatile *", "");
#elif defined(_MSC_VER)
static_assert(cx == "SomeClass<int> const volatile *");
REQUIRE(cx == "SomeClass<int> const volatile *");
# endif
#endif
}
SECTION("NAMEOF_TYPE_T") {
constexpr auto cx = NAMEOF_TYPE_T(const SomeClass<int> volatile *);
# if defined(__clang__)
static_assert(cx == "const volatile SomeClass<int> *", "");
#if defined(__clang__)
static_assert(cx == "const volatile SomeClass<int> *");
REQUIRE(cx == "const volatile SomeClass<int> *");
# elif defined(__GNUC__)
#elif defined(__GNUC__)
static_assert(cx == "const volatile SomeClass<int>*");
REQUIRE(cx == "const volatile SomeClass<int>*");
# elif defined(_MSC_VER)
static_assert(cx == "SomeClass<int> const volatile *", "");
#elif defined(_MSC_VER)
static_assert(cx == "SomeClass<int> const volatile *");
REQUIRE(cx == "SomeClass<int> 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") {}