This commit is contained in:
neargye 2019-03-22 15:09:13 +05:00
parent 16f010ef08
commit 68ad4fba4e
5 changed files with 43 additions and 35 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.6) cmake_minimum_required(VERSION 3.6)
project(nameof VERSION "0.6.1" LANGUAGES CXX) project(nameof VERSION "0.6.2" LANGUAGES CXX)
option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ON) option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ON)
option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ON) option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ON)

View file

@ -15,7 +15,7 @@ master |[![Build Status](https://travis-ci.org/Neargye/nameof.svg?branch=master)
## What is Nameof? ## What is Nameof?
Header-only C++17 library provides nameof macros and functions to obtain the simple name of variable, type, function, macro, and enum. Header-only C++17 library provides nameof macros and functions to obtain simple name of variable, type, function, macro, and enum.
Before, you had to use string literals to refer to definitions, which is brittle when renaming code elements because tools do not know to check these string literals. Before, you had to use string literals to refer to definitions, which is brittle when renaming code elements because tools do not know to check these string literals.
@ -56,9 +56,9 @@ static_assert("foo" == cx_name);
* Name of enum * Name of enum
```cpp ```cpp
// Name of enum // Name of enum
const auto c = Color::RED; auto c = Color::RED;
NAMEOF_ENUM(c) -> "RED" NAMEOF_ENUM(c) -> "RED"
// Name of enum function // Name of enum
nameof::nameof_enum(c) -> "RED" nameof::nameof_enum(c) -> "RED"
constexpr auto cx_name = NAMEOF_ENUM(c); constexpr auto cx_name = NAMEOF_ENUM(c);
@ -71,9 +71,9 @@ static_assert("RED" == cx_name);
NAMEOF_TYPE(Color::RED) -> "Color" NAMEOF_TYPE(Color::RED) -> "Color"
// Name of type // Name of type
NAMEOF_TYPE_T(int) -> "int" NAMEOF_TYPE_T(int) -> "int"
// Name of variable type function // Name of variable type
nameof::nameof_type(Color::RED) -> "Color" nameof::nameof_type(Color::RED) -> "Color"
// Name of type function // Name of type
nameof::nameof_type<int> -> "int" nameof::nameof_type<int> -> "int"
constexpr auto cx_name = NAMEOF_TYPE(Color::RED); constexpr auto cx_name = NAMEOF_TYPE(Color::RED);
@ -82,6 +82,7 @@ static_assert("Color" == cx_name);
* Name of macro * Name of macro
```cpp ```cpp
// Name of macro
NAMEOF(__LINE__) -> "__LINE__" NAMEOF(__LINE__) -> "__LINE__"
constexpr auto cx_name = NAMEOF(__LINE__); constexpr auto cx_name = NAMEOF(__LINE__);
@ -92,12 +93,13 @@ static_assert("__LINE__" == cx_name);
* Nameof return std::string_view. * Nameof return std::string_view.
* The argument expression identifies a code definition, but it is never evaluated. * The argument expression identifies code definition, but it is never evaluated.
* If you need raw fully-qualified name, use NAMEOF_RAW. * If you need raw fully-qualified name, use NAMEOF_RAW.
```cpp ```cpp
NAMEOF_RAW(somevar.somefield) -> "somevar.somefield" NAMEOF_RAW(somevar.somefield) -> "somevar.somefield"
NAMEOF_RAW(&SomeStruct::SomeMethod) -> "&SomeStruct::SomeMethod" NAMEOF_RAW(&SomeStruct::SomeMethod) -> "&SomeStruct::SomeMethod"
NAMEOF_RAW(std::string) -> "std::string"
``` ```
* NAMEOF_ENUM does not work on the GCC. * NAMEOF_ENUM does not work on the GCC.
@ -122,6 +124,6 @@ You should add required file [nameof.hpp](include/nameof.hpp).
* Clang/LLVM >= 5 * Clang/LLVM >= 5
* MSVC >= 15.3 / Visual Studio 2017 * MSVC >= 15.3 / Visual Studio 2017
* Xcode >= 9 * Xcode >= 9
* GCC >= 7 (NAMEOF_ENUM not support) * GCC >= 7
## Licensed under the [MIT License](LICENSE) ## Licensed under the [MIT License](LICENSE)

View file

@ -130,6 +130,7 @@ int main() {
std::cout << NAMEOF_RAW(__LINE__) << std::endl; // __LINE__ std::cout << NAMEOF_RAW(__LINE__) << std::endl; // __LINE__
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 << NAMEOF_RAW(const SomeClass<int> volatile *) << std::endl; // const SomeClass<int> volatile *
// Some more example. // Some more example.

View file

@ -5,7 +5,7 @@
// | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_| // | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_|
// |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____| // |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____|
// https://github.com/Neargye/nameof // https://github.com/Neargye/nameof
// vesion 0.6.1 // vesion 0.6.2
// //
// Licensed under the MIT License <http://opensource.org/licenses/MIT>. // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
@ -44,19 +44,19 @@ namespace nameof {
namespace detail { namespace detail {
template <typename T> template <typename T>
struct identity { struct identity final {
using type = T; using type = T;
}; };
constexpr bool is_name_char(char s) noexcept { [[nodiscard]] constexpr bool is_name_char(char s) noexcept {
return (s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || s == '_'; return (s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || s == '_';
} }
constexpr bool is_bracket_char(char s) noexcept { [[nodiscard]] constexpr bool is_bracket_char(char s) noexcept {
return s == ')' || s == '}' || s == '>' || s == '(' || s == '{' || s == '<'; return s == ')' || s == '}' || s == '>' || s == '(' || s == '{' || s == '<';
} }
constexpr std::string_view pretty_name(std::string_view name, bool with_suffix) noexcept { [[nodiscard]] constexpr std::string_view pretty_name(std::string_view name, bool with_suffix) noexcept {
for (std::size_t i = name.size(), h = 0, s = 0; i > 0; --i) { for (std::size_t i = name.size(), h = 0, s = 0; i > 0; --i) {
if (h == 0 && !is_name_char(name[i - 1]) && !is_bracket_char(name[i - 1])) { if (h == 0 && !is_name_char(name[i - 1]) && !is_bracket_char(name[i - 1])) {
++s; ++s;
@ -114,7 +114,7 @@ constexpr std::string_view pretty_name(std::string_view name, bool with_suffix)
} }
template <typename E> template <typename E>
constexpr int nameof_enum_impl_() noexcept { [[nodiscard]] constexpr int nameof_enum_impl_() noexcept {
#if defined(__clang__) #if defined(__clang__)
return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::nameof_enum_impl_() [E = ") - sizeof("]") + 1; return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::nameof_enum_impl_() [E = ") - sizeof("]") + 1;
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -127,7 +127,7 @@ constexpr int nameof_enum_impl_() noexcept {
} }
template <typename E, E V> template <typename E, E V>
constexpr std::string_view nameof_enum_impl() noexcept { [[nodiscard]] constexpr std::string_view nameof_enum_impl() noexcept {
#if defined(__clang__) #if defined(__clang__)
const auto str = __PRETTY_FUNCTION__; const auto str = __PRETTY_FUNCTION__;
const auto size = sizeof(__PRETTY_FUNCTION__) - 1; const auto size = sizeof(__PRETTY_FUNCTION__) - 1;
@ -152,8 +152,8 @@ constexpr std::string_view nameof_enum_impl() noexcept {
} }
template <typename E, int V> template <typename E, int V>
struct nameof_enum_t { struct nameof_enum_t final {
constexpr std::string_view operator()(int value) const noexcept { [[nodiscard]] constexpr std::string_view operator()(int value) const noexcept {
switch (value - V) { switch (value - V) {
case 0: case 0:
return nameof_enum_impl<E, E{V}>(); return nameof_enum_impl<E, E{V}>();
@ -178,13 +178,13 @@ struct nameof_enum_t {
}; };
template <typename E> template <typename E>
struct nameof_enum_t<E, NAMEOF_ENUM_MAX_SEARCH_DEPTH> { struct nameof_enum_t<E, NAMEOF_ENUM_MAX_SEARCH_DEPTH> final {
constexpr std::string_view operator()(int) const noexcept { [[nodiscard]] constexpr std::string_view operator()(int) const noexcept {
return {"nameof_enum::out_of_range"}; return {"nameof_enum::out_of_range"};
} }
}; };
constexpr std::string_view nameof_type_impl_(std::string_view name) noexcept { [[nodiscard]] constexpr std::string_view nameof_type_impl_(std::string_view name) noexcept {
#if defined(_MSC_VER) #if defined(_MSC_VER)
if (name.size() > sizeof("enum") && name[0] == 'e' && name[1] == 'n' && name[2] == 'u' && name[3] == 'm' && name[4] == ' ') { if (name.size() > sizeof("enum") && name[0] == 'e' && name[1] == 'n' && name[2] == 'u' && name[3] == 'm' && name[4] == ' ') {
name.remove_prefix(sizeof("enum")); name.remove_prefix(sizeof("enum"));
@ -204,7 +204,7 @@ constexpr std::string_view nameof_type_impl_(std::string_view name) noexcept {
} }
template <typename T> template <typename T>
constexpr std::string_view nameof_type_impl() noexcept { [[nodiscard]] constexpr std::string_view nameof_type_impl() noexcept {
#if defined(__clang__) #if defined(__clang__)
const auto str = __PRETTY_FUNCTION__; const auto str = __PRETTY_FUNCTION__;
const auto size = sizeof(__PRETTY_FUNCTION__) - 1; const auto size = sizeof(__PRETTY_FUNCTION__) - 1;
@ -229,49 +229,48 @@ constexpr std::string_view nameof_type_impl() noexcept {
} }
template <typename T, typename = std::enable_if_t<!std::is_reference_v<T>>> template <typename T, typename = std::enable_if_t<!std::is_reference_v<T>>>
constexpr std::string_view nameof_impl(std::string_view name, bool with_suffix) noexcept { [[nodiscard]] constexpr std::string_view nameof_impl(std::string_view name, bool with_suffix) noexcept {
return detail::pretty_name(name, with_suffix); return detail::pretty_name(name, with_suffix);
} }
template <typename T> [[nodiscard]] constexpr std::string_view nameof_raw_impl(std::string_view name) noexcept {
constexpr std::string_view nameof_raw_impl(std::string_view name) noexcept {
return name; return name;
} }
} // namespace detail } // namespace detail
template <typename T, typename = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>> template <typename T, typename = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>>
constexpr std::string_view nameof_enum(T value) noexcept { [[nodiscard]] constexpr std::string_view nameof_enum(T value) noexcept {
constexpr auto s = std::is_signed_v<std::underlying_type_t<std::decay_t<T>>>; constexpr auto s = std::is_signed_v<std::underlying_type_t<std::decay_t<T>>>;
return detail::nameof_enum_t<std::decay_t<T>, s ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value)); return detail::nameof_enum_t<std::decay_t<T>, s ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value));
} }
template <typename T> template <typename T>
constexpr std::string_view nameof_type() noexcept { [[nodiscard]] constexpr std::string_view nameof_type() noexcept {
return detail::nameof_type_impl<detail::identity<T>>(); return detail::nameof_type_impl<detail::identity<T>>();
} }
template <typename T> template <typename T>
constexpr std::string_view nameof_type(T) noexcept { [[nodiscard]] constexpr std::string_view nameof_type(T) noexcept {
return nameof_type<T>(); return nameof_type<T>();
} }
} // namespace nameof } // namespace nameof
// Used to obtain the simple (unqualified) string name of variable, function, enum, macro. // NAMEOF used to obtain the simple (unqualified) string name of variable, function, enum, macro.
#define NAMEOF(...) ::nameof::detail::nameof_impl<decltype(__VA_ARGS__)>(#__VA_ARGS__, false) #define NAMEOF(...) ::nameof::detail::nameof_impl<decltype(__VA_ARGS__)>(#__VA_ARGS__, false)
// Used to obtain the full string name of variable, function, enum, macro. // NAMEOF_FULL used to obtain the full string name of variable, function, enum, macro.
#define NAMEOF_FULL(...) ::nameof::detail::nameof_impl<decltype(__VA_ARGS__)>(#__VA_ARGS__, true) #define NAMEOF_FULL(...) ::nameof::detail::nameof_impl<decltype(__VA_ARGS__)>(#__VA_ARGS__, true)
// Used to obtain the raw string name of variable, function, enum, macro. // NAMEOF_ENUM used to obtain the simple (unqualified) string name of enum variable.
#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw_impl<decltype(__VA_ARGS__)>(#__VA_ARGS__)
// Used to obtain the simple (unqualified) string name of enum variable.
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<decltype(__VA_ARGS__)>(__VA_ARGS__) #define NAMEOF_ENUM(...) ::nameof::nameof_enum<decltype(__VA_ARGS__)>(__VA_ARGS__)
// Used to obtain the string name of variable type. // NAMEOF_TYPE used to obtain the string name of variable type.
#define NAMEOF_TYPE(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>() #define NAMEOF_TYPE(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>()
// Used to obtain the string name of type. // NAMEOF_TYPE_T used to obtain the string name of type.
#define NAMEOF_TYPE_T(...) ::nameof::nameof_type<__VA_ARGS__>() #define NAMEOF_TYPE_T(...) ::nameof::nameof_type<__VA_ARGS__>()
// NAMEOF_RAW used to obtain the raw string name of variable, function, enum, macro.
#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw_impl(#__VA_ARGS__)

View file

@ -201,6 +201,12 @@ TEST_CASE("NAMEOF_RAW") {
REQUIRE(NAMEOF_RAW(__LINE__) == "__LINE__"); REQUIRE(NAMEOF_RAW(__LINE__) == "__LINE__");
REQUIRE(NAMEOF_RAW(__FILE__) == "__FILE__"); REQUIRE(NAMEOF_RAW(__FILE__) == "__FILE__");
} }
SECTION("type") {
REQUIRE(NAMEOF_RAW(const SomeStruct volatile *) == "const SomeStruct volatile *");
REQUIRE(NAMEOF_RAW(SomeClass<int>) == "SomeClass<int>");
REQUIRE(NAMEOF_RAW(decltype(othervar)) == "decltype(othervar)");
}
} }
TEST_CASE("NAMEOF_ENUM") { TEST_CASE("NAMEOF_ENUM") {