add nameof enum

This commit is contained in:
Neargye 2018-09-01 18:27:49 +05:00
parent edc3ba588d
commit ddc79d8d3e
4 changed files with 107 additions and 9 deletions

View file

@ -44,6 +44,8 @@ NAMEOF(SomeMethod<int, float>) -> "SomeMethod"
NAMEOF_FULL(SomeMethod<int, float>) -> "SomeMethod4<int, float>" NAMEOF_FULL(SomeMethod<int, float>) -> "SomeMethod4<int, float>"
// Name of enum // Name of enum
NAMEOF(SomeEnum::RED) -> "RED" NAMEOF(SomeEnum::RED) -> "RED"
SomeEnum e = SomeEnum::RED;
NAMEOF_ENUM(e) -> "RED"
// Name of type // Name of type
NAMEOF_TYPE(SomeEnum::RED) -> "SomeEnum" NAMEOF_TYPE(SomeEnum::RED) -> "SomeEnum"
NAMEOF_TYPE_T(int) -> "int" NAMEOF_TYPE_T(int) -> "int"

View file

@ -86,10 +86,12 @@ int main() {
constexpr auto constexpr_work_fine = NAMEOF(structvar); constexpr auto constexpr_work_fine = NAMEOF(structvar);
static_assert("structvar" == constexpr_work_fine, ""); static_assert("structvar" == constexpr_work_fine, "");
std::cout << SomeMethod4<int>(structvar) << std::endl; // SomeMethod4<int>(SomeStruct value)
// Enum name. // Enum name.
std::cout << NAMEOF(Color::RED) << std::endl; // RED 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
// Variable name. // Variable name.
std::cout << NAMEOF(structvar) << std::endl; // structvar std::cout << NAMEOF(structvar) << std::endl; // structvar
@ -129,6 +131,8 @@ int main() {
std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // structvar.somefield std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // structvar.somefield
std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // &SomeStruct::SomeMethod1 std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // &SomeStruct::SomeMethod1
std::cout << SomeMethod4<int>(structvar) << std::endl; // SomeMethod4<int>(SomeStruct value)
const auto div = [](int x, int y) -> int { const auto div = [](int x, int y) -> int {
if (y == 0) { if (y == 0) {
throw std::invalid_argument(std::string(NAMEOF(y)).append(" should not be zero!")); throw std::invalid_argument(std::string(NAMEOF(y)).append(" should not be zero!"));

View file

@ -297,12 +297,12 @@ constexpr cstring RemovePrefix(cstring name, const std::size_t p = 0) {
: RemovePrefix(name, p + 1); : RemovePrefix(name, p + 1);
} }
constexpr cstring NameofPrettyImpl_(cstring name, std::size_t s, bool with_suffix) { constexpr cstring NameofPrettyImpl1(cstring name, std::size_t s, bool with_suffix) {
return RemovePrefix(name.remove_suffix(s)).add_suffix(with_suffix ? s : 0); return RemovePrefix(name.remove_suffix(s)).add_suffix(with_suffix ? s : 0);
} }
constexpr cstring NameofPrettyImpl(cstring name, bool with_suffix) { constexpr cstring NameofPrettyImpl(cstring name, bool with_suffix) {
return NameofPrettyImpl_(name, FindSuffix(name), with_suffix); return NameofPrettyImpl1(name, FindSuffix(name), with_suffix);
} }
constexpr cstring NameofPretty(cstring name, bool with_suffix) { constexpr cstring NameofPretty(cstring name, bool with_suffix) {
@ -346,6 +346,55 @@ constexpr cstring NameofTypePretty(const char* str, std::size_t size, std::size_
} }
#endif #endif
template <typename T>
constexpr int NameofEnumImpl1() {
#if defined(__clang__)
return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::NameofEnumImpl1() [T = ") - sizeof("]") + 1;
#elif defined(__GNUC__)
return sizeof(__PRETTY_FUNCTION__) - sizeof("constexpr int nameof::detail::NameofEnumImpl1() [with T = ") - sizeof("]") + 1;
#elif defined(_MSC_VER)
return sizeof(__FUNCSIG__) - sizeof("int __cdecl nameof::detail::NameofEnumImpl1<") - sizeof(">(void)") + 1;
#else
return 0;
#endif
}
template <typename T, T V>
constexpr nameof::cstring NameofEnumImpl2() {
#if defined(__clang__)
return {__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1,
sizeof("nameof::cstring nameof::detail::NameofEnumImpl2() [T = ") + NameofEnumImpl1<T>() + sizeof("; V = ") - 2,
sizeof("]") - 1};
#elif defined(__GNUC__)
return {__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1,
sizeof("constexpr nameof::cstring nameof::detail::NameofEnumImpl2() [with T = ") + NameofEnumImpl1<T>() + sizeof("; T V = ") - 2,
sizeof("]") - 1};
#elif defined(_MSC_VER)
return {__FUNCSIG__,
sizeof(__FUNCSIG__) - 1,
sizeof("class nameof::cstring __cdecl nameof::detail::NameofEnumImpl2<") + NameofEnumImpl1<T>(),
sizeof(">(void)") - 1};
#else
return {};
#endif
}
template <typename T, int I = 0>
struct NameofEnumImpl {
constexpr nameof::cstring operator()(T value) const noexcept {
return (static_cast<int>(value) - I == 0)
? NameofEnumImpl2<T, T(0 + I)>()
: NameofEnumImpl<T, I + 1>{}(value);
}
};
template <typename T>
struct NameofEnumImpl<T, 128> {
constexpr nameof::cstring operator()(T) const noexcept { return {}; }
};
template <typename T> template <typename T>
NAMEOF_TYPE_CONSTEXPR cstring NameofType() { NAMEOF_TYPE_CONSTEXPR cstring NameofType() {
#if defined(__clang__) #if defined(__clang__)
@ -383,6 +432,12 @@ constexpr cstring Nameof(const char* name, std::size_t size, bool with_suffix =
return detail::NameofPretty({name, size}, with_suffix); return detail::NameofPretty({name, size}, with_suffix);
} }
template <typename T,
typename = typename std::enable_if<!std::is_reference<T>::value && std::is_enum<T>::value>::type>
constexpr cstring NameofEnum(T value) {
return detail::NameofPretty(detail::NameofEnumImpl<T>{}(value), false);
}
template <typename T> template <typename T>
NAMEOF_TYPE_CONSTEXPR cstring NameofType() { NAMEOF_TYPE_CONSTEXPR cstring NameofType() {
return true ? detail::NameofType<detail::nstd::identity<T>>() : detail::NameofType<detail::nstd::identity<T>>(); return true ? detail::NameofType<detail::nstd::identity<T>>() : detail::NameofType<detail::nstd::identity<T>>();
@ -395,15 +450,16 @@ constexpr cstring NameofRaw(const char* name, std::size_t size) {
} // namespace nameof } // namespace nameof
// Used to obtain the simple (unqualified) string name of a variable, member, function, macros. // 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__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1, false)
// Used to obtain the full string name of a variable, member, function, enum, macros.
// Used to obtain the full string name of a variable, member, function, 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__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1, true)
// Used to obtain the raw string name of a variable, member, function, enum, macros.
// Used to obtain the raw string name of a variable, member, function, macros.
#define NAMEOF_RAW(...) ::nameof::NameofRaw<decltype(__VA_ARGS__)>(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1) #define NAMEOF_RAW(...) ::nameof::NameofRaw<decltype(__VA_ARGS__)>(#__VA_ARGS__, (sizeof(#__VA_ARGS__) / sizeof(char)) - 1)
// Used to obtain the simple (unqualified) string name of a enum variable.
#define NAMEOF_ENUM(...) ::nameof::NameofEnum<decltype(__VA_ARGS__)>(__VA_ARGS__)
// Used to obtain the string name of a type. // Used to obtain the string name of a type.
#define NAMEOF_TYPE(...) ::nameof::NameofType<decltype(__VA_ARGS__)>() #define NAMEOF_TYPE(...) ::nameof::NameofType<decltype(__VA_ARGS__)>()
#define NAMEOF_TYPE_T(...) ::nameof::NameofType<__VA_ARGS__>() #define NAMEOF_TYPE_T(...) ::nameof::NameofType<__VA_ARGS__>()

View file

@ -70,6 +70,8 @@ struct Long {
enum class Color { RED, GREEN, BLUE }; enum class Color { RED, GREEN, BLUE };
enum Directions { Up, Down, Right, Left};
SomeStruct struct_var; SomeStruct struct_var;
Long othervar; Long othervar;
SomeStruct * ptr_s = &struct_var; SomeStruct * ptr_s = &struct_var;
@ -78,6 +80,9 @@ SomeStruct & ref_s = struct_var;
SomeClass<int> class_var; SomeClass<int> class_var;
const SomeClass<int> volatile * ptr_c = nullptr; const SomeClass<int> volatile * ptr_c = nullptr;
const Color color = Color::RED;
const Directions directions = Directions::Right;
TEST_CASE("constexpr") { TEST_CASE("constexpr") {
SECTION("NAMEOF") { SECTION("NAMEOF") {
// variable // variable
@ -140,6 +145,17 @@ TEST_CASE("constexpr") {
REQUIRE(cx6 == "__cplusplus"); REQUIRE(cx6 == "__cplusplus");
} }
SECTION("NAMEOF_ENUM") {
constexpr auto cx = NAMEOF_ENUM(color);
# if defined(__clang__) || defined(_MSC_VER)
static_assert(cx == "RED", "");
REQUIRE(cx == "RED");
# elif defined(__GNUC__)
//static_assert(cx == "(Color)0", "");
REQUIRE(cx == "(Color)0");
# endif
}
#if defined(NAMEOF_TYPE_HAS_CONSTEXPR) #if defined(NAMEOF_TYPE_HAS_CONSTEXPR)
SECTION("NAMEOF_TYPE") { SECTION("NAMEOF_TYPE") {
constexpr auto cx = NAMEOF_TYPE(ptr_c); constexpr auto cx = NAMEOF_TYPE(ptr_c);
@ -290,6 +306,22 @@ TEST_CASE("NAMEOF_RAW") {
} }
} }
TEST_CASE("NAMEOF_ENUM") {
# if defined(__clang__) || defined(_MSC_VER)
REQUIRE(NAMEOF_ENUM(Color::RED) == "RED");
REQUIRE(NAMEOF_ENUM(color) == "RED");
REQUIRE(NAMEOF_ENUM(Directions::Right) == "Right");
REQUIRE(NAMEOF_ENUM(directions) == "Right");
# elif defined(__GNUC__)
REQUIRE(NAMEOF_ENUM(Color::RED) == "(Color)0");
REQUIRE(NAMEOF_ENUM(color) == "0");
REQUIRE(NAMEOF_ENUM(Directions::Right) == "2");
REQUIRE(NAMEOF_ENUM(directions) == "2");
# endif
}
TEST_CASE("NAMEOF_TYPE") { TEST_CASE("NAMEOF_TYPE") {
#if defined(__clang__) #if defined(__clang__)
REQUIRE(NAMEOF_TYPE(struct_var) == "SomeStruct"); REQUIRE(NAMEOF_TYPE(struct_var) == "SomeStruct");
@ -397,6 +429,8 @@ TEST_CASE("Spaces and Tabs ignored") {
REQUIRE(NAMEOF_FULL( struct_var ) == "struct_var"); REQUIRE(NAMEOF_FULL( struct_var ) == "struct_var");
REQUIRE(NAMEOF_RAW( struct_var ) == "struct_var"); REQUIRE(NAMEOF_RAW( struct_var ) == "struct_var");
REQUIRE(NAMEOF_ENUM( color ) == "RED");
REQUIRE(NAMEOF_TYPE( struct_var ) == "SomeStruct"); REQUIRE(NAMEOF_TYPE( struct_var ) == "SomeStruct");
REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct"); REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct");
} }
@ -406,6 +440,8 @@ TEST_CASE("Spaces and Tabs ignored") {
REQUIRE(NAMEOF_FULL( struct_var ) == "struct_var"); REQUIRE(NAMEOF_FULL( struct_var ) == "struct_var");
REQUIRE(NAMEOF_RAW( struct_var ) == "struct_var"); REQUIRE(NAMEOF_RAW( struct_var ) == "struct_var");
REQUIRE(NAMEOF_ENUM( color ) == "RED");
REQUIRE(NAMEOF_TYPE( struct_var ) == "SomeStruct"); REQUIRE(NAMEOF_TYPE( struct_var ) == "SomeStruct");
REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct"); REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct");
} }