WIP new version nameof

This commit is contained in:
Neargye 2018-08-02 19:51:44 +05:00
parent e155d22c34
commit fb1299ab02
4 changed files with 404 additions and 228 deletions

View file

@ -2,7 +2,7 @@
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
project(nameof) project(nameof)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)

View file

@ -39,13 +39,9 @@ std::string operator"" _string(const char* str, std::size_t) {
struct SomeStruct { struct SomeStruct {
int somefield = 0; int somefield = 0;
void SomeMethod1(const int i) { void SomeMethod1(const int i) { somefield = i; }
somefield = i;
}
int SomeMethod2() const { int SomeMethod2() const { return somefield; }
return somefield;
}
}; };
void SomeMethod3() { void SomeMethod3() {
@ -57,6 +53,15 @@ T SomeMethod4() {
return T{}; return T{};
} }
template <typename T>
class SomeClass {
public:
void SomeMethod5() const {}
template <typename C>
C SomeMethod6() const { return C{}; }
};
struct Long { struct Long {
struct LL { struct LL {
int field = 0; int field = 0;
@ -68,12 +73,12 @@ enum class Color { RED, GREEN, BLUE };
SomeStruct somevar; SomeStruct somevar;
Long othervar; Long othervar;
int intvar = 0; SomeStruct& refvar = somevar;
SomeStruct* ptrvar = &somevar; SomeStruct* ptrvar = &somevar;
int main() { int main() {
// constexpr // constexpr
constexpr auto constexpr_work_fine = NAMEOF(intvar); constexpr auto constexpr_work_fine = NAMEOF(somevar);
std::cout << constexpr_work_fine << std::endl; // intvar std::cout << constexpr_work_fine << std::endl; // intvar
// enum // enum
@ -82,7 +87,6 @@ int main() {
// variable // variable
std::cout << NAMEOF(somevar) << std::endl; // somevar std::cout << NAMEOF(somevar) << std::endl; // somevar
std::cout << NAMEOF(::somevar) << std::endl; // somevar std::cout << NAMEOF(::somevar) << std::endl; // somevar
std::cout << NAMEOF(&somevar) << std::endl; // somevar
// member // member
std::cout << NAMEOF(somevar.somefield) << std::endl; // somefield std::cout << NAMEOF(somevar.somefield) << std::endl; // somefield
@ -90,23 +94,37 @@ int main() {
std::cout << NAMEOF(othervar.ll.field) << std::endl; // field std::cout << NAMEOF(othervar.ll.field) << std::endl; // field
// function // function
std::cout << NAMEOF(&SomeStruct::SomeMethod1) << std::endl; // SomeMethod1
std::cout << NAMEOF(&SomeStruct::SomeMethod2) << std::endl; // SomeMethod2 std::cout << NAMEOF(&SomeStruct::SomeMethod2) << std::endl; // SomeMethod2
std::cout << NAMEOF(SomeMethod3) << std::endl; // SomeMethod3 std::cout << NAMEOF(SomeMethod3) << std::endl; // SomeMethod3
std::cout << NAMEOF(SomeMethod4<int>) << std::endl; // SomeMethod4
std::cout << NAMEOF(&SomeClass<int>::SomeMethod5) << std::endl; // SomeMethod5
std::cout << NAMEOF(&SomeClass<int>::SomeMethod6<long int>) << std::endl; // SomeMethod6
// function with template prefix
std::cout << NAMEOF_T(SomeMethod4<int>) << std::endl; // SomeMethod4<int>
std::cout << NAMEOF_T(&SomeClass<int>::SomeMethod6<long int>) << std::endl; // SomeMethod6<long int>
// type // type
std::cout << NAMEOF(int[]) << std::endl; // int[] std::cout << NAMEOF_TYPE(std::string{}) << std::endl; // basic_string
std::cout << NAMEOF(SomeStruct) << std::endl; // SomeStruct std::cout << NAMEOF_TYPE(somevar) << std::endl; // SomeStruct
std::cout << NAMEOF(Long::LL) << std::endl; // LL std::cout << NAMEOF_TYPE(refvar) << std::endl; // basic_string
std::cout << NAMEOF(volatile const int) << std::endl; // volatile const int std::cout << NAMEOF_TYPE(ptrvar) << std::endl; // basic_string
std::cout << NAMEOF_TYPE(Color::RED) << std::endl; // Color
std::cout << NAMEOF_RAW(int[]) << std::endl; // int[]
std::cout << NAMEOF_RAW(SomeStruct) << std::endl; // SomeStruct
std::cout << NAMEOF_RAW(Long::LL) << std::endl; // LL
std::cout << NAMEOF_RAW(volatile const int) << std::endl; // volatile const int
// macros // macros
std::cout << NAMEOF(__LINE__) << std::endl; // __LINE__ std::cout << NAMEOF_RAW(__LINE__) << std::endl; // __LINE__
std::cout << NAMEOF(__FILE__) << std::endl; // __FILE__ std::cout << NAMEOF_RAW(__FILE__) << std::endl; // __FILE__
// full name // full name
std::cout << NAMEOF_FULL(somevar.somefield) << std::endl; // somevar.somefield std::cout << NAMEOF_RAW(somevar.somefield) << std::endl; // somevar.somefield
std::cout << NAMEOF_FULL(&SomeStruct::SomeMethod2) << std::endl; // &SomeStruct::SomeMethod2 std::cout << NAMEOF_RAW(&SomeClass<int>::SomeMethod6<long int>) << std::endl; // &SomeStruct::SomeMethod2
std::cout << NAMEOF_FULL(Long::LL) << std::endl; // Long::LL std::cout << NAMEOF_RAW(Long::LL) << std::endl; // Long::LL
const auto div = [](int x, int y) -> int { const auto div = [](int x, int y) -> int {
if (y == 0) { if (y == 0) {
@ -125,10 +143,11 @@ int main() {
/* Remarks */ /* Remarks */
// Spaces and Tabs ignored // Spaces and Tabs ignored
std::cout << NAMEOF( std::string ) << std::endl; // string std::cout << NAMEOF( somevar ) << std::endl; // string
std::cout << NAMEOF( std::string ) << std::endl; // string std::cout << NAMEOF( somevar ) << std::endl; // string
// Bad case #if 0
// This expression does not have a name.
std::cout << NAMEOF("Bad case") << std::endl; // '"Bad case"' std::cout << NAMEOF("Bad case") << std::endl; // '"Bad case"'
std::cout << NAMEOF("Bad case"_string) << std::endl; // '"Bad case"_string' std::cout << NAMEOF("Bad case"_string) << std::endl; // '"Bad case"_string'
std::cout << NAMEOF("somevar.somefield") << std::endl; // 'somefield"' std::cout << NAMEOF("somevar.somefield") << std::endl; // 'somefield"'
@ -148,6 +167,7 @@ int main() {
std::cout << NAMEOF(decltype(intvar)) << std::endl; // 'decltype(intvar)' std::cout << NAMEOF(decltype(intvar)) << std::endl; // 'decltype(intvar)'
std::cout << NAMEOF(typeid(intvar)) << std::endl; // 'typeid(intvar)' std::cout << NAMEOF(typeid(intvar)) << std::endl; // 'typeid(intvar)'
std::cout << NAMEOF((intvar)) << std::endl; // '(intvar)' std::cout << NAMEOF((intvar)) << std::endl; // '(intvar)'
#endif
return 0; return 0;
} }

View file

@ -5,7 +5,7 @@
// | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_| // | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_|
// |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____| // |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____|
// https://github.com/Neargye/nameof // https://github.com/Neargye/nameof
// vesion 0.4.0 // vesion 0.5.0
// //
// Licensed under the MIT License <http://opensource.org/licenses/MIT>. // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// Copyright (c) 2016, 2018 Daniil Goncharov <neargye@gmail.com>. // Copyright (c) 2016, 2018 Daniil Goncharov <neargye@gmail.com>.
@ -32,53 +32,276 @@
#include <cstddef> #include <cstddef>
#include <type_traits> #include <type_traits>
#include <ostream>
namespace nameof { namespace nameof {
namespace detail { namespace detail {
template <typename T>
struct identity {
using type = T;
};
template <typename T>
struct remove_all_pointers
: std::conditional_t<std::is_pointer<T>::value,
remove_all_pointers<typename std::remove_pointer<T>::type>,
identity<T>> {};
class cstring final {
const char* str_;
std::size_t size_;
public:
constexpr cstring(const char* str, std::size_t size) noexcept : str_(str), size_(size) {}
template <std::size_t N>
constexpr cstring(const char(&str)[N]) noexcept : str_(str), size_(N - 1) {}
cstring() = delete;
cstring(const cstring&) = default;
cstring(cstring&&) = default;
cstring& operator=(const cstring&) = default;
cstring& operator=(cstring&&) = default;
~cstring() = default;
inline constexpr std::size_t size() const noexcept { return size_; }
inline constexpr std::size_t length() const noexcept { return size_; }
inline constexpr std::size_t max_size() const noexcept { return std::numeric_limits<decltype(size_)>::max(); }
inline constexpr bool empty() const noexcept { return size_ == 0; }
inline constexpr const char* begin() const noexcept { return str_; }
inline constexpr const char* end() const noexcept { return str_ + size_; }
inline constexpr const char* cbegin() const noexcept { return begin(); }
inline constexpr const char* cend() const noexcept { return end(); }
inline constexpr const char& operator[](std::size_t i) const { return str_[i]; }
inline friend constexpr bool operator==(const cstring& lhs, const cstring& rhs) noexcept;
inline friend constexpr bool operator!=(const cstring& lhs, const cstring& rhs) noexcept;
template <std::size_t N>
inline friend constexpr bool operator==(const cstring& lhs, const char(&str)[N]) noexcept;
template <std::size_t N>
inline friend constexpr bool operator!=(const cstring& lhs, const char(&str)[N]) noexcept;
inline friend std::ostream& operator<<(std::ostream& os, const cstring& str);
inline operator std::string() const { return std::string(begin(), end()); }
};
inline constexpr bool operator==(const cstring& lhs, const cstring& rhs) noexcept {
if (lhs.size_ != rhs.size_)
return false;
for (std::size_t i = 0; i < lhs.size_; ++i) {
if (lhs.str_[i] != rhs.str_[i])
return false;
}
return true;
}
inline constexpr bool operator!=(const cstring& lhs, const cstring& rhs) noexcept {
return !(lhs == rhs);
}
template <std::size_t N>
inline constexpr bool operator==(const cstring& lhs, const char(&str)[N]) noexcept {
return lhs == cstring{str, N - 1};
}
template <std::size_t N>
constexpr bool operator!=(const cstring& lhs, const char(&str)[N]) noexcept {
return !(lhs == cstring{str, N - 1});
}
inline std::ostream& operator<<(std::ostream& os, const cstring& str) {
os.write(str.begin(), str.size());
return os;
}
inline constexpr bool IsLexeme(char s) noexcept { inline constexpr bool IsLexeme(char s) noexcept {
return (s == '.' || s == '>' || s == ':' || s == '&' || s == '*' || return !((s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') ||
s == '+' || s == '~' || s == '-' || s == '!'); (s >= 'A' && s <= 'Z') || s == '_');
}
inline constexpr cstring NameofBase(const char* name, std::size_t length) noexcept {
if (length == 0)
return {name, length};
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 NameofFunction(const char* name, std::size_t length, bool with_template_prefix) noexcept {
if (length == 0)
return {name, length};
std::size_t h = 0;
std::size_t p = 0;
for (std::size_t i = length; i > 0; --i) {
if (name[i - 1] == '>') {
++h;
++p;
continue;
}
if (name[i - 1] == '<') {
--h;
++p;
continue;
}
if (h != 0) {
++p;
continue;
}
if (IsLexeme(name[i - 1]) && h == 0) {
return {&name[i], length - i - (with_template_prefix ? 0 : p)};
}
}
return {name, length - (with_template_prefix ? 0 : p)};
}
inline constexpr cstring NameofType(const char* name, std::size_t length) noexcept {
if (length == 0)
return {name, length};
std::size_t h = 0;
for (std::size_t i = length; i > 0; --i) {
if (h == 0 && (name[i - 1] == '&' || name[i - 1] == '*')) {
continue;
}
if (name[i - 1] == '>') {
++h;
continue;
}
if (name[i - 1] == '<') {
--h;
continue;
}
if (h != 0) {
continue;
}
if (IsLexeme(name[i - 1]) && h == 0) {
return {&name[i], length - i};
}
}
return {name, length};
}
inline constexpr cstring NameofRaw(const char* name, std::size_t length) noexcept {
return {name, length};
} }
} // namespace detail } // namespace detail
inline constexpr const char* Nameof(const char* name, std::size_t length) noexcept { template <typename T,
return ((length == 0) ? name : (detail::IsLexeme(name[length - 1]) typename = typename std::enable_if<!std::is_reference<T>::value &&
? &name[length] !std::is_void<T>::value>::type>
: Nameof(name, length - 1))); inline constexpr detail::cstring Nameof(const T&, const char* name, std::size_t length, bool with_template_prefix) noexcept {
// TODO: conditional expression is constant
if (std::is_function<T>::value || std::is_member_function_pointer<T>::value)
return detail::NameofFunction(name, length, with_template_prefix);
return detail::NameofBase(name, length);
} }
template <typename T, template <typename T,
typename = typename std::enable_if< typename = typename std::enable_if<!std::is_enum<T>::value &&
!std::is_reference<T>::value && !std::is_function<T>::value &&
!std::is_void<T>::value && !std::is_member_function_pointer<T>::value>::type>
!std::is_function<T>::value && inline constexpr detail::cstring Nameof(T&&, const char*, std::size_t) = delete;
!std::is_member_function_pointer<T>::value
>::type>
inline constexpr const char* NameofVariable(const T&, const char* name, std::size_t length) noexcept {
return Nameof(name, length);
}
template <typename T> template <typename T>
inline constexpr const char* NameofVariable(T&&, const char*, std::size_t) = delete; inline constexpr detail::cstring NameofType() {
#if defined(__GNUC__) || defined(__clang__)
constexpr auto function_name = __PRETTY_FUNCTION__;
constexpr auto total_length = sizeof(__PRETTY_FUNCTION__) - 1;
constexpr auto prefix_length = sizeof("nameof::detail::cstring nameof::NameofType() [T = ") - 1;
constexpr auto suffix_length = sizeof("]") - 1;
#elif defined(_MSC_VER)
constexpr auto function_name = __FUNCSIG__;
constexpr auto total_length = sizeof(__FUNCSIG__) - 1;
constexpr auto prefix_length = sizeof("class nameof::detail::cstring __cdecl nameof::NameofType<") - 1;
constexpr auto suffix_length = sizeof(">(void)") - 1;
#endif
constexpr auto type_name = detail::cstring{function_name + prefix_length, total_length - prefix_length - suffix_length};
#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;
if (std::is_class<typename detail::remove_all_pointers<typename std::remove_reference<T>::type>::type>::value) {
if (type_name[0] == 'c') {
if (type_name[class_length] == ' ') {
return detail::cstring{type_name.begin() + class_length + 1, type_name.length() - class_length - 1};
}
return detail::cstring{type_name.begin() + class_length, type_name.length() - class_length};
}
if (type_name[0] == 's') {
if (type_name[struct_length] == ' ') {
return detail::cstring{type_name.begin() + struct_length + 1, type_name.length() - struct_length - 1};
}
return detail::cstring{type_name.begin() + struct_length, type_name.length() - struct_length};
}
}
if (std::is_enum<typename detail::remove_all_pointers<typename std::remove_reference<T>::type>::type>::value) {
if (type_name[0] == 'e') {
if (type_name[enum_length] == ' ') {
return detail::cstring{type_name.begin() + enum_length + 1, type_name.length() - enum_length - 1};
}
return detail::cstring{type_name.begin() + enum_length, type_name.length() - enum_length};
}
}
#endif
return type_name;
}
} // namespace nameof } // namespace nameof
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
// Used to obtain the simple (unqualified) string name of a variable, type, member, function, macros. // Used to obtain the raw string name of a variable, type, member, function, macros.
# define NAMEOF(name) ::nameof::Nameof(#name, (((sizeof(#name) / sizeof(char)) - 1) + (0 * sizeof(void(*)(__typeof__(name)))))) # define NAMEOF_RAW(name) ::nameof::detail::NameofRaw(#name, ((sizeof(#name) / sizeof(char)) - 1) + (0 * sizeof(void (*)(__typeof__(name)))))
// Used to obtain the full string name of a variable, type, member, function, macros.
# define NAMEOF_FULL(name) ::nameof::Nameof(#name, (0 * sizeof(void(*)(__typeof__(name)))))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
// Used to obtain the simple (unqualified) string name of a variable, type, member, function, macros. // Used to obtain the raw string name of a variable, type, member, function, macros.
# define NAMEOF(name) ::nameof::Nameof(#name, (((sizeof(#name) / sizeof(char)) - 1) + (0 * sizeof(typeid(name))))) # define NAMEOF_RAW(name) ::nameof::detail::NameofRaw(#name, ((sizeof(#name) / sizeof(char)) - 1) + (0 * sizeof(typeid(name))))
// Used to obtain the full string name of a variable, type, member, function, macros.
# define NAMEOF_FULL(name) ::nameof::Nameof(#name, (0 * sizeof(typeid(name))))
#endif #endif
// Used to obtain the simple (unqualified) string name of a variable or member. // Used to obtain the simple (unqualified) string name of a variable, member, function.
#define NAMEOF_VARIABLE(name) ::nameof::NameofVariable<decltype(name)>(name, #name, (sizeof(#name) / sizeof(char)) - 1) #define NAMEOF(name) ::nameof::Nameof<decltype(name)>(name, #name, (sizeof(#name) / sizeof(char)) - 1, false)
// Used to obtain the full string name of a variable or member.
#define NAMEOF_VARIABLE_FULL(name) ::nameof::NameofVariable<decltype(name)>(name, #name, 0) #define NAMEOF_T(name) ::nameof::Nameof<decltype(name)>(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<decltype(name)>()

View file

@ -33,18 +33,28 @@
struct SomeStruct { struct SomeStruct {
int somefield = 0; int somefield = 0;
void SomeMethod1(const int i) { void SomeMethod1(const int i) { somefield = i; }
somefield = i;
throw std::exception{};
}
int SomeMethod2() const { int SomeMethod2() const { return somefield; }
throw std::exception{};
return somefield;
}
}; };
void SomeMethod3() { throw std::exception{}; } void SomeMethod3() {
std::cout << NAMEOF(SomeMethod3) << " no called!" << std::endl;
}
template <typename T>
T SomeMethod4() {
return T{};
}
template <typename T>
class SomeClass {
public:
void SomeMethod5() const {}
template <typename C>
C SomeMethod6() const { return C{}; }
};
struct Long { struct Long {
struct LL { struct LL {
@ -57,236 +67,159 @@ enum class Color { RED, GREEN, BLUE };
SomeStruct somevar; SomeStruct somevar;
Long othervar; Long othervar;
int intvar = 0;
SomeStruct* ptrvar = &somevar; SomeStruct* ptrvar = &somevar;
SomeStruct** ptrptrvar = &ptrvar;
TEST_CASE("constexpr") { TEST_CASE("constexpr") {
SECTION("NAMEOF") { SECTION("NAMEOF") {
// variable // variable
constexpr auto cx1 = NAMEOF((&somevar)->somefield); constexpr auto cx1 = NAMEOF(somevar);
REQUIRE(std::strcmp(cx1, "somefield") == 0); static_assert(cx1 == "somevar", "");
// type // member
constexpr auto cx2 = NAMEOF(std::string); constexpr auto cx2 = NAMEOF((&somevar)->somefield);
REQUIRE(std::strcmp(cx2, "string") == 0); static_assert(cx2 == "somefield", "");
// function // function
constexpr auto cx3 = NAMEOF(&SomeStruct::SomeMethod2); constexpr auto cx3 = NAMEOF(&SomeStruct::SomeMethod2);
REQUIRE(std::strcmp(cx3, "SomeMethod2") == 0); static_assert(cx3 == "SomeMethod2", "");
// enum // enum
constexpr auto cx4 = NAMEOF(Color::RED); constexpr auto cx4 = NAMEOF(Color::RED);
REQUIRE(std::strcmp(cx4, "RED") == 0); static_assert(cx4 == "RED", "");
// macros
constexpr auto cx5 = NAMEOF(__cplusplus);
REQUIRE(std::strcmp(cx5, "__cplusplus") == 0);
} }
SECTION("NAMEOF_FULL") { SECTION("NAMEOF_RAW") {
// variable // variable
constexpr auto cx1 = NAMEOF_FULL((&somevar)->somefield); constexpr auto cx1 = NAMEOF_RAW(somevar);
REQUIRE(std::strcmp(cx1, "(&somevar)->somefield") == 0); static_assert(cx1 == "somevar", "");
// member
constexpr auto cx2 = NAMEOF_RAW((&somevar)->somefield);
static_assert(cx2 == "(&somevar)->somefield", "");
// type // type
constexpr auto cx2 = NAMEOF_FULL(std::string); constexpr auto cx3 = NAMEOF_RAW(std::string);
REQUIRE(std::strcmp(cx2, "std::string") == 0); static_assert(cx3 == "std::string", "");
// function // function
constexpr auto cx3 = NAMEOF_FULL(&SomeStruct::SomeMethod2); constexpr auto cx4 = NAMEOF_RAW(&SomeStruct::SomeMethod2);
REQUIRE(std::strcmp(cx3, "&SomeStruct::SomeMethod2") == 0); static_assert(cx4 == "&SomeStruct::SomeMethod2", "");
// enum // enum
constexpr auto cx4 = NAMEOF_FULL(Color::RED); constexpr auto cx5 = NAMEOF_RAW(Color::RED);
REQUIRE(std::strcmp(cx4, "Color::RED") == 0); static_assert(cx5 == "Color::RED", "");
// macros // macros
constexpr auto cx5 = NAMEOF_FULL(__cplusplus); constexpr auto cx6 = NAMEOF_RAW(__cplusplus);
REQUIRE(std::strcmp(cx5, "__cplusplus") == 0); static_assert(cx6 == "__cplusplus", "");
} }
#if !defined(_MSC_VER) || _MSC_VER > 1910
SECTION("NAMEOF_VARIABLE") {
constexpr auto cx1 = NAMEOF_VARIABLE((&somevar)->somefield);
REQUIRE(std::strcmp(cx1, "somefield") == 0);
}
SECTION("NAMEOF_VARIABLE_FULL") {
constexpr auto cx1 = NAMEOF_VARIABLE_FULL((&somevar)->somefield);
REQUIRE(std::strcmp(cx1, "(&somevar)->somefield") == 0);
}
#endif
} }
TEST_CASE("simple name") { TEST_CASE("simple name") {
SECTION("variable") { SECTION("variable") {
REQUIRE(std::strcmp(NAMEOF(somevar), "somevar") == 0); REQUIRE(NAMEOF(somevar) == "somevar");
REQUIRE(std::strcmp(NAMEOF(&somevar), "somevar") == 0); REQUIRE(NAMEOF(::somevar) == "somevar");
REQUIRE(std::strcmp(NAMEOF(::somevar), "somevar") == 0); REQUIRE(NAMEOF(ptrvar) == "ptrvar");
REQUIRE(std::strcmp(NAMEOF(somevar.somefield), "somefield") == 0);
REQUIRE(std::strcmp(NAMEOF((&somevar)->somefield), "somefield") == 0);
REQUIRE(std::strcmp(NAMEOF(othervar.ll.field), "field") == 0);
REQUIRE(std::strcmp(NAMEOF(ptrvar), "ptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF(*ptrvar), "ptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF(ptrptrvar), "ptrptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF(*ptrptrvar), "ptrptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF(**ptrptrvar), "ptrptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF(+intvar), "intvar") == 0);
REQUIRE(std::strcmp(NAMEOF(-intvar), "intvar") == 0);
REQUIRE(std::strcmp(NAMEOF(~intvar), "intvar") == 0);
REQUIRE(std::strcmp(NAMEOF(!intvar), "intvar") == 0);
} }
SECTION("type") { SECTION("member") {
REQUIRE(std::strcmp(NAMEOF(int[]), "int[]") == 0); REQUIRE(NAMEOF(somevar.somefield) == "somefield");
REQUIRE(std::strcmp(NAMEOF(int), "int") == 0); REQUIRE(NAMEOF((&somevar)->somefield) == "somefield");
REQUIRE(std::strcmp(NAMEOF(const volatile int[]), "const volatile int[]") == 0); REQUIRE(NAMEOF(othervar.ll.field) == "field");
REQUIRE(std::strcmp(NAMEOF(std::string), "string") == 0);
REQUIRE(std::strcmp(NAMEOF(SomeStruct), "SomeStruct") == 0);
REQUIRE(std::strcmp(NAMEOF(Long::LL), "LL") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(Color), "Color") == 0);
} }
SECTION("function") { SECTION("function") {
REQUIRE(std::strcmp(NAMEOF(&SomeStruct::SomeMethod2), "SomeMethod2") == 0); REQUIRE(NAMEOF(&SomeStruct::SomeMethod1) == "SomeMethod1");
REQUIRE(std::strcmp(NAMEOF(SomeMethod3), "SomeMethod3") == 0); REQUIRE(NAMEOF(&SomeStruct::SomeMethod2) == "SomeMethod2");
REQUIRE(NAMEOF(SomeMethod3) == "SomeMethod3");
REQUIRE(NAMEOF(SomeMethod4<int>) == "SomeMethod4");
REQUIRE(NAMEOF(&SomeClass<int>::SomeMethod5) == "SomeMethod5");
REQUIRE(NAMEOF(&SomeClass<int>::SomeMethod6<long int>) == "SomeMethod6");
} }
SECTION("enum") { SECTION("enum") {
REQUIRE(std::strcmp(NAMEOF(Color::RED), "RED") == 0); REQUIRE(NAMEOF(Color::RED) == "RED");
REQUIRE(std::strcmp(NAMEOF(Color::BLUE), "BLUE") == 0); REQUIRE(NAMEOF(Color::BLUE) == "BLUE");
}
SECTION("macros") {
REQUIRE(std::strcmp(NAMEOF(__cplusplus), "__cplusplus") == 0);
REQUIRE(std::strcmp(NAMEOF(__LINE__), "__LINE__") == 0);
REQUIRE(std::strcmp(NAMEOF(__FILE__), "__FILE__") == 0);
} }
} }
TEST_CASE("raw name") {
TEST_CASE("full name") {
SECTION("variable") { SECTION("variable") {
REQUIRE(std::strcmp(NAMEOF_FULL(somevar), "somevar") == 0); REQUIRE(NAMEOF_RAW(somevar) == "somevar");
REQUIRE(std::strcmp(NAMEOF_FULL(&somevar), "&somevar") == 0); REQUIRE(NAMEOF_RAW(&somevar) == "&somevar");
REQUIRE(std::strcmp(NAMEOF_FULL(::somevar), "::somevar") == 0); REQUIRE(NAMEOF_RAW(::somevar) == "::somevar");
REQUIRE(NAMEOF_RAW(ptrvar) == "ptrvar");
REQUIRE(std::strcmp(NAMEOF_FULL(somevar.somefield), "somevar.somefield") == 0); REQUIRE(NAMEOF_RAW(*ptrvar) == "*ptrvar");
REQUIRE(std::strcmp(NAMEOF_FULL((&somevar)->somefield), "(&somevar)->somefield") == 0); REQUIRE(NAMEOF_RAW(+somevar.somefield) == "+somevar.somefield");
REQUIRE(NAMEOF_RAW(-somevar.somefield) == "-somevar.somefield");
REQUIRE(std::strcmp(NAMEOF_FULL(othervar.ll.field), "othervar.ll.field") == 0); REQUIRE(NAMEOF_RAW(~somevar.somefield) == "~somevar.somefield");
REQUIRE(NAMEOF_RAW(!somevar.somefield) == "!somevar.somefield");
REQUIRE(std::strcmp(NAMEOF_FULL(ptrvar), "ptrvar") == 0); }
REQUIRE(std::strcmp(NAMEOF_FULL(*ptrvar), "*ptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(ptrptrvar), "ptrptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(*ptrptrvar), "*ptrptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(**ptrptrvar), "**ptrptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(+intvar), "+intvar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(-intvar), "-intvar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(~intvar), "~intvar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(!intvar), "!intvar") == 0);
SECTION("member") {
REQUIRE(NAMEOF_RAW(somevar.somefield) == "somevar.somefield");
REQUIRE(NAMEOF_RAW((&somevar)->somefield) == "(&somevar)->somefield");
REQUIRE(NAMEOF_RAW(othervar.ll.field) == "othervar.ll.field");
} }
SECTION("type") { SECTION("type") {
REQUIRE(std::strcmp(NAMEOF_FULL(int[]), "int[]") == 0); REQUIRE(NAMEOF_RAW(int[]) == "int[]");
REQUIRE(std::strcmp(NAMEOF_FULL(int), "int") == 0); REQUIRE(NAMEOF_RAW(int) == "int");
REQUIRE(std::strcmp(NAMEOF_FULL(const volatile int[]), "const volatile int[]") == 0); REQUIRE(NAMEOF_RAW(const volatile int[]) == "const volatile int[]");
REQUIRE(std::strcmp(NAMEOF_FULL(std::string), "std::string") == 0); REQUIRE(NAMEOF_RAW(std::string) == "std::string");
REQUIRE(NAMEOF_RAW(SomeStruct) == "SomeStruct");
REQUIRE(std::strcmp(NAMEOF_FULL(SomeStruct), "SomeStruct") == 0); REQUIRE(NAMEOF_RAW(Long::LL) == "Long::LL");
REQUIRE(std::strcmp(NAMEOF_FULL(Long::LL), "Long::LL") == 0); REQUIRE(NAMEOF_RAW(Color) == "Color");
REQUIRE(std::strcmp(NAMEOF_FULL(Color), "Color") == 0);
} }
SECTION("function") { SECTION("function") {
REQUIRE(std::strcmp(NAMEOF_FULL(&SomeStruct::SomeMethod2), "&SomeStruct::SomeMethod2") == 0); REQUIRE(NAMEOF_RAW(&SomeStruct::SomeMethod1) == "&SomeStruct::SomeMethod1");
REQUIRE(std::strcmp(NAMEOF_FULL(SomeMethod3), "SomeMethod3") == 0); REQUIRE(NAMEOF_RAW(&SomeStruct::SomeMethod2) == "&SomeStruct::SomeMethod2");
REQUIRE(NAMEOF_RAW(SomeMethod3) == "SomeMethod3");
REQUIRE(NAMEOF_RAW(SomeMethod4<int>) == "SomeMethod4<int>");
REQUIRE(NAMEOF_RAW(&SomeClass<int>::SomeMethod5) == "&SomeClass<int>::SomeMethod5");
REQUIRE(NAMEOF_RAW(&SomeClass<int>::SomeMethod6<int>) == "&SomeClass<int>::SomeMethod6<int>");
} }
SECTION("enum") { SECTION("enum") {
REQUIRE(std::strcmp(NAMEOF_FULL(Color::RED), "Color::RED") == 0); REQUIRE(NAMEOF_RAW(Color::RED) == "Color::RED");
REQUIRE(std::strcmp(NAMEOF_FULL(Color::BLUE), "Color::BLUE") == 0); REQUIRE(NAMEOF_RAW(Color::BLUE) == "Color::BLUE");
} }
SECTION("macros") { SECTION("macros") {
REQUIRE(std::strcmp(NAMEOF_FULL(__cplusplus), "__cplusplus") == 0); REQUIRE(NAMEOF_RAW(__cplusplus) == "__cplusplus");
REQUIRE(std::strcmp(NAMEOF_FULL(__LINE__), "__LINE__") == 0); REQUIRE(NAMEOF_RAW(__LINE__) == "__LINE__");
REQUIRE(std::strcmp(NAMEOF_FULL(__FILE__), "__FILE__") == 0); REQUIRE(NAMEOF_RAW(__FILE__) == "__FILE__");
} }
} }
TEST_CASE("Spaces and Tabs ignored") { TEST_CASE("Spaces and Tabs ignored") {
SECTION("Spaces") { SECTION("Spaces") {
// variable // variable
REQUIRE(std::strcmp(NAMEOF_VARIABLE( (&somevar)->somefield ), "somefield") == 0); REQUIRE(NAMEOF( somevar ) == "somevar");
REQUIRE(std::strcmp(NAMEOF_FULL( (&somevar)->somefield ), "(&somevar)->somefield") == 0); REQUIRE(NAMEOF_RAW( somevar ) == "somevar");
// member
REQUIRE(std::strcmp(NAMEOF_VARIABLE( (&somevar)->somefield ), "somefield") == 0); REQUIRE(NAMEOF( (&somevar)->somefield ) == "somefield");
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL( (&somevar)->somefield ), "(&somevar)->somefield") == 0); REQUIRE(NAMEOF_RAW( (&somevar)->somefield ) == "(&somevar)->somefield");
// type // type
REQUIRE(std::strcmp(NAMEOF( std::string ), "string") == 0); REQUIRE(NAMEOF_RAW( std::string ) == "std::string");
REQUIRE(std::strcmp(NAMEOF_FULL( std::string ), "std::string") == 0);
// function // function
REQUIRE(std::strcmp(NAMEOF( &SomeStruct::SomeMethod2 ), "SomeMethod2") == 0); REQUIRE(NAMEOF( &SomeStruct::SomeMethod2 ) == "SomeMethod2");
REQUIRE(std::strcmp(NAMEOF_FULL( &SomeStruct::SomeMethod2 ), "&SomeStruct::SomeMethod2") == 0); REQUIRE(NAMEOF_RAW( &SomeStruct::SomeMethod2 ) == "&SomeStruct::SomeMethod2");
// enum // enum
REQUIRE(std::strcmp(NAMEOF( Color::RED ), "RED") == 0); REQUIRE(NAMEOF( Color::RED ) == "RED");
REQUIRE(std::strcmp(NAMEOF_FULL( Color::RED ), "Color::RED") == 0); REQUIRE(NAMEOF_RAW( Color::RED ) == "Color::RED");
// macros // macros
REQUIRE(std::strcmp(NAMEOF( __cplusplus ), "__cplusplus") == 0); REQUIRE(NAMEOF_RAW( __cplusplus ) == "__cplusplus");
REQUIRE(std::strcmp(NAMEOF_FULL( __cplusplus ), "__cplusplus") == 0);
} }
SECTION("Tabs") { SECTION("Tabs") {
// variable // variable
REQUIRE(std::strcmp(NAMEOF_VARIABLE( (&somevar)->somefield ), "somefield") == 0); REQUIRE(NAMEOF( somevar ) == "somevar");
REQUIRE(std::strcmp(NAMEOF_FULL( (&somevar)->somefield ), "(&somevar)->somefield") == 0); REQUIRE(NAMEOF_RAW( somevar ) == "somevar");
// member
REQUIRE(std::strcmp(NAMEOF_VARIABLE( (&somevar)->somefield ), "somefield") == 0); REQUIRE(NAMEOF( (&somevar)->somefield ) == "somefield");
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL( (&somevar)->somefield ), "(&somevar)->somefield") == 0); REQUIRE(NAMEOF_RAW( (&somevar)->somefield ) == "(&somevar)->somefield");
// type // type
REQUIRE(std::strcmp(NAMEOF( std::string ), "string") == 0); REQUIRE(NAMEOF_RAW( std::string ) == "std::string");
REQUIRE(std::strcmp(NAMEOF_FULL( std::string ), "std::string") == 0);
// function // function
REQUIRE(std::strcmp(NAMEOF( &SomeStruct::SomeMethod2 ), "SomeMethod2") == 0); REQUIRE(NAMEOF( &SomeStruct::SomeMethod2 ) == "SomeMethod2");
REQUIRE(std::strcmp(NAMEOF_FULL( &SomeStruct::SomeMethod2 ), "&SomeStruct::SomeMethod2") == 0); REQUIRE(NAMEOF_RAW( &SomeStruct::SomeMethod2 ) == "&SomeStruct::SomeMethod2");
// enum // enum
REQUIRE(std::strcmp(NAMEOF( Color::RED ), "RED") == 0); REQUIRE(NAMEOF( Color::RED ) == "RED");
REQUIRE(std::strcmp(NAMEOF_FULL( Color::RED ), "Color::RED") == 0); REQUIRE(NAMEOF_RAW( Color::RED ) == "Color::RED");
// macros // macros
REQUIRE(std::strcmp(NAMEOF( __cplusplus ), "__cplusplus") == 0); REQUIRE(NAMEOF_RAW( __cplusplus ) == "__cplusplus");
REQUIRE(std::strcmp(NAMEOF_FULL( __cplusplus ), "__cplusplus") == 0);
}
}
TEST_CASE("variable name") {
SECTION("simple") {
REQUIRE(std::strcmp(NAMEOF_VARIABLE(somevar), "somevar") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE(::somevar), "somevar") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE(somevar.somefield), "somefield") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE((&somevar)->somefield), "somefield") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE(othervar.ll.field), "field") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE(ptrvar), "ptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE(ptrptrvar), "ptrptrvar") == 0);
}
SECTION("full name") {
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL(somevar), "somevar") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL(::somevar), "::somevar") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL(somevar.somefield), "somevar.somefield") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL((&somevar)->somefield), "(&somevar)->somefield") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL(othervar.ll.field), "othervar.ll.field") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL(ptrvar), "ptrvar") == 0);
REQUIRE(std::strcmp(NAMEOF_VARIABLE_FULL(ptrptrvar), "ptrptrvar") == 0);
} }
} }