wip v0.6.0
This commit is contained in:
parent
e5fe4258d6
commit
80a3e6d3e3
10 changed files with 175 additions and 498 deletions
|
@ -19,7 +19,6 @@ build:
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- GENERATOR: "Visual Studio 15 2017"
|
- GENERATOR: "Visual Studio 15 2017"
|
||||||
- GENERATOR: "Visual Studio 14 2015"
|
|
||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
- if exist build RMDIR /S /Q build
|
- if exist build RMDIR /S /Q build
|
||||||
|
|
104
.travis.yml
104
.travis.yml
|
@ -9,50 +9,6 @@ git:
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
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
|
- os: linux
|
||||||
compiler: g++
|
compiler: g++
|
||||||
addons:
|
addons:
|
||||||
|
@ -75,66 +31,6 @@ matrix:
|
||||||
env:
|
env:
|
||||||
- CXX_COMPILER=g++-8 CC_COMPILER=gcc-8
|
- 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
|
- os: linux
|
||||||
compiler: clang++
|
compiler: clang++
|
||||||
addons:
|
addons:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.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_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)
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
28
README.md
28
README.md
|
@ -18,7 +18,7 @@ Before, you had to use string literals to refer to definitions, which is brittle
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* C++11
|
* C++17
|
||||||
* Header-only
|
* Header-only
|
||||||
* Dependency-free
|
* Dependency-free
|
||||||
* Compile-time
|
* Compile-time
|
||||||
|
@ -43,11 +43,10 @@ NAMEOF(person.address.zip_code) -> "zip_code"
|
||||||
NAMEOF(SomeMethod<int, float>) -> "SomeMethod"
|
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"
|
auto c = Color::RED;
|
||||||
auto e = SomeEnum::RED;
|
NAMEOF_ENUM(c) -> "RED"
|
||||||
NAMEOF_ENUM(e) -> "RED"
|
|
||||||
// Name of type
|
// Name of type
|
||||||
NAMEOF_TYPE(SomeEnum::RED) -> "SomeEnum"
|
NAMEOF_TYPE(Color::RED) -> "Color"
|
||||||
NAMEOF_TYPE_T(int) -> "int"
|
NAMEOF_TYPE_T(int) -> "int"
|
||||||
// Name of macros
|
// Name of macros
|
||||||
NAMEOF(__LINE__) -> "__LINE__"
|
NAMEOF(__LINE__) -> "__LINE__"
|
||||||
|
@ -57,7 +56,7 @@ NAMEOF(__LINE__) -> "__LINE__"
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
constexpr auto cx = NAMEOF(somevar); -> "somevar"
|
constexpr auto cx = NAMEOF(somevar); -> "somevar"
|
||||||
static_assert(cx == "somevar", "Wrong name!");
|
static_assert("somevar" == cx, "Wrong name!");
|
||||||
```
|
```
|
||||||
|
|
||||||
* Compilation check
|
* Compilation check
|
||||||
|
@ -102,6 +101,8 @@ void f() {
|
||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
|
* Nameof return std::string_view.
|
||||||
|
|
||||||
* The argument expression identifies a code definition, but it is never evaluated.
|
* The argument expression identifies a 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().
|
||||||
|
@ -114,24 +115,23 @@ NAMEOF_RAW(&SomeStruct::SomeMethod) -> "&SomeStruct::SomeMethod"
|
||||||
* Instead of macros NAMEOF_ENUM, you can use the function nameof::NameofEnum().
|
* Instead of macros NAMEOF_ENUM, you can use the function nameof::NameofEnum().
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
nameof::NameofEnum(SomeEnum::RED) -> "RED"
|
nameof::NameofEnum(Color::RED) -> "RED"
|
||||||
auto e = SomeEnum::RED;
|
auto c = Color::RED;
|
||||||
nameof::NameofEnum(e) -> "RED"
|
nameof::NameofEnum(c) -> "RED"
|
||||||
```
|
```
|
||||||
|
|
||||||
* Instead of macros NAMEOF_TYPE, you can use the function nameof::NameofType<>.
|
* Instead of macros NAMEOF_TYPE, you can use the function nameof::NameofType<>.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
nameof::NameofType<decltype(SomeEnum::RED)>() -> "SomeEnum"
|
nameof::NameofType<decltype(Color::RED)>() -> "Color"
|
||||||
nameof::NameofType<int> -> "int"
|
nameof::NameofType<int> -> "int"
|
||||||
```
|
```
|
||||||
|
|
||||||
* NAMEOF_ENUM does not work on the GCC.
|
* NAMEOF_ENUM does not work on the GCC.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// On GCC.
|
auto c = Color::RED;
|
||||||
auto e = SomeEnum::RED;
|
NAMEOF_ENUM(c) -> "(Color)0"
|
||||||
NAMEOF_ENUM(e) -> "(SomeEnum)0"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
* Spaces and Tabs ignored
|
* Spaces and Tabs ignored
|
||||||
|
@ -143,7 +143,7 @@ NAMEOF( somevar ) -> "somevar"
|
||||||
|
|
||||||
## Integration
|
## 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
|
## Compiler compatibility
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,13 @@ set(OPTIONS "")
|
||||||
if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||||
set(OPTIONS -Wall -Wextra -pedantic-errors)
|
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")
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
set(OPTIONS /W4)
|
set(OPTIONS /W4)
|
||||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.11)
|
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.11)
|
||||||
set(OPTIONS ${OPTIONS} /permissive-)
|
set(OPTIONS ${OPTIONS} /permissive-)
|
||||||
endif()
|
endif()
|
||||||
|
set(OPTIONS ${OPTIONS} /std:c++17)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(example
|
add_executable(example
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// nameof example
|
|
||||||
//
|
|
||||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
// 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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -50,14 +49,25 @@ void SomeMethod3() {
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
std::string SomeMethod4(U value) {
|
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>
|
template <typename T>
|
||||||
class SomeClass {
|
class SomeClass {
|
||||||
public:
|
public:
|
||||||
void SomeMethod5() const {
|
void SomeMethod5() const {
|
||||||
std::cout << nameof::NameofType<T>() << std::endl;
|
std::cout << nameof::nameof_type<T>() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename C>
|
template <typename C>
|
||||||
|
@ -75,7 +85,7 @@ struct Long {
|
||||||
LL ll;
|
LL ll;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Color { RED, GREEN, BLUE };
|
enum class Color { RED = -10, GREEN, BLUE };
|
||||||
|
|
||||||
SomeStruct structvar;
|
SomeStruct structvar;
|
||||||
Long othervar;
|
Long othervar;
|
||||||
|
@ -84,14 +94,14 @@ SomeStruct* ptrvar = &structvar;
|
||||||
int main() {
|
int main() {
|
||||||
// Compile-time nameof.
|
// Compile-time nameof.
|
||||||
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);
|
||||||
|
|
||||||
// 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;
|
auto color = Color::RED;
|
||||||
std::cout << NAMEOF(color) << std::endl; // color
|
std::cout << NAMEOF(color) << std::endl; // color
|
||||||
std::cout << NAMEOF_ENUM(color) << std::endl; // RED
|
std::cout << NAMEOF_ENUM(color) << std::endl; // RED
|
||||||
|
std::cout << nameof::nameof_enum(color) << std::endl; // RED
|
||||||
|
|
||||||
// Variable name.
|
// Variable name.
|
||||||
std::cout << NAMEOF(structvar) << std::endl; // structvar
|
std::cout << NAMEOF(structvar) << std::endl; // structvar
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
// vesion 0.5.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>.
|
// 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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -32,21 +33,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <limits>
|
#include <string_view>
|
||||||
#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
|
|
||||||
|
|
||||||
#if !defined(NAMEOF_ENUM_MAX_SEARCH_DEPTH)
|
#if !defined(NAMEOF_ENUM_MAX_SEARCH_DEPTH)
|
||||||
# define NAMEOF_ENUM_MAX_SEARCH_DEPTH 64
|
# define NAMEOF_ENUM_MAX_SEARCH_DEPTH 64
|
||||||
|
@ -56,159 +43,22 @@ namespace nameof {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
namespace nstd {
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct identity {
|
struct identity {
|
||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nstd
|
constexpr bool is_lexeme(char s) noexcept {
|
||||||
|
|
||||||
#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 {
|
|
||||||
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 IsBracket(char s) noexcept {
|
constexpr bool is_bracket(char s) noexcept {
|
||||||
return s == ')' || s == '}' || s == '>' || s == '(' || s == '{' || s == '<';
|
return s == ')' || s == '}' || s == '>' || s == '(' || s == '{' || s == '<';
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NAMEOF_HAS_CONSTEXPR14)
|
constexpr std::string_view pretty_name(std::string_view name, bool with_suffix) {
|
||||||
constexpr cstring NameofPretty(cstring name, bool with_suffix) {
|
|
||||||
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 && IsLexeme(name[i - 1]) && !IsBracket(name[i - 1])) {
|
if (h == 0 && is_lexeme(name[i - 1]) && !is_bracket(name[i - 1])) {
|
||||||
++s;
|
++s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +74,7 @@ constexpr cstring NameofPretty(cstring name, bool with_suffix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h == 0) {
|
if (h == 0) {
|
||||||
name = name.remove_suffix(s);
|
name.remove_suffix(s);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
++s;
|
++s;
|
||||||
|
@ -253,183 +103,121 @@ constexpr cstring NameofPretty(cstring name, bool with_suffix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t i = name.size() - s; i > 0; --i) {
|
for (std::size_t i = name.size() - s; i > 0; --i) {
|
||||||
if (IsLexeme(name[i - 1])) {
|
if (is_lexeme(name[i - 1])) {
|
||||||
return name.remove_prefix(i).remove_suffix(with_suffix ? 0 : s);
|
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>
|
template <typename T>
|
||||||
NAMEOF_CONSTEXPR int NameofEnumImpl1() {
|
constexpr int nameof_enum_impl_() {
|
||||||
#if defined(__clang__)
|
#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__)
|
#elif defined(__GNUC__)
|
||||||
# if defined(NAMEOF_HAS_CONSTEXPR)
|
return sizeof(__PRETTY_FUNCTION__) - sizeof("constexpr int nameof::detail::nameof_enum_impl_() [with T = ") - sizeof("]") + 1;
|
||||||
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
|
|
||||||
#elif defined(_MSC_VER)
|
#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
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, T V>
|
template <typename T, T V>
|
||||||
NAMEOF_CONSTEXPR cstring NameofEnumImpl2() {
|
constexpr std::string_view nameof_enum_impl() {
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
return {__PRETTY_FUNCTION__,
|
const auto str = __PRETTY_FUNCTION__;
|
||||||
sizeof(__PRETTY_FUNCTION__) - 1,
|
const auto size = sizeof(__PRETTY_FUNCTION__) - 1;
|
||||||
sizeof("nameof::cstring nameof::detail::NameofEnumImpl2() [T = ") + NameofEnumImpl1<T>() + sizeof("; V = ") - 2,
|
const auto prefix = sizeof("std::string_view nameof::detail::nameof_enum_impl() [T = ") + nameof_enum_impl_<T>() + sizeof("; V = ") - 2;
|
||||||
sizeof("]") - 1};
|
const auto suffix = sizeof("]") - 1;
|
||||||
|
return {str + prefix, size - prefix - suffix};
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
return {__PRETTY_FUNCTION__,
|
const auto str = __PRETTY_FUNCTION__;
|
||||||
sizeof(__PRETTY_FUNCTION__) - 1,
|
const auto size = sizeof(__PRETTY_FUNCTION__) - 1;
|
||||||
# if defined(NAMEOF_HAS_CONSTEXPR)
|
const auto prefix = sizeof("constexpr std::string_view nameof::detail::nameof_enum_impl() [with T = ") + nameof_enum_impl_<T>() + sizeof("; V = ");
|
||||||
sizeof("constexpr nameof::cstring nameof::detail::NameofEnumImpl2() [with T = ") + NameofEnumImpl1<T>() + sizeof("; T V = ") - 2,
|
const auto suffix = sizeof("; std::string_view = std::basic_string_view<char>]") - 1;
|
||||||
# else
|
return {str + prefix, size - prefix - suffix};
|
||||||
sizeof("nameof::cstring nameof::detail::NameofEnumImpl2() [with T = ") + NameofEnumImpl1<T>() + sizeof("; T V = ") - 2,
|
|
||||||
# endif
|
|
||||||
sizeof("]") - 1};
|
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
return {__FUNCSIG__,
|
const auto str = __FUNCSIG__;
|
||||||
sizeof(__FUNCSIG__) - 1,
|
const auto size = sizeof(__FUNCSIG__) - 1;
|
||||||
sizeof("class nameof::cstring __cdecl nameof::detail::NameofEnumImpl2<") + NameofEnumImpl1<T>(),
|
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>();
|
||||||
sizeof(">(void)") - 1};
|
const auto suffix = sizeof(">(void)") - 1;
|
||||||
|
return {str + prefix, size - prefix - suffix};
|
||||||
#else
|
#else
|
||||||
return {};
|
return {};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, int I>
|
template <typename T, int I>
|
||||||
struct NameofEnumImpl {
|
struct nameof_enum_t {
|
||||||
NAMEOF_CONSTEXPR cstring operator()(int value) const {
|
constexpr std::string_view operator()(int value) const {
|
||||||
return (value - I == 0)
|
return (value - I == 0)
|
||||||
? NameofEnumImpl2<T, T(I)>()
|
? nameof_enum_impl<T, T(I)>()
|
||||||
: (value - I == 1)
|
: (value - I == 1)
|
||||||
? NameofEnumImpl2<T, T(I + 1)>()
|
? nameof_enum_impl<T, T(I + 1)>()
|
||||||
: (value - I == 2)
|
: (value - I == 2)
|
||||||
? NameofEnumImpl2<T, T(I + 2)>()
|
? nameof_enum_impl<T, T(I + 2)>()
|
||||||
: (value - I == 3)
|
: (value - I == 3)
|
||||||
? NameofEnumImpl2<T, T(I + 3)>()
|
? nameof_enum_impl<T, T(I + 3)>()
|
||||||
: (value - I == 4)
|
: (value - I == 4)
|
||||||
? NameofEnumImpl2<T, T(I + 4)>()
|
? nameof_enum_impl<T, T(I + 4)>()
|
||||||
: (value - I == 5)
|
: (value - I == 5)
|
||||||
? NameofEnumImpl2<T, T(I + 5)>()
|
? nameof_enum_impl<T, T(I + 5)>()
|
||||||
: (value - I == 6)
|
: (value - I == 6)
|
||||||
? NameofEnumImpl2<T, T(I + 6)>()
|
? nameof_enum_impl<T, T(I + 6)>()
|
||||||
: (value - I == 7)
|
: (value - I == 7)
|
||||||
? NameofEnumImpl2<T, T(I + 7)>()
|
? nameof_enum_impl<T, T(I + 7)>()
|
||||||
: NameofEnumImpl<T, I + 8>{}(value);
|
: nameof_enum_t<T, I + 8>{}(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct NameofEnumImpl<T, NAMEOF_ENUM_MAX_SEARCH_DEPTH> {
|
struct nameof_enum_t<T, NAMEOF_ENUM_MAX_SEARCH_DEPTH> {
|
||||||
NAMEOF_CONSTEXPR cstring operator()(int) const { return {}; }
|
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>
|
template <typename T>
|
||||||
NAMEOF_CONSTEXPR cstring NameofType() {
|
constexpr std::string_view nameof_type_impl() {
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
return NameofTypePretty(
|
const auto str = __PRETTY_FUNCTION__;
|
||||||
__PRETTY_FUNCTION__,
|
const auto size = sizeof(__PRETTY_FUNCTION__) - 1;
|
||||||
sizeof(__PRETTY_FUNCTION__) - 1,
|
const auto prefix = sizeof("std::string_view nameof::detail::nameof_type_impl() [T = nameof::detail::identity<") - 1;
|
||||||
sizeof("nameof::cstring nameof::detail::NameofType() [T = nameof::detail::nstd::identity<") - 1,
|
const auto suffix = sizeof(">]") - 1;
|
||||||
sizeof(">]") - 1);
|
return nameof_type_impl_({str + prefix, size - prefix - suffix});
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
return NameofTypePretty(
|
const auto str = __PRETTY_FUNCTION__;
|
||||||
__PRETTY_FUNCTION__,
|
const auto size = sizeof(__PRETTY_FUNCTION__) - 1;
|
||||||
sizeof(__PRETTY_FUNCTION__) - 1,
|
const auto prefix = sizeof("constexpr std::string_view nameof::detail::nameof_type_impl() [with T = nameof::detail::identity<") - 1;
|
||||||
# if defined(NAMEOF_HAS_CONSTEXPR)
|
const auto suffix = sizeof(">; std::string_view = std::basic_string_view<char>]") - 1;
|
||||||
sizeof("constexpr nameof::cstring nameof::detail::NameofType() [with T = nameof::detail::nstd::identity<") - 1,
|
return nameof_type_impl_({str + prefix, size - prefix - suffix});
|
||||||
# else
|
|
||||||
sizeof("nameof::cstring nameof::detail::NameofType() [with T = nameof::detail::nstd::identity<") - 1,
|
|
||||||
# endif
|
|
||||||
sizeof(">]") - 1);
|
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
return NameofTypePretty(
|
const auto str = __FUNCSIG__;
|
||||||
{__FUNCSIG__,
|
const auto size = sizeof(__FUNCSIG__) - 1;
|
||||||
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;
|
||||||
sizeof("class nameof::cstring __cdecl nameof::detail::NameofType<struct nameof::detail::nstd::identity<") - 1,
|
const auto suffix = sizeof(">>(void)") - 1;
|
||||||
sizeof(">>(void)") - 1});
|
return nameof_type_impl_({str + prefix, size - prefix - suffix});
|
||||||
#else
|
#else
|
||||||
return {};
|
return {};
|
||||||
#endif
|
#endif
|
||||||
|
@ -439,49 +227,48 @@ NAMEOF_CONSTEXPR cstring NameofType() {
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename = typename std::enable_if<!std::is_reference<T>::value>::type>
|
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) {
|
constexpr std::string_view nameof(std::string_view name, bool with_suffix = false) {
|
||||||
return detail::NameofPretty({name, size}, with_suffix);
|
return detail::pretty_name(name, with_suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename D = typename std::decay<T>::type,
|
typename = typename std::enable_if<std::is_enum<typename std::decay<T>::type>::value>::type>
|
||||||
typename U = typename std::underlying_type<D>::type,
|
constexpr std::string_view nameof_enum(T value) {
|
||||||
typename S = typename std::is_signed<U>::type,
|
constexpr auto s = std::is_signed<typename std::underlying_type<typename std::decay<T>::type>::type>::value;
|
||||||
typename = typename std::enable_if<std::is_enum<D>::value>::type>
|
const auto name = detail::nameof_enum_t<typename std::decay<T>::type, s ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value));
|
||||||
NAMEOF_CONSTEXPR cstring NameofEnum(D value) {
|
|
||||||
#if defined(__clang__) || defined(_MSC_VER)
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
return detail::NameofPretty(
|
return detail::pretty_name(name, false);
|
||||||
detail::NameofEnumImpl<D, S::value ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value)),
|
|
||||||
false);
|
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
return detail::NameofEnumImpl<D, S::value ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast<int>(value));
|
return name;
|
||||||
#else
|
#else
|
||||||
return {};
|
return {};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename D = detail::nstd::identity<T>>
|
template <typename T>
|
||||||
NAMEOF_CONSTEXPR cstring NameofType() {
|
constexpr std::string_view nameof_type() {
|
||||||
return true ? detail::NameofType<D>() : detail::NameofType<D>();
|
return detail::nameof_type_impl<detail::identity<T>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr cstring NameofRaw(const char* name, std::size_t size) {
|
constexpr std::string_view nameof_raw(std::string_view name) {
|
||||||
return {name, size};
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace nameof
|
} // namespace nameof
|
||||||
|
|
||||||
// Used to obtain the simple (unqualified) string name of a variable, member, function, enum, 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__, 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, 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.
|
// 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.
|
// 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.
|
// Used to obtain the string name of a type.
|
||||||
#define NAMEOF_TYPE(...) ::nameof::NameofType<decltype(__VA_ARGS__)>()
|
#define NAMEOF_TYPE(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>()
|
||||||
#define NAMEOF_TYPE_T(...) ::nameof::NameofType<__VA_ARGS__>()
|
#define NAMEOF_TYPE_T(...) ::nameof::nameof_type<__VA_ARGS__>()
|
||||||
|
|
|
@ -68,20 +68,6 @@ function(make_target target std)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
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)
|
if(HAS_CPP17_FLAG)
|
||||||
set(std17 c++17)
|
set(std17 c++17)
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// nameof test
|
|
||||||
//
|
|
||||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
// 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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -38,12 +37,12 @@ struct SomeStruct {
|
||||||
};
|
};
|
||||||
|
|
||||||
void SomeMethod3() {
|
void SomeMethod3() {
|
||||||
std::cout << NAMEOF(SomeMethod3) << " no called!" << std::endl;
|
throw std::runtime_error{"should not be called!"};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
std::string SomeMethod4(U value) {
|
std::string SomeMethod4(U) {
|
||||||
return NAMEOF(SomeMethod4<T, U>) + "<" + NAMEOF_TYPE_T(T) + ", " + NAMEOF_TYPE_T(U) + ">(" + NAMEOF_TYPE_T(U) + " " + NAMEOF(value) + ")";
|
throw std::runtime_error{"should not be called!"};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -87,101 +86,102 @@ TEST_CASE("constexpr") {
|
||||||
SECTION("NAMEOF") {
|
SECTION("NAMEOF") {
|
||||||
// variable
|
// variable
|
||||||
constexpr auto cx1 = NAMEOF(struct_var);
|
constexpr auto cx1 = NAMEOF(struct_var);
|
||||||
static_assert(cx1 == "struct_var", "");
|
static_assert(cx1 == "struct_var");
|
||||||
REQUIRE(cx1 == "struct_var");
|
REQUIRE(cx1 == "struct_var");
|
||||||
// member
|
// member
|
||||||
constexpr auto cx2 = NAMEOF((&struct_var)->somefield);
|
constexpr auto cx2 = NAMEOF((&struct_var)->somefield);
|
||||||
static_assert(cx2 == "somefield", "");
|
static_assert(cx2 == "somefield");
|
||||||
REQUIRE(cx2 == "somefield");
|
REQUIRE(cx2 == "somefield");
|
||||||
// function
|
// function
|
||||||
constexpr auto cx3 = NAMEOF(&SomeClass<int>::SomeMethod6<long int>);
|
constexpr auto cx3 = NAMEOF(&SomeClass<int>::SomeMethod6<long int>);
|
||||||
static_assert(cx3 == "SomeMethod6", "");
|
static_assert(cx3 == "SomeMethod6");
|
||||||
REQUIRE(cx3 == "SomeMethod6");
|
REQUIRE(cx3 == "SomeMethod6");
|
||||||
// enum
|
// enum
|
||||||
constexpr auto cx4 = NAMEOF(Color::RED);
|
constexpr auto cx4 = NAMEOF(Color::RED);
|
||||||
static_assert(cx4 == "RED", "");
|
static_assert(cx4 == "RED");
|
||||||
REQUIRE(cx4 == "RED");
|
REQUIRE(cx4 == "RED");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("NAMEOF_FULL") {
|
SECTION("NAMEOF_FULL") {
|
||||||
// variable
|
// variable
|
||||||
constexpr auto cx1 = NAMEOF_FULL(struct_var);
|
constexpr auto cx1 = NAMEOF_FULL(struct_var);
|
||||||
static_assert(cx1 == "struct_var", "");
|
static_assert(cx1 == "struct_var");
|
||||||
REQUIRE(cx1 == "struct_var");
|
REQUIRE(cx1 == "struct_var");
|
||||||
// member
|
// member
|
||||||
constexpr auto cx2 = NAMEOF_FULL((&struct_var)->somefield);
|
constexpr auto cx2 = NAMEOF_FULL((&struct_var)->somefield);
|
||||||
static_assert(cx2 == "somefield", "");
|
static_assert(cx2 == "somefield");
|
||||||
REQUIRE(cx2 == "somefield");
|
REQUIRE(cx2 == "somefield");
|
||||||
// function
|
// function
|
||||||
constexpr auto cx3 = NAMEOF_FULL(&SomeClass<int>::SomeMethod6<long int>);
|
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>");
|
REQUIRE(cx3 == "SomeMethod6<long int>");
|
||||||
// enum
|
// enum
|
||||||
constexpr auto cx4 = NAMEOF_FULL(Color::RED);
|
constexpr auto cx4 = NAMEOF_FULL(Color::RED);
|
||||||
static_assert(cx4 == "RED", "");
|
static_assert(cx4 == "RED");
|
||||||
REQUIRE(cx4 == "RED");
|
REQUIRE(cx4 == "RED");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("NAMEOF_RAW") {
|
SECTION("NAMEOF_RAW") {
|
||||||
// variable
|
// variable
|
||||||
constexpr auto cx1 = NAMEOF_RAW(struct_var);
|
constexpr auto cx1 = NAMEOF_RAW(struct_var);
|
||||||
static_assert(cx1 == "struct_var", "");
|
static_assert(cx1 == "struct_var");
|
||||||
REQUIRE(cx1 == "struct_var");
|
REQUIRE(cx1 == "struct_var");
|
||||||
// member
|
// member
|
||||||
constexpr auto cx2 = NAMEOF_RAW((&struct_var)->somefield);
|
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");
|
REQUIRE(cx2 == "(&struct_var)->somefield");
|
||||||
// function
|
// function
|
||||||
constexpr auto cx4 = NAMEOF_RAW(&SomeStruct::SomeMethod2);
|
constexpr auto cx4 = NAMEOF_RAW(&SomeStruct::SomeMethod2);
|
||||||
static_assert(cx4 == "&SomeStruct::SomeMethod2", "");
|
static_assert(cx4 == "&SomeStruct::SomeMethod2");
|
||||||
REQUIRE(cx4 == "&SomeStruct::SomeMethod2");
|
REQUIRE(cx4 == "&SomeStruct::SomeMethod2");
|
||||||
// enum
|
// enum
|
||||||
constexpr auto cx5 = NAMEOF_RAW(Color::RED);
|
constexpr auto cx5 = NAMEOF_RAW(Color::RED);
|
||||||
static_assert(cx5 == "Color::RED", "");
|
static_assert(cx5 == "Color::RED");
|
||||||
REQUIRE(cx5 == "Color::RED");
|
REQUIRE(cx5 == "Color::RED");
|
||||||
// macros
|
// macros
|
||||||
constexpr auto cx6 = NAMEOF_RAW(__cplusplus);
|
constexpr auto cx6 = NAMEOF_RAW(__cplusplus);
|
||||||
static_assert(cx6 == "__cplusplus", "");
|
static_assert(cx6 == "__cplusplus");
|
||||||
REQUIRE(cx6 == "__cplusplus");
|
REQUIRE(cx6 == "__cplusplus");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NAMEOF_HAS_CONSTEXPR)
|
|
||||||
SECTION("NAMEOF_ENUM") {
|
SECTION("NAMEOF_ENUM") {
|
||||||
constexpr auto cx = NAMEOF_ENUM(color);
|
constexpr auto cx = NAMEOF_ENUM(color);
|
||||||
# if defined(__clang__) || defined(_MSC_VER)
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
static_assert(cx == "RED", "");
|
static_assert(cx == "RED");
|
||||||
REQUIRE(cx == "RED");
|
REQUIRE(cx == "RED");
|
||||||
# elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
|
static_assert(cx == "(Color)-1");
|
||||||
REQUIRE(cx == "(Color)-1");
|
REQUIRE(cx == "(Color)-1");
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("NAMEOF_TYPE") {
|
SECTION("NAMEOF_TYPE") {
|
||||||
constexpr auto cx = NAMEOF_TYPE(ptr_c);
|
constexpr auto cx = NAMEOF_TYPE(ptr_c);
|
||||||
# if defined(__clang__)
|
#if defined(__clang__)
|
||||||
static_assert(cx == "const volatile SomeClass<int> *", "");
|
static_assert(cx == "const volatile SomeClass<int> *");
|
||||||
REQUIRE(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>*");
|
REQUIRE(cx == "const volatile SomeClass<int>*");
|
||||||
# elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
static_assert(cx == "SomeClass<int> const volatile *", "");
|
static_assert(cx == "SomeClass<int> const volatile *");
|
||||||
REQUIRE(cx == "SomeClass<int> const volatile *");
|
REQUIRE(cx == "SomeClass<int> const volatile *");
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("NAMEOF_TYPE_T") {
|
SECTION("NAMEOF_TYPE_T") {
|
||||||
constexpr auto cx = NAMEOF_TYPE_T(const SomeClass<int> volatile *);
|
constexpr auto cx = NAMEOF_TYPE_T(const SomeClass<int> volatile *);
|
||||||
# if defined(__clang__)
|
#if defined(__clang__)
|
||||||
static_assert(cx == "const volatile SomeClass<int> *", "");
|
static_assert(cx == "const volatile SomeClass<int> *");
|
||||||
REQUIRE(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>*");
|
REQUIRE(cx == "const volatile SomeClass<int>*");
|
||||||
# elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
static_assert(cx == "SomeClass<int> const volatile *", "");
|
static_assert(cx == "SomeClass<int> const volatile *");
|
||||||
REQUIRE(cx == "SomeClass<int> const volatile *");
|
REQUIRE(cx == "SomeClass<int> const volatile *");
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NAMEOF") {
|
TEST_CASE("NAMEOF") {
|
||||||
|
@ -461,5 +461,3 @@ TEST_CASE("Spaces and Tabs ignored") {
|
||||||
REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct");
|
REQUIRE(NAMEOF_TYPE_T( decltype(struct_var) ) == "SomeStruct");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("cstring") {}
|
|
||||||
|
|
Loading…
Reference in a new issue