Compare commits
228 commits
Author | SHA1 | Date | |
---|---|---|---|
ad4ba073a3 | |||
![]() |
6c8e87da57 | ||
![]() |
3f1664327a | ||
![]() |
174b23d76e | ||
![]() |
3d4c9820fc | ||
![]() |
72a9659576 | ||
![]() |
72ce6c9ae0 | ||
![]() |
4d097b9da0 | ||
![]() |
e86b94cb8d | ||
![]() |
c9ae9a57c3 | ||
![]() |
5443409085 | ||
![]() |
8aeb677413 | ||
![]() |
f2522c2cc0 | ||
![]() |
8a6813f242 | ||
![]() |
31ac2b3273 | ||
![]() |
8f416c881e | ||
![]() |
6708611448 | ||
![]() |
1f071407dc | ||
![]() |
9494cbd4aa | ||
![]() |
84ce6d87fb | ||
![]() |
173271ef06 | ||
![]() |
a83b66aac9 | ||
![]() |
34d8c2b74e | ||
![]() |
1cc3feb884 | ||
![]() |
b877a1a556 | ||
![]() |
bc183cd334 | ||
![]() |
70ca094db8 | ||
![]() |
f7b2f34053 | ||
![]() |
84c2d8bb19 | ||
![]() |
6a1efd31c1 | ||
![]() |
ea3871026a | ||
![]() |
54a6a795a9 | ||
![]() |
f14c1b5065 | ||
![]() |
00a333bb8e | ||
![]() |
09f879a995 | ||
![]() |
3237b9a367 | ||
![]() |
db94e8b345 | ||
![]() |
4d2d89eac7 | ||
![]() |
c44b65d57d | ||
![]() |
c04b72fc51 | ||
![]() |
b6a4452eef | ||
![]() |
59411bf519 | ||
![]() |
f32bbb0f09 | ||
![]() |
c793b69c40 | ||
![]() |
2cb9751cb6 | ||
![]() |
32885c092e | ||
![]() |
5bf352dfa6 | ||
![]() |
7e2cc11360 | ||
![]() |
83ee9b42df | ||
![]() |
e37861d46f | ||
![]() |
3a728f4102 | ||
![]() |
b5deb0055c | ||
![]() |
b12d458de0 | ||
![]() |
22c8c79c15 | ||
![]() |
ed238a058b | ||
![]() |
6422949948 | ||
![]() |
143d19c5e0 | ||
![]() |
d99ab9ae73 | ||
![]() |
286c76eef9 | ||
![]() |
7ea354b14f | ||
![]() |
ef84cb110b | ||
![]() |
bd14db23e1 | ||
![]() |
b19b00b61a | ||
![]() |
e009769d00 | ||
![]() |
292d604578 | ||
![]() |
12bb8c0df3 | ||
![]() |
d69f91daa5 | ||
![]() |
6810459778 | ||
![]() |
a9813bd7a1 | ||
![]() |
d091ca081e | ||
![]() |
b61944a3b6 | ||
![]() |
71ae34dbe8 | ||
![]() |
dad9b4b044 | ||
![]() |
84c6c9866a | ||
![]() |
bb413bbdaa | ||
![]() |
fb480caab2 | ||
![]() |
df0ea27383 | ||
![]() |
2cf013dbf3 | ||
![]() |
6df582978d | ||
![]() |
f57dcf410a | ||
![]() |
3a52b520c9 | ||
![]() |
b94b243525 | ||
![]() |
7b5d24e37f | ||
![]() |
6fa49cca4b | ||
![]() |
308bbf9c68 | ||
![]() |
3986a3ce93 | ||
![]() |
0ba625e215 | ||
![]() |
8d2044f2d7 | ||
![]() |
0e8bec0dc0 | ||
![]() |
02e33b6b18 | ||
![]() |
e814a3c13d | ||
![]() |
0ccc3b4f3b | ||
![]() |
1fafaba65d | ||
![]() |
74dfbd6528 | ||
![]() |
5de9eb6291 | ||
![]() |
7daf306654 | ||
![]() |
735ba9fb1d | ||
![]() |
fff49040ed | ||
![]() |
7614db16d1 | ||
![]() |
abac0c52b6 | ||
![]() |
faf5a52b91 | ||
![]() |
e97a790afb | ||
![]() |
ed04f81ff7 | ||
![]() |
d12b28c346 | ||
![]() |
f4f4908d7e | ||
![]() |
d099f13d12 | ||
![]() |
c42376a8d1 | ||
![]() |
59f176a10f | ||
![]() |
7bf624de33 | ||
![]() |
2cdcdc0f83 | ||
![]() |
77fd770012 | ||
![]() |
18cfc68c65 | ||
![]() |
3e2fa48b37 | ||
![]() |
9ede5ab901 | ||
![]() |
121166d263 | ||
![]() |
a47f23bc6d | ||
![]() |
e2a56fa18a | ||
![]() |
f7aa276086 | ||
![]() |
51a79f9545 | ||
![]() |
dc127d3d4d | ||
![]() |
7da39ee9ba | ||
![]() |
66a61bf7f2 | ||
![]() |
1b8b849184 | ||
![]() |
6e97229efd | ||
![]() |
9885d98bf3 | ||
![]() |
1303731a6b | ||
![]() |
ef959f7da5 | ||
![]() |
f9078cc9f9 | ||
![]() |
04578f3316 | ||
![]() |
a01e3d26b9 | ||
![]() |
8bf60cc20d | ||
![]() |
16740daf9e | ||
![]() |
d33424c377 | ||
![]() |
f7554a166f | ||
![]() |
ad59562c9e | ||
![]() |
06aafae7b7 | ||
![]() |
fa938cff96 | ||
![]() |
ed639692b5 | ||
![]() |
7e3b975054 | ||
![]() |
0e425a33b7 | ||
![]() |
6398e5ecfa | ||
![]() |
08d11632d2 | ||
![]() |
33023e3275 | ||
![]() |
534ece4154 | ||
![]() |
a23f4fac65 | ||
![]() |
05eb30b844 | ||
![]() |
1e0c019453 | ||
![]() |
5e198e9983 | ||
![]() |
61a05620d0 | ||
![]() |
dec2c332bd | ||
![]() |
f5a2489330 | ||
![]() |
9d66520257 | ||
![]() |
742f2879db | ||
![]() |
27c2aeb6bb | ||
![]() |
d06a1c717a | ||
![]() |
e831936fbe | ||
![]() |
d293613b62 | ||
![]() |
550891639a | ||
![]() |
0f3dbd70f2 | ||
![]() |
64499c3763 | ||
![]() |
240b3f4d6a | ||
![]() |
42a6b64f20 | ||
![]() |
b479bb458a | ||
![]() |
23fc75df57 | ||
![]() |
cff9399e28 | ||
![]() |
e3ff0c85cf | ||
![]() |
5d4db414b9 | ||
![]() |
f0c2d7c539 | ||
![]() |
0414495682 | ||
![]() |
dde974339d | ||
![]() |
6829441ca8 | ||
![]() |
d7f6787cd1 | ||
![]() |
f7ed4583d8 | ||
![]() |
a6b2aac0b5 | ||
![]() |
1baf418d21 | ||
![]() |
4b3536d211 | ||
![]() |
4319be3c2e | ||
![]() |
96ac608d13 | ||
![]() |
fd53f1e723 | ||
![]() |
aa45d44f05 | ||
![]() |
67c27efd61 | ||
![]() |
47fa9b5f7c | ||
![]() |
a8dac47ada | ||
![]() |
7f4fc39a0a | ||
![]() |
9145963e35 | ||
![]() |
6a976ef472 | ||
![]() |
48ffc2f855 | ||
![]() |
9de7bbaeb8 | ||
![]() |
c597ade7ac | ||
![]() |
dbe2547ed1 | ||
![]() |
4172418e59 | ||
![]() |
7f1ed8b98f | ||
![]() |
a267cc70d7 | ||
![]() |
d74130477e | ||
![]() |
23c959c3e2 | ||
![]() |
f6a6c5de10 | ||
![]() |
44833f2272 | ||
![]() |
e62d87432f | ||
![]() |
50ded04922 | ||
![]() |
c99f0a4e40 | ||
![]() |
31301aca91 | ||
![]() |
7e974384b2 | ||
![]() |
523a9896ac | ||
![]() |
cb08b67e9d | ||
![]() |
0639b4b0c4 | ||
![]() |
fea658233a | ||
![]() |
ecddb3c302 | ||
![]() |
341104fb62 | ||
![]() |
412e9a69d0 | ||
![]() |
ef791f7a8a | ||
![]() |
4c5b75e56e | ||
![]() |
b5a158d0d2 | ||
![]() |
e4c754cb43 | ||
![]() |
d32e9ce4f7 | ||
![]() |
231ea223c8 | ||
![]() |
707bb945fd | ||
![]() |
4073167fa4 | ||
![]() |
c6c6112161 | ||
![]() |
1400b612c1 | ||
![]() |
7276880fdf | ||
![]() |
a362b570bb | ||
![]() |
9c5ae69b36 | ||
![]() |
1aea83279c | ||
![]() |
3ae26b5430 | ||
![]() |
5a1e58bbdf | ||
![]() |
f0720ba756 | ||
![]() |
18a7bb7f8c | ||
![]() |
6f6871dd4b |
26 changed files with 7644 additions and 2097 deletions
|
@ -1,33 +0,0 @@
|
|||
version: "{branch} #{build}"
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
- x64
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
build:
|
||||
parallel: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- GENERATOR: "Visual Studio 15 2017"
|
||||
|
||||
before_build:
|
||||
- if exist build RMDIR /S /Q build
|
||||
- if not exist build mkdir build
|
||||
- cd build
|
||||
- cmake -G "%GENERATOR%" -A %PLATFORM% ..
|
||||
|
||||
build_script:
|
||||
- cmake --build . --config %CONFIGURATION%
|
||||
|
||||
test_script:
|
||||
- ctest --output-on-failure -C %CONFIGURATION%
|
37
.github/workflows/macos.yml
vendored
Normal file
37
.github/workflows/macos.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
name: macos
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { os: macos-13 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-13-Readme.md#xcode
|
||||
- { os: macos-14 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-14-Readme.md#xcode
|
||||
|
||||
name: "${{ matrix.config.os }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build Release
|
||||
run: |
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build . -j 4 --config Release
|
||||
ctest --output-on-failure -C Release
|
||||
|
||||
- name: Build Debug
|
||||
run: |
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build . -j 4 --config Debug
|
||||
ctest --output-on-failure -C Debug
|
76
.github/workflows/ubuntu.yml
vendored
Normal file
76
.github/workflows/ubuntu.yml
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
name: ubuntu
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler:
|
||||
- { cc: "gcc-9", cxx: "g++-9", os: "ubuntu-20.04" }
|
||||
- { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04" }
|
||||
- { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04" }
|
||||
- { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-20.04" }
|
||||
- { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-20.04" }
|
||||
- { cc: "gcc-12", cxx: "g++-12", os: "ubuntu-22.04" }
|
||||
- { cc: "gcc-13", cxx: "g++-12", os: "ubuntu-22.04" }
|
||||
- { cc: "gcc-14", cxx: "g++-12", os: "ubuntu-22.04" }
|
||||
- { cc: "clang-9", cxx: "clang++-9", os: "ubuntu-20.04" }
|
||||
- { cc: "clang-10", cxx: "clang++-10", os: "ubuntu-20.04" }
|
||||
- { cc: "clang-11", cxx: "clang++-11", os: "ubuntu-20.04" }
|
||||
- { cc: "clang-12", cxx: "clang++-12", os: "ubuntu-20.04" }
|
||||
- { cc: "clang-13", cxx: "clang++-13", os: "ubuntu-20.04" }
|
||||
- { cc: "clang-14", cxx: "clang++-14", os: "ubuntu-20.04" }
|
||||
- { cc: "clang-15", cxx: "clang++-15", os: "ubuntu-20.04" }
|
||||
- { cc: "clang-16", cxx: "clang++-16", os: "ubuntu-20.04" }
|
||||
|
||||
name: "${{ matrix.compiler.cc }}"
|
||||
runs-on: ${{ matrix.compiler.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure clang
|
||||
run: |
|
||||
if [[ "${{ matrix.compiler.cc }}" == "clang"* ]]; then
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-9 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-11 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
|
||||
sudo apt update
|
||||
sudo apt install ${{ matrix.compiler.cc }} -y
|
||||
fi
|
||||
|
||||
- name: Configure gcc
|
||||
run: |
|
||||
if [[ "${{ matrix.compiler.cc }}" == "gcc"* ]]; then
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
sudo apt update
|
||||
sudo apt install ${{ matrix.compiler.cxx }} -y
|
||||
fi
|
||||
|
||||
- name: Build Release
|
||||
run: |
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }}
|
||||
cmake --build . -j 4 --config Release
|
||||
ctest --output-on-failure -C Release
|
||||
|
||||
- name: Build Debug
|
||||
run: |
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }}
|
||||
cmake --build . -j 4 --config Debug
|
||||
ctest --output-on-failure -C Debug
|
43
.github/workflows/windows.yml
vendored
Normal file
43
.github/workflows/windows.yml
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
name: windows
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { os: windows-2019, vs: "Visual Studio 2019" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019
|
||||
- { os: windows-2022, vs: "Visual Studio 2022" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022
|
||||
|
||||
name: "${{ matrix.config.vs }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build Win32
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -A Win32
|
||||
cmake --build . -j 4 --config Release
|
||||
ctest --output-on-failure -C Release
|
||||
cmake --build . -j 4 --config Debug
|
||||
ctest --output-on-failure -C Debug
|
||||
|
||||
- name: Build x64
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -A x64
|
||||
cmake --build . -j 4 --config Release
|
||||
ctest --output-on-failure -C Release
|
||||
cmake --build . -j 4 --config Debug
|
||||
ctest --output-on-failure -C Debug
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
|||
build/
|
||||
.vscode/
|
||||
.vs/
|
||||
|
||||
### C++ gitignore ###
|
||||
# Prerequisites
|
||||
|
|
150
.travis.yml
150
.travis.yml
|
@ -1,150 +0,0 @@
|
|||
os: linux # Use linux unless specified otherwise.
|
||||
dist: xenial
|
||||
sudo: required
|
||||
|
||||
language: cpp
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: g++
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
env:
|
||||
- CXX_COMPILER=g++-7 CC_COMPILER=gcc-7
|
||||
|
||||
- os: linux
|
||||
compiler: g++
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-8
|
||||
env:
|
||||
- CXX_COMPILER=g++-8 CC_COMPILER=gcc-8
|
||||
|
||||
- os: linux
|
||||
compiler: g++
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-9
|
||||
env:
|
||||
- CXX_COMPILER=g++-9 CC_COMPILER=gcc-9
|
||||
|
||||
- os: linux
|
||||
compiler: clang++
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
env:
|
||||
- CXX_COMPILER=clang++-5.0 CC_COMPILER=clang-5.0
|
||||
|
||||
- os: linux
|
||||
compiler: clang++
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-6.0
|
||||
packages:
|
||||
- clang-6.0
|
||||
env:
|
||||
- CXX_COMPILER=clang++-6.0 CC_COMPILER=clang-6.0
|
||||
|
||||
- os: linux
|
||||
compiler: clang++
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-7
|
||||
packages:
|
||||
- clang-7
|
||||
env:
|
||||
- CXX_COMPILER=clang++-7 CC_COMPILER=clang-7
|
||||
|
||||
- os: linux
|
||||
compiler: clang++
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-8
|
||||
packages:
|
||||
- clang-8
|
||||
env:
|
||||
- CXX_COMPILER=clang++-8 CC_COMPILER=clang-8
|
||||
|
||||
- os: osx
|
||||
compiler: clang++
|
||||
osx_image: xcode9.4
|
||||
env:
|
||||
- CXX_COMPILER=clang++ CC_COMPILER=clang
|
||||
|
||||
- os: osx
|
||||
compiler: clang++
|
||||
osx_image: xcode10.2
|
||||
env:
|
||||
- CXX_COMPILER=clang++ CC_COMPILER=clang
|
||||
|
||||
install:
|
||||
- export CC=${CC_COMPILER}
|
||||
- export CXX=${CXX_COMPILER}
|
||||
- JOBS=2 # Travis machines have 2 cores.
|
||||
- |
|
||||
# If linux and clang install the right version of libc++.
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" && "${CXX%%+*}" == "clang" && -n "$(ls -A ${LLVM_INSTALL})" ]]; then
|
||||
LLVM_INSTALL=${DEPS_DIR}/llvm/install
|
||||
if [[ "${CXX}" == "clang++-3.5" ]]; then LLVM_VERSION="3.5.2";
|
||||
elif [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2";
|
||||
elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1";
|
||||
elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1";
|
||||
elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1";
|
||||
elif [[ "${CXX}" == "clang++-4.0" ]]; then LLVM_VERSION="4.0.1";
|
||||
elif [[ "${CXX}" == "clang++-5.0" ]]; then LLVM_VERSION="5.0.2";
|
||||
elif [[ "${CXX}" == "clang++-6.0" ]]; then LLVM_VERSION="6.0.1";
|
||||
elif [[ "${CXX}" == "clang++-7" ]]; then LLVM_VERSION="7.0.1";
|
||||
elif [[ "${CXX}" == "clang++-8" ]]; then LLVM_VERSION="8.0.0";
|
||||
fi
|
||||
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz"
|
||||
LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz"
|
||||
LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz"
|
||||
mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi
|
||||
travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm
|
||||
travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx
|
||||
travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi
|
||||
(cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_INSTALL})
|
||||
(cd llvm/build/projects/libcxx && sudo make install -j${JOBS})
|
||||
(cd llvm/build/projects/libcxxabi && sudo make install -j${JOBS})
|
||||
export CXXFLAGS="-isystem ${LLVM_INSTALL}/include/c++/v1"
|
||||
export LDFLAGS="-L ${LLVM_INSTALL}/lib -l c++ -l c++abi"
|
||||
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_INSTALL}/lib"
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- rm -rf build
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- cmake -G "Unix Makefiles" ..
|
||||
|
||||
script:
|
||||
- cmake --build . -- -j${JOBS}
|
||||
- ctest --output-on-failure -j${JOBS}
|
||||
|
||||
notifications:
|
||||
email: false
|
145
CMakeLists.txt
145
CMakeLists.txt
|
@ -1,6 +1,17 @@
|
|||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.30)
|
||||
|
||||
project(nameof VERSION "0.9.0" LANGUAGES CXX)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(ADDITIONAL_MODULES_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}")
|
||||
|
||||
project(nameof
|
||||
VERSION "0.10.4"
|
||||
HOMEPAGE_URL "https://github.com/Neargye/nameof"
|
||||
DESCRIPTION "A library that provides nameof macros and functions to simply obtain the name of a variable, type, function, macro, and enum."
|
||||
LANGUAGES CXX
|
||||
)
|
||||
set(CPACK_PACKAGE_VENDOR "Daniil Goncharov")
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||
set(IS_TOPLEVEL_PROJECT TRUE)
|
||||
|
@ -10,6 +21,8 @@ endif()
|
|||
|
||||
option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ${IS_TOPLEVEL_PROJECT})
|
||||
option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ${IS_TOPLEVEL_PROJECT})
|
||||
option(NAMEOF_OPT_INSTALL "Generate and install nameof target" ${IS_TOPLEVEL_PROJECT})
|
||||
option(NAMEOF_MODULE "Build nameof module" OFF)
|
||||
|
||||
if(NAMEOF_OPT_BUILD_EXAMPLES)
|
||||
add_subdirectory(example)
|
||||
|
@ -22,27 +35,119 @@ endif()
|
|||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17)
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
set(EXPORT_NAMESPACE "${PROJECT_NAME}::")
|
||||
|
||||
|
||||
set(INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
||||
if(NAMEOF_MODULE)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
add_library(${PROJECT_NAME})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${INCLUDES}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NAMEOF_MODULE)
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
|
||||
|
||||
target_sources(${PROJECT_NAME} PUBLIC FILE_SET nameofModules TYPE CXX_MODULES
|
||||
FILES src/nameof.cpp)
|
||||
else()
|
||||
add_library("${PROJECT_NAME}" INTERFACE)
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
$<BUILD_INTERFACE:${INCLUDES}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
endif()
|
||||
|
||||
write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
add_library("${EXPORT_NAMESPACE}${PROJECT_NAME}" ALIAS "${PROJECT_NAME}")
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}Config)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
DESTINATION lib/cmake/${PROJECT_NAME})
|
||||
|
||||
install(EXPORT ${PROJECT_NAME}Config
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION lib/cmake/${PROJECT_NAME})
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
DESTINATION .)
|
||||
if(NAMEOF_OPT_INSTALL)
|
||||
list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}/GenPkgConfig")
|
||||
include(GenPkgConfig)
|
||||
include(CPackComponent)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
string(REPLACE "/${CMAKE_LIBRARY_ARCHITECTURE}" "" CMAKE_INSTALL_LIBDIR_ARCHIND "${CMAKE_INSTALL_LIBDIR}")
|
||||
install(TARGETS "${PROJECT_NAME}"
|
||||
EXPORT ${PROJECT_NAME}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
FILE_SET nameofModules DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
INCLUDES
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
# COMPONENT "${SDK_COMPONENT_NAME}" # component is not allowed for includes! Headers are installed separately! Includes only marks the headers for export
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE HEADERS "${INCLUDES}/*.h" "${INCLUDES}/*.hxx" "${INCLUDES}/*.hpp")
|
||||
foreach(headerFile ${HEADERS})
|
||||
get_filename_component(headerFileParentDir "${headerFile}" DIRECTORY)
|
||||
file(RELATIVE_PATH headerFileRelParentDir "${INCLUDES}" "${headerFileParentDir}")
|
||||
|
||||
install(FILES "${headerFile}"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${headerFileRelParentDir}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all")
|
||||
set(CPACK_DEBIAN_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-dev")
|
||||
set(CPACK_RPM_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-devel")
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}")
|
||||
set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_MAINTAINER}")
|
||||
set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}")
|
||||
set(CPACK_DEB_COMPONENT_INSTALL ON)
|
||||
set(CPACK_RPM_COMPONENT_INSTALL ON)
|
||||
set(CPACK_NSIS_COMPONENT_INSTALL ON)
|
||||
set(CPACK_DEBIAN_COMPRESSION_TYPE "xz")
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
|
||||
|
||||
set(CMAKE_CONFIG_FILE_BASENAME "${PROJECT_NAME}Config.cmake")
|
||||
set(CMAKE_EXPORT_FILE_BASENAME "${PROJECT_NAME}Export.cmake")
|
||||
set(CMAKE_CONFIG_VERSION_FILE_BASENAME "${PROJECT_NAME}ConfigVersion.cmake")
|
||||
set(CMAKE_CONFIG_VERSION_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_VERSION_FILE_BASENAME}")
|
||||
|
||||
export(TARGETS "${PROJECT_NAME}"
|
||||
NAMESPACE "${EXPORT_NAMESPACE}"
|
||||
FILE "${CMAKE_EXPORT_FILE_BASENAME}"
|
||||
EXPORT_LINK_INTERFACE_LIBRARIES
|
||||
)
|
||||
|
||||
install(EXPORT "${PROJECT_NAME}"
|
||||
FILE "${CMAKE_CONFIG_FILE_BASENAME}"
|
||||
NAMESPACE "${EXPORT_NAMESPACE}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR_ARCHIND}/cmake/${PROJECT_NAME}"
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CONFIG_VERSION_FILE_NAME}"
|
||||
#VERSION "100500.100500.100500" # any version of same bitness suits. CMake cannot compare to infinity, so use a large number we expect to be greater than any future version
|
||||
VERSION ${_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
ARCH_INDEPENDENT
|
||||
)
|
||||
install(FILES "${CMAKE_CONFIG_VERSION_FILE_NAME}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR_ARCHIND}/cmake/${PROJECT_NAME}"
|
||||
)
|
||||
|
||||
configure_pkg_config_file("${PROJECT_NAME}"
|
||||
NAME "${PROJECT_NAME}"
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}"
|
||||
URL "${CPACK_PACKAGE_HOMEPAGE_URL}"
|
||||
INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR_ARCHIND}"
|
||||
INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016, 2018 - 2019 Daniil Goncharov
|
||||
Copyright (c) 2016 - 2024 Daniil Goncharov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
222
README.md
222
README.md
|
@ -1,39 +1,26 @@
|
|||
```text
|
||||
_ _ __ _____
|
||||
| \ | | / _| / ____|_ _
|
||||
| \| | __ _ _ __ ___ ___ ___ | |_ | | _| |_ _| |_
|
||||
| . ` |/ _` | '_ ` _ \ / _ \/ _ \| _| | | |_ _|_ _|
|
||||
| |\ | (_| | | | | | | __/ (_) | | | |____|_| |_|
|
||||
|_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____|
|
||||
```
|
||||
|
||||
[](https://github.com/Neargye/nameof/releases)
|
||||
[](https://github.com/Neargye/nameof/releases)
|
||||
[](https://conan.io/center/recipes/nameof)
|
||||
[](https://github.com/microsoft/vcpkg/tree/master/ports/nameof)
|
||||
[](LICENSE)
|
||||
[](https://travis-ci.org/Neargye/nameof)
|
||||
[](https://ci.appveyor.com/project/Neargye/nameof/branch/master)
|
||||
[](https://www.codacy.com/app/Neargye/nameof?utm_source=github.com&utm_medium=referral&utm_content=Neargye/nameof&utm_campaign=Badge_Grade)
|
||||
[](https://wandbox.org/permlink/XjaqDqqHOGJT56HE)
|
||||
[](https://godbolt.org/z/s_ecko)
|
||||
[](https://stand-with-ukraine.pp.ua)
|
||||
|
||||
# Nameof C++
|
||||
|
||||
Header-only C++17 library provides nameof macros and functions to obtain simple name of variable, type, function, macro, and enum.
|
||||
Header-only C++17 library provides nameof macros and functions to simply obtain the name of a variable, type, function, macro, and enum.
|
||||
|
||||
## Features
|
||||
If you like this project, please consider donating to one of the funds that help victims of the war in Ukraine: https://u24.gov.ua.
|
||||
|
||||
* C++17
|
||||
* Header-only
|
||||
* Dependency-free
|
||||
* Compile-time
|
||||
* Name of variable, member variable
|
||||
* Name of type, variable type
|
||||
* Name of function, member function
|
||||
* Name of enum, enum variable
|
||||
* Name of macro
|
||||
* Enum to string
|
||||
## Documentation
|
||||
|
||||
## [Examples](example/example.cpp)
|
||||
* [Reference](doc/reference.md)
|
||||
* [Limitations](doc/limitations.md)
|
||||
* [Integration](#Integration)
|
||||
|
||||
## [Features & Examples](example/example.cpp)
|
||||
|
||||
* Nameof
|
||||
|
||||
```cpp
|
||||
// Name of variable.
|
||||
NAMEOF(somevar) -> "somevar"
|
||||
|
@ -51,10 +38,19 @@ Header-only C++17 library provides nameof macros and functions to obtain simple
|
|||
// Name of macro.
|
||||
NAMEOF(__LINE__) -> "__LINE__"
|
||||
NAMEOF(NAMEOF(structvar)) -> "NAMEOF"
|
||||
|
||||
// Obtains full name of variable, function, macro.
|
||||
NAMEOF_FULL(somevar.some_method<int>()) -> "some_method<int>"
|
||||
|
||||
// Obtains raw name of variable, function, macro.
|
||||
NAMEOF_RAW(somevar.some_method<int>()) -> "somevar.some_method<int>()"
|
||||
```
|
||||
|
||||
* Nameof enum
|
||||
|
||||
```cpp
|
||||
enum class Color { RED = 1, BLUE = 2, GREEN = 4 };
|
||||
|
||||
auto color = Color::RED;
|
||||
// Name of enum variable.
|
||||
NAMEOF_ENUM(color) -> "RED"
|
||||
|
@ -62,134 +58,88 @@ Header-only C++17 library provides nameof macros and functions to obtain simple
|
|||
|
||||
// Static storage enum variable to string.
|
||||
// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
|
||||
NAMEOF_CONST_ENUM(Color::GREEN) -> "GREEN"
|
||||
NAMEOF_ENUM_CONST(Color::GREEN) -> "GREEN"
|
||||
nameof::nameof_enum<Color::GREEN>() -> "GREEN"
|
||||
|
||||
// Enum flags variable to string.
|
||||
NAMEOF_ENUM_FLAG(Color::GREEN | Color::BLUE) -> "GREEN|BLUE"
|
||||
nameof::nameof_enum_flag<Color::GREEN | Color::BLUE>() -> "GREEN|BLUE"
|
||||
|
||||
// Obtains name of enum variable or default value if enum variable out of range.
|
||||
NAMEOF_ENUM_OR(Color::GREEN) -> "GREEN"
|
||||
NAMEOF_ENUM_OR((Color)0, "none") -> "none"
|
||||
```
|
||||
|
||||
* Nameof type
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
T var = 42;
|
||||
const my::detail::SomeClass<int>& var_ref = var;
|
||||
// Name of variable type.
|
||||
NAMEOF_TYPE_EXPR(var) -> "int"
|
||||
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&"
|
||||
nameof::nameof_type<decltype(var)>() -> "int"
|
||||
nameof::nameof_full_type<decltype(var)>() -> "const int&"
|
||||
NAMEOF_TYPE_EXPR(var_ref) -> "my::detail::SomeClass<int>"
|
||||
nameof::nameof_type<decltype(var_ref)>() -> "my::detail::SomeClass<int>"
|
||||
NAMEOF_FULL_TYPE_EXPR(var_ref) -> "const my::detail::SomeClass<int>&"
|
||||
nameof::nameof_full_type<decltype(var_ref)>() -> "const my::detail::SomeClass<int>&"
|
||||
NAMEOF_SHORT_TYPE_EXPR(var_ref) -> "SomeClass"
|
||||
nameof::nameof_short_type<decltype(var_ref)>() -> "SomeClass"
|
||||
|
||||
using T = const my::detail::SomeClass<int>&;
|
||||
// Name of type.
|
||||
NAMEOF_TYPE(T) -> "int"
|
||||
NAMEOF_FULL_TYPE(T) -> "const int&"
|
||||
nameof::nameof_type<T>() -> "int"
|
||||
nameof::nameof_full_type<T>() -> "const int&"
|
||||
```
|
||||
NAMEOF_TYPE(T) ->"my::detail::SomeClass<int>"
|
||||
nameof::nameof_type<T>() -> "my::detail::SomeClass<int>"
|
||||
NAMEOF_FULL_TYPE(T) -> "const my::detail::SomeClass<int>&"
|
||||
nameof::nameof_full_type<T>() -> "const my::detail::SomeClass<int>&"
|
||||
NAMEOF_SHORT_TYPE(T) -> "SomeClass"
|
||||
nameof::nameof_short_type<T>() -> "SomeClass"
|
||||
|
||||
* Compile-time
|
||||
```cpp
|
||||
constexpr auto somevar_name = NAMEOF(somevar);
|
||||
// somevar_name -> "somevar"
|
||||
constexpr auto color_name = NAMEOF_ENUM(Color::BLUE); // or nameof::nameof_enum(Color::BLUE)
|
||||
// color_name -> "BLUE"
|
||||
constexpr auto var_type_name = NAMEOF_TYPE_EXPR(var); // or nameof::nameof_type<decltype(var)>()
|
||||
// var_type_name -> "int"
|
||||
constexpr auto type_name = NAMEOF_TYPE(T); // or nameof::nameof_type<T>()
|
||||
// type_name -> "int"
|
||||
my::detail::Base* ptr = new my::detail::Derived();
|
||||
// Name of type, using rtti.
|
||||
NAMEOF_TYPE_RTTI(*ptr) -> "my::detail::Derived"
|
||||
NAMEOF_FULL_TYPE_RTTI(*ptr) -> "volatile const my::detail::Derived&"
|
||||
NAMEOF_SHORT_TYPE_RTTI(*ptr) -> "Derived"
|
||||
|
||||
struct A {
|
||||
int this_is_the_name;
|
||||
};
|
||||
// Obtains name of member.
|
||||
NAMEOF_MEMBER(&A::this_is_the_name) -> "this_is_the_name"
|
||||
nameof::nameof_member(&A::this_is_the_name) -> "this_is_the_name"
|
||||
|
||||
int someglobalvariable = 0;
|
||||
// Obtains name of a function, a global or class static variable.
|
||||
NAMEOF_POINTER(&someglobalconstvariable) == "someglobalconstvariable"
|
||||
nameof::nameof_pointer(&someglobalconstvariable) == "someglobalconstvariable"
|
||||
|
||||
constexpr auto global_ptr = &someglobalvariable;
|
||||
NAMEOF_POINTER(global_ptr) == "someglobalconstvariable"
|
||||
nameof::nameof_pointer(global_ptr) == "someglobalconstvariable"
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
||||
* Nameof returns `std::string_view`. If argument does not have name, returns empty string.
|
||||
|
||||
* Nameof expression argument are identified, but are not evaluated.
|
||||
|
||||
* Nameof type returns compiler-specific type name. In all cases, reference and cv-qualifiers are ignored by `nameof_type` (that is, `nameof_type<const T&>() == nameof_type<T>()`). If you need detailed name of full type, use `nameof_full_type`.
|
||||
|
||||
* If you need name with template suffix, use NAMEOF_FULL.
|
||||
```cpp
|
||||
// Full name of template function.
|
||||
NAMEOF_FULL(foo<int, float>()) -> "foo<int, float>"
|
||||
|
||||
// Full name of template member function.
|
||||
NAMEOF_FULL(somevar.some_method<int>()) -> "some_method<int>"
|
||||
```
|
||||
|
||||
* If you need raw fully-qualified name, use NAMEOF_RAW.
|
||||
```cpp
|
||||
NAMEOF_RAW(::somevar.somefield) -> "::somevar.somefield"
|
||||
NAMEOF_RAW(&some_class::some_method<int>) -> "&some_class::some_method<int>"
|
||||
```
|
||||
|
||||
* Enum value must be in range `[NAMEOF_ENUM_RANGE_MIN, NAMEOF_ENUM_RANGE_MAX]`. By default `NAMEOF_ENUM_RANGE_MIN = -128`, `NAMEOF_ENUM_RANGE_MAX = 128`.
|
||||
|
||||
If need another range for all enum types by default, redefine the macro `NAMEOF_ENUM_RANGE_MIN` and `NAMEOF_ENUM_RANGE_MAX`.
|
||||
```cpp
|
||||
#define NAMEOF_ENUM_RANGE_MIN 0
|
||||
#define NAMEOF_ENUM_RANGE_MAX 256
|
||||
#include <nameof.hpp>
|
||||
```
|
||||
|
||||
If need another range for specific enum type, add specialization `enum_range` for necessary enum type.
|
||||
```cpp
|
||||
#include <nameof.hpp>
|
||||
|
||||
enum number { one = 100, two = 200, three = 300 };
|
||||
|
||||
namespace nameof {
|
||||
template <>
|
||||
struct enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
* Nameof enum obtains the first defined value enums, and won't work if value are aliased.
|
||||
```cpp
|
||||
enum ShapeKind {
|
||||
ConvexBegin = 0,
|
||||
Box = 0, // Won't work.
|
||||
Sphere = 1,
|
||||
ConvexEnd = 2,
|
||||
Donut = 2, // Won't work too.
|
||||
Banana = 3,
|
||||
COUNT = 4,
|
||||
};
|
||||
// NAMEOF_ENUM(ShapeKind::Box) -> "ConvexBegin"
|
||||
// nameof::nameof_enum(ShapeKind::Box) -> "ConvexBegin"
|
||||
```
|
||||
Work around the issue:
|
||||
```cpp
|
||||
enum ShapeKind {
|
||||
// Convex shapes, see ConvexBegin and ConvexEnd below.
|
||||
Box = 0,
|
||||
Sphere = 1,
|
||||
|
||||
// Non-convex shapes.
|
||||
Donut = 2,
|
||||
Banana = 3,
|
||||
|
||||
COUNT = Banana + 1,
|
||||
|
||||
// Non-reflected aliases.
|
||||
ConvexBegin = Box,
|
||||
ConvexEnd = Sphere + 1,
|
||||
};
|
||||
// NAMEOF_ENUM(ShapeKind::Box) -> "Box"
|
||||
// nameof::nameof_enum(ShapeKind::Box) -> "Box"
|
||||
|
||||
// Non-reflected aliases.
|
||||
// NAMEOF_ENUM(ShapeKind::ConvexBegin) -> "Box"
|
||||
// nameof::nameof_enum(ShapeKind::ConvexBegin) -> "Box"
|
||||
```
|
||||
* Before use, read the [limitations](doc/limitations.md) of functionality.
|
||||
|
||||
## Integration
|
||||
|
||||
You should add required file [nameof.hpp](include/nameof.hpp).
|
||||
|
||||
If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nameof package](https://github.com/microsoft/vcpkg/tree/master/ports/nameof).
|
||||
|
||||
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nameof/x.y.z` to your conan's requires, where `x.y.z` is the release version you want to use.
|
||||
|
||||
Archlinux users can install `nameof` by package manager AUR, using the following command: `yay -S nameof`.
|
||||
|
||||
Alternatively, you can use something like [CPM](https://github.com/TheLartians/CPM) which is based on CMake's `Fetch_Content` module.
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME nameof
|
||||
GITHUB_REPOSITORY Neargye/nameof
|
||||
GIT_TAG x.y.z # Where `x.y.z` is the release version you want to use.
|
||||
)
|
||||
```
|
||||
|
||||
## Compiler compatibility
|
||||
|
||||
* Clang/LLVM >= 5
|
||||
* Visual C++ >= 15.3 / Visual Studio >= 2017
|
||||
* Xcode >= 9
|
||||
* GCC >= 7 (GCC >= 9 for NAMEOF_ENUM)
|
||||
Check in the [reference](doc/reference.md) for each features.
|
||||
|
||||
## Licensed under the [MIT License](LICENSE)
|
||||
|
|
239
cmake/GenPkgConfig/GenPkgConfig.cmake
Normal file
239
cmake/GenPkgConfig/GenPkgConfig.cmake
Normal file
|
@ -0,0 +1,239 @@
|
|||
#[=======================================================================[.rst:
|
||||
|
||||
GenPkgConfig
|
||||
------------
|
||||
|
||||
This is the library helping you to generate and install pkg-config files.
|
||||
|
||||
Unlicense
|
||||
^^^^^^^^^
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
For more information, please refer to <https://unlicense.org/>
|
||||
|
||||
Warning
|
||||
^^^^^^^
|
||||
|
||||
CMake is currently merging a built-in impl of pkg-config file generator! https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363
|
||||
|
||||
Functions
|
||||
^^^^^^^^^
|
||||
.. command:: configure_pkg_config_file
|
||||
|
||||
.. versionadded:: 3.22
|
||||
|
||||
Generates a pkg-config file for
|
||||
|
||||
::
|
||||
|
||||
configure_pkg_config_file(<targetName>
|
||||
NAME <name of the package>
|
||||
VERSION <version to be written into the package>
|
||||
DESCRIPTION <description to be written into the package>
|
||||
URL <homepage URL to be written into the package>
|
||||
COMPONENT <install as the component>
|
||||
INSTALL_LIB_DIR <path to something like CMAKE_INSTALL_LIBDIR>
|
||||
INSTALL_INCLUDE_DIR <path to something like CMAKE_INSTALL_INCLUDEDIR>
|
||||
REQUIRES ... <list of pkg-config packages this one depends on> ...
|
||||
REQUIRES ... <list of pkg-config packages this one conflicts with> ...
|
||||
)
|
||||
|
||||
The arguments are optional and usually are not needed to be set if global (not component-specific) CPACK vars have been set before.
|
||||
|
||||
Generation is done in build time using packaging expressions.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
set("GEN_PKG_CONFIG_WORKAROUNDS_BUILD_TIME_SCRIPTS" "${CMAKE_CURRENT_LIST_DIR}/buildTimeScripts")
|
||||
|
||||
cmake_policy(SET CMP0070 NEW)
|
||||
|
||||
function(configure_pkg_config_file TARGET)
|
||||
cmake_parse_arguments(""
|
||||
"" # options
|
||||
"NAME;VERSION;DESCRIPTION;URL;COMPONENT;INSTALL_LIB_DIR;INSTALL_INCLUDE_DIR" # one_value_keywords
|
||||
"REQUIRES;CONFLICTS" # multi_value_keywords
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
configure_pkg_config_file_vars("${TARGET}" "${_NAME}" "${_INSTALL_LIB_DIR}" "${_INSTALL_INCLUDE_DIR}" "${_COMPONENT}" "${_DESCRIPTION}" "${_URL}" "${_VERSION}" "${_REQUIRES}" "${_CONFLICTS}")
|
||||
endfunction()
|
||||
|
||||
function(ge_expr_basename inputExpr outVar)
|
||||
set("${outVar}" "$<TARGET_PROPERTY:${inputExpr}>" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(configure_pkg_config_file_vars TARGET _NAME _INSTALL_LIB_DIR _INSTALL_INCLUDE_DIR _COMPONENT _DESCRIPTION _URL _VERSION _REQUIRES _CONFLICTS)
|
||||
#$<TARGET_PROPERTY:${TARGET},NAME>
|
||||
#INTERFACE_LINK_DIRECTORIES
|
||||
#INTERFACE_LINK_LIBRARIES
|
||||
#INTERFACE_LINK_OPTIONS
|
||||
|
||||
if(_NAME)
|
||||
else()
|
||||
set(_NAME "$<TARGET_PROPERTY:${TARGET},NAME>")
|
||||
endif()
|
||||
|
||||
if(_DESCRIPTION)
|
||||
else()
|
||||
set(_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}")
|
||||
endif()
|
||||
|
||||
if(_VERSION)
|
||||
else()
|
||||
set(_VERSION "${CPACK_PACKAGE_VERSION}")
|
||||
endif()
|
||||
|
||||
if(_URL)
|
||||
else()
|
||||
set(_URL "${CPACK_PACKAGE_HOMEPAGE_URL}")
|
||||
endif()
|
||||
|
||||
if(INSTALL_INCLUDE_DIR)
|
||||
else()
|
||||
set(INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
endif()
|
||||
|
||||
if(INSTALL_LIB_DIR)
|
||||
else()
|
||||
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
set(PKG_CONFIG_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}.pc")
|
||||
|
||||
set(PUBLIC_INCLUDES "$<TARGET_PROPERTY:${TARGET},INTERFACE_INCLUDE_DIRECTORIES>")
|
||||
set(PUBLIC_LIBS "$<TARGET_PROPERTY:${TARGET},INTERFACE_LINK_LIBRARIES>")
|
||||
set(PUBLIC_COMPILE_FLAGS "$<TARGET_PROPERTY:${TARGET},INTERFACE_COMPILE_DEFINITIONS>")
|
||||
|
||||
set("IS_INTERFACE" "$<STREQUAL:$<TARGET_PROPERTY:${TARGET},TYPE>,INTERFACE_LIBRARY>")
|
||||
set("IS_OBJECT" "$<STREQUAL:$<TARGET_PROPERTY:${TARGET},TYPE>,OBJECT_LIBRARY>")
|
||||
get_target_property(CONFIGURE_TIME_TARGET_TYPE "${TARGET}" TYPE)
|
||||
if(CONFIGURE_TIME_TARGET_TYPE STREQUAL OBJECT_LIBRARY)
|
||||
set(CONFIGURE_TIME_IS_OBJECT ON) # Special measures have to be taken!!!
|
||||
endif()
|
||||
|
||||
set("NEEDS_LIBS" "$<AND:$<NOT:${IS_INTERFACE}>,$<NOT:${IS_OBJECT}>>")
|
||||
set("NEEDS_LIB_DIR" "$<NOT:${IS_INTERFACE}>")
|
||||
string(REPLACE "," "$<COMMA>" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS}")
|
||||
string(REPLACE ">" "$<ANGLE-R>" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS_ESCAPED}")
|
||||
|
||||
list(APPEND header "prefix=${CMAKE_INSTALL_PREFIX}")
|
||||
list(APPEND header "$<IF:$<OR:$<BOOL:${PUBLIC_LIBS}>,${NEEDS_LIB_DIR}>,libdir=\${prefix}/${INSTALL_LIB_DIR},>")
|
||||
list(APPEND header "$<IF:$<BOOL:${PUBLIC_INCLUDES}>,includedir=\${prefix}/${INSTALL_INCLUDE_DIR},>")
|
||||
|
||||
|
||||
list(APPEND libSpecific "Name: ${_NAME}")
|
||||
if(_DESCRIPTION)
|
||||
list(APPEND libSpecific "Description: ${_DESCRIPTION}")
|
||||
endif()
|
||||
if(_URL)
|
||||
list(APPEND libSpecific "URL: ${_URL}")
|
||||
endif()
|
||||
if(_VERSION)
|
||||
list(APPEND libSpecific "Version: ${_VERSION}")
|
||||
endif()
|
||||
if(_REQUIRES)
|
||||
list(APPEND libSpecific "Requires: ${_REQUIRES}")
|
||||
endif()
|
||||
if(_CONFLICTS)
|
||||
list(APPEND libSpecific "Conflicts: ${_CONFLICTS}")
|
||||
endif()
|
||||
|
||||
set(OTHER_INCLUDE_FLAGS "-I$<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_INCLUDES}>, -I>") # Not needed, we can only get build interface flags here. Insert them after -I\${includedir} if you find a way to fix/workaround it
|
||||
|
||||
# Here is a workaround to inability to use TARGET_LINKER_FILE_NAME for targets not involving library generation.
|
||||
# Strangely $<IF evaluates both branches, not only the one taken, which causes an error
|
||||
# We workaround it by generating the subexpression source using $<IF and then evaluating it using $<GENEX_EVAL
|
||||
# Of course we could have used conditional expressions on CMake script part, but I have decided to implement it in generator expressions part, so hypthetically all the expressions can be merged into a single file and this function can be made simple
|
||||
|
||||
set(ESCAPED_GENEXPR_BEGINNING "$<1:$><") # A hack because there is no escape for `$` or `<` or `$<`. So we just disrupt $< into pieces
|
||||
set(CURRENT_LIB_ESCAPED_BINARY_NAME "${ESCAPED_GENEXPR_BEGINNING}TARGET_LINKER_FILE_NAME:${TARGET}$<ANGLE-R>")
|
||||
set(LINK_CURRENT_LIB_FLAG "$<GENEX_EVAL:$<IF:${NEEDS_LIBS},-l:${CURRENT_LIB_ESCAPED_BINARY_NAME},>>")
|
||||
|
||||
if(CONFIGURE_TIME_IS_OBJECT)
|
||||
set(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE ON)
|
||||
if(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE)
|
||||
message(WARNING "CMake is shit: There is (at least was at the time of writing of this code) no generator expression to get only basenames of object files. They are also unavailable at configure stage. And there were no CMake generator expressions for making replacements in strings. So we workaround this.")
|
||||
set(TARGET_OBJECTS_FILE "${TARGET}.obj_list")
|
||||
set(OBJECTS_FILE_RETRIEVAL_TARGET_NAME "${TARGET}_get_objects_list")
|
||||
|
||||
set(PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME "${TARGET}_pkgconfig_unfinished")
|
||||
set(PKGCONFIG_PATCH_TARGET_NAME "${TARGET}_patch_pkgconfig")
|
||||
|
||||
set(PKG_CONFIG_FILE_NAME_FINISHED "${PKG_CONFIG_FILE_NAME}")
|
||||
set(PKG_CONFIG_FILE_NAME_UNFINISHED "${PKG_CONFIG_FILE_NAME_FINISHED}.unfinished")
|
||||
|
||||
file(GENERATE OUTPUT "${TARGET_OBJECTS_FILE}" CONTENT "$<TARGET_OBJECTS:${TARGET}>")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${TARGET_OBJECTS_FILE}"
|
||||
COMMENT "A dummy command to workaround cmake limitations"
|
||||
)
|
||||
add_custom_target("${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}"
|
||||
DEPENDS "${TARGET_OBJECTS_FILE}"
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${PKG_CONFIG_FILE_NAME_FINISHED}"
|
||||
PRE_BUILD COMMAND ${CMAKE_COMMAND} "-DobjectsFile=\"${TARGET_OBJECTS_FILE}\"" "-DpkgConfigFileUnlinished=\"${PKG_CONFIG_FILE_NAME_UNFINISHED}\"" "-DpkgConfigFileFinal=\"${PKG_CONFIG_FILE_NAME_FINISHED}\"" "-P" "${GEN_PKG_CONFIG_WORKAROUNDS_BUILD_TIME_SCRIPTS}/getObjectFilesBaseNames.cmake"
|
||||
MAIN_DEPENDENCY "${TARGET_OBJECTS_FILE}"
|
||||
DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
|
||||
COMMENT "Working around CMake limitations about getting list of basenames of object files and about lack of generator expressions to modify strings: ${PKG_CONFIG_FILE_NAME_UNFINISHED} + ${TARGET_OBJECTS_FILE} -> ${PKG_CONFIG_FILE_NAME_FINISHED}"
|
||||
)
|
||||
add_custom_target("${PKGCONFIG_PATCH_TARGET_NAME}" ALL
|
||||
DEPENDS "${PKG_CONFIG_FILE_NAME_FINISHED}"
|
||||
)
|
||||
add_dependencies("${PKGCONFIG_PATCH_TARGET_NAME}" "${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}" "${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}")
|
||||
|
||||
set(PROPERLY_JOINED_TARGET_OBJECTS "@PROPERLY_JOINED_TARGET_OBJECTS@")
|
||||
else()
|
||||
set("RAW_TARGET_OBJECTS" "$<TARGET_OBJECTS:${TARGET}>")
|
||||
message(FATAL_ERROR "This branch is unimplemented because CMake lacked the needed functionality at the time")
|
||||
set(PROPERLY_JOINED_TARGET_OBJECTS "${RAW_TARGET_OBJECTS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LINK_CURRENT_OBJECT_FLAG "$<IF:${IS_OBJECT},${PROPERLY_JOINED_TARGET_OBJECTS},>")
|
||||
|
||||
list(APPEND libSpecific "$<IF:$<OR:$<BOOL:${PUBLIC_LIBS}>,${NEEDS_LIBS},${IS_OBJECT}>,Libs: -L\${libdir} ${LINK_CURRENT_LIB_FLAG} ${LINK_CURRENT_OBJECT_FLAG} $<IF:$<BOOL:${PUBLIC_LIBS}>,-l$<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_LIBS}>, -l>,>,>\n$<IF:$<OR:$<BOOL:${PUBLIC_INCLUDES}>,$<BOOL:${PUBLIC_COMPILE_FLAGS}>>,Cflags: -I\${includedir} $<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_COMPILE_FLAGS}>,>,>")
|
||||
|
||||
|
||||
list(JOIN header "\n" header)
|
||||
list(JOIN libSpecific "\n" libSpecific)
|
||||
set(libSpecific "${header}\n\n${libSpecific}")
|
||||
|
||||
if(CONFIGURE_TIME_IS_OBJECT)
|
||||
file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
|
||||
CONTENT "${libSpecific}"
|
||||
)
|
||||
|
||||
# Dummy target for generated files
|
||||
add_custom_command(
|
||||
OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
|
||||
COMMENT "A dummy command to workaround cmake limitations"
|
||||
)
|
||||
add_custom_target("${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}"
|
||||
DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
|
||||
)
|
||||
|
||||
|
||||
install(FILES "${PKG_CONFIG_FILE_NAME_FINISHED}"
|
||||
DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig"
|
||||
COMPONENT "${_COMPONENT}"
|
||||
)
|
||||
else()
|
||||
file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME}"
|
||||
CONTENT "${libSpecific}"
|
||||
)
|
||||
|
||||
|
||||
install(FILES "${PKG_CONFIG_FILE_NAME}"
|
||||
DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig"
|
||||
COMPONENT "${_COMPONENT}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
45
cmake/GenPkgConfig/ReadMe.md
Normal file
45
cmake/GenPkgConfig/ReadMe.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
GenPkgConfig.cmake
|
||||
===================
|
||||
|
||||
A script generating pkg-config files.
|
||||
|
||||
WARNING: CMake [is currently merging own built-in pkgconfig generation implementation](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363)!
|
||||
|
||||
If you require such a new version of CMake, you probably should use the built-in impl instead.
|
||||
|
||||
Syntax
|
||||
------
|
||||
|
||||
```cmake
|
||||
configure_pkg_config_file(<targetName>
|
||||
NAME <name of the pkgconfig package>
|
||||
VERSION <version to be written into the package>
|
||||
DESCRIPTION <description to be written into the package>
|
||||
URL <homepage URL to be written into the package>
|
||||
COMPONENT <install as the component>
|
||||
INSTALL_LIB_DIR <path to something like CMAKE_INSTALL_LIBDIR>
|
||||
INSTALL_INCLUDE_DIR <path to something like CMAKE_INSTALL_INCLUDEDIR>
|
||||
REQUIRES ... <list of pkg-config packages this one depends on> ...
|
||||
REQUIRES ... <list of pkg-config packages this one conflicts with> ...
|
||||
)
|
||||
```
|
||||
|
||||
Issuees
|
||||
-------
|
||||
|
||||
1. For `OBJECT` targets we have run into big issues. CMake
|
||||
1. Doesn't allow to get the list of object files at configure time
|
||||
2. Allows to get a list of object files as a generator exression ...
|
||||
3. BUT ... the path to them is full, but we need only file name!
|
||||
4. CMake doesn't allow to strip directory path via generator expression
|
||||
5. ... neither it allows string editing within generator expressions ...
|
||||
|
||||
so ... we have to create a custom target using a custom CMake script executed separately, but ...
|
||||
|
||||
6. `file(GENERATE` doesn't properly register dependencies
|
||||
... so we have to use `add_custom_command` to say CMake that these files are generated
|
||||
|
||||
7. And CMake `install(FILES` doesn't mean that the targets generating these files are automatically executed,
|
||||
|
||||
So we have to use `ALL` in `add_custom_target`.
|
||||
|
24
cmake/GenPkgConfig/UNLICENSE
Normal file
24
cmake/GenPkgConfig/UNLICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org/>
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
message(STATUS "objectsFile ${objectsFile}")
|
||||
message(STATUS "pkgConfigFileFinal ${pkgConfigFileFinal}")
|
||||
message(STATUS "pkgConfigFileUnlinished ${pkgConfigFileUnlinished}")
|
||||
|
||||
file(READ "${objectsFile}" TARGET_OBJECTS)
|
||||
|
||||
set(PROPERLY_JOINED_TARGET_OBJECTS "")
|
||||
|
||||
foreach(objFullPath ${TARGET_OBJECTS})
|
||||
get_filename_component(objFullPath "${objFullPath}" NAME)
|
||||
list(APPEND PROPERLY_JOINED_TARGET_OBJECTS "${objFullPath}")
|
||||
endforeach()
|
||||
list(JOIN PROPERLY_JOINED_TARGET_OBJECTS " " PROPERLY_JOINED_TARGET_OBJECTS)
|
||||
|
||||
message(STATUS "PROPERLY_JOINED_TARGET_OBJECTS AFTER ${PROPERLY_JOINED_TARGET_OBJECTS}")
|
||||
|
||||
configure_file("${pkgConfigFileUnlinished}" "${pkgConfigFileFinal}" @ONLY)
|
68
doc/limitations.md
Normal file
68
doc/limitations.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Limitations
|
||||
|
||||
## Nameof
|
||||
|
||||
* If the argument does not have a name, the compilation error `"Expression does not have a name."` occurs.
|
||||
|
||||
## Nameof Type
|
||||
|
||||
* This library uses a compiler-specific hack (based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`).
|
||||
|
||||
* nameof_type and nameof_type_rtti return a compiler-specific type name.
|
||||
|
||||
* To check if nameof_type is supported by your compiler use the macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.</br>
|
||||
If nameof_type is used on an unsupported compiler, a compilation error occurs. To suppress the error define the macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check if nameof_type_rtti is supported by your compiler use macro `NAMEOF_TYPE_RTTI_SUPPORTED` or constexpr constant `nameof::is_nameof_type_rtti_supported`.</br>
|
||||
If nameof_type_rtti is used on an unsupported compiler, a compilation error occurs. To suppress the error define the macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_member supported compiler use macro `NAMEOF_MEMBER_SUPPORTED` or constexpr constant `nameof::is_nameof_member_supported`.</br>
|
||||
If nameof_member used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_pointer supported compiler use macro `NAMEOF_POINTER_SUPPORTED` or constexpr constant `nameof::is_nameof_pointer_supported`.</br>
|
||||
If nameof_pointer used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
## Nameof Enum
|
||||
|
||||
* This library uses a compiler-specific hack (based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 9.
|
||||
|
||||
* Do not use [nameof](https://github.com/Neargye/nameof) and [magic_enum](https://github.com/Neargye/magic_enum) in the same project to get enum name.
|
||||
|
||||
* To check if nameof_enum is supported by your compiler use the macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.</br>
|
||||
If nameof_enum is used on an unsupported compiler, a compilation error occurs. To suppress the error define the macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
|
||||
|
||||
* Enum value must be in range `[NAMEOF_ENUM_RANGE_MIN, NAMEOF_ENUM_RANGE_MAX]`.
|
||||
|
||||
* By default `NAMEOF_ENUM_RANGE_MIN = -128`, `NAMEOF_ENUM_RANGE_MAX = 128`.
|
||||
|
||||
* `NAMEOF_ENUM_RANGE_MIN` must be less than or equal to `0` and must be greater than `INT16_MIN`.
|
||||
|
||||
* `NAMEOF_ENUM_RANGE_MAX` must be greater than `0` and must be less than `INT16_MAX`.
|
||||
|
||||
* If another range is needed for all enum types by default, redefine the macro `NAMEOF_ENUM_RANGE_MIN` and `NAMEOF_ENUM_RANGE_MAX`.
|
||||
|
||||
```cpp
|
||||
#define NAMEOF_ENUM_RANGE_MIN 0
|
||||
#define NAMEOF_ENUM_RANGE_MAX 256
|
||||
#include <nameof.hpp>
|
||||
```
|
||||
|
||||
* If another range is needed for a specific enum type, add specialization `enum_range` for necessary enum type. Specialization of `enum_range` must be injected in `namespace nameof::customize`.
|
||||
|
||||
```cpp
|
||||
#include <nameof.hpp>
|
||||
|
||||
enum class number { one = 100, two = 200, three = 300 };
|
||||
|
||||
template <>
|
||||
struct nameof::customize::enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
```
|
||||
|
||||
* Won't work if a value is aliased, support for enum-aliases is compiler-implementation-defined.
|
||||
|
||||
* Won't work if the enum is a forward declaration.
|
||||
|
||||
* Intellisense Visual Studio may have some problems analyzing `nameof`.
|
462
doc/reference.md
Normal file
462
doc/reference.md
Normal file
|
@ -0,0 +1,462 @@
|
|||
# Reference
|
||||
|
||||
* [`NAMEOF` obtains simple name of variable, function, macro.](#nameof)
|
||||
* [`NAMEOF_FULL` obtains full name of variable, function, macro.](#nameof_full)
|
||||
* [`NAMEOF_RAW` obtains raw name of variable, function, macro.](#nameof_raw)
|
||||
* [`NAMEOF_ENUM` obtains name of enum variable.](#nameof_enum)
|
||||
* [`NAMEOF_ENUM_OR` Obtains name of enum variable or default value if enum variable out of range.](#nameof_enum_or)
|
||||
* [`NAMEOF_ENUM_CONST` obtains name of static storage enum variable.](#nameof_enum_const)
|
||||
* [`NAMEOF_ENUM_FLAG` obtains name of enum-flags variable.](#nameof_enum_flag)
|
||||
* [`NAMEOF_TYPE` obtains type name.](#nameof_type)
|
||||
* [`NAMEOF_FULL_TYPE` obtains full type name.](#nameof_full_type)
|
||||
* [`NAMEOF_SHORT_TYPE` obtains short type name.](#nameof_short_type)
|
||||
* [`NAMEOF_TYPE_EXPR` obtains type name of expression.](#nameof_type_expr)
|
||||
* [`NAMEOF_FULL_TYPE_EXPR` obtains full type name of expression.](#nameof_full_type_expr)
|
||||
* [`NAMEOF_SHORT_TYPE_EXPR` obtains short type name of expression.](#nameof_short_type_expr)
|
||||
* [`NAMEOF_TYPE_RTTI` obtains type name, using RTTI.](#nameof_type_rtti)
|
||||
* [`NAMEOF_FULL_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_full_type_rtti)
|
||||
* [`NAMEOF_SHORT_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_short_type_rtti)
|
||||
* [`NAMEOF_MEMBER` obtains name of member.](#nameof_member)
|
||||
* [`NAMEOF_POINTER` obtains name of a function, a global or class static variable.](#nameof_pointer)
|
||||
|
||||
## Synopsis
|
||||
|
||||
* Before use, read the [limitations](limitations.md) of functionality.
|
||||
|
||||
* To check is nameof_enum supported compiler use macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.</br>
|
||||
If nameof_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_type supported compiler use macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.</br>
|
||||
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_type_rtti supported compiler use macro `NAMEOF_TYPE_RTTI_SUPPORTED` or constexpr constant `nameof::is_nameof_type_rtti_supported`.</br>
|
||||
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_member supported compiler use macro `NAMEOF_MEMBER_SUPPORTED` or constexpr constant `nameof::is_nameof_member_supported`.</br>
|
||||
If nameof_member used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_pointer supported compiler use macro `NAMEOF_POINTER_SUPPORTED` or constexpr constant `nameof::is_nameof_pointer_supported`.</br>
|
||||
If nameof_pointer used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To add custom enum or type names see the [example](../example/example_custom_name.cpp).
|
||||
|
||||
* To change the type of strings, use special macros:
|
||||
|
||||
```cpp
|
||||
#include <my_lib/string.hpp>
|
||||
#include <my_lib/string_view.hpp>
|
||||
#define NAMEOF_USING_ALIAS_STRING using string = my_lib::String;
|
||||
#define NAMEOF_USING_ALIAS_STRING_VIEW using string_view = my_lib::StringView;
|
||||
#include <nameof.hpp>
|
||||
```
|
||||
|
||||
## `NAMEOF`
|
||||
|
||||
* Obtains name of variable, function, macro.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
// Name of variable.
|
||||
NAMEOF(somevar) -> "somevar"
|
||||
|
||||
// Name of member variable.
|
||||
NAMEOF(person.address.zip_code) -> "zip_code"
|
||||
|
||||
// Name of function.
|
||||
NAMEOF(foo<int, float>()) -> "foo"
|
||||
|
||||
// Name of member function.
|
||||
NAMEOF(somevar.some_method()) -> "some_method"
|
||||
NAMEOF(somevar.some_method<int>()) -> "some_method"
|
||||
|
||||
// Name of macro.
|
||||
NAMEOF(__LINE__) -> "__LINE__"
|
||||
NAMEOF(NAMEOF(structvar)) -> "NAMEOF"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_FULL`
|
||||
|
||||
* Obtains full (with template suffix) name of variable, function, macro.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
// Full name of template function.
|
||||
NAMEOF_FULL(foo<int, float>()) -> "foo<int, float>"
|
||||
|
||||
// Full name of template member function.
|
||||
NAMEOF_FULL(somevar.some_method<int>()) -> "some_method<int>"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_RAW`
|
||||
|
||||
* Obtains raw name of variable, function, macro.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
NAMEOF_RAW(::somevar.somefield) -> "::somevar.somefield"
|
||||
NAMEOF_RAW(&some_class::some_method<int>) -> "&some_class::some_method<int>"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_ENUM`
|
||||
|
||||
* Obtains name of enum variable.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `string_view`, in debug occurs assert.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
auto color = Color::RED;
|
||||
NAMEOF_ENUM(color) -> "RED"
|
||||
nameof::nameof_enum(color) -> "RED"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 9 and C++ >= 17</br>
|
||||
|
||||
# `NAMEOF_ENUM_OR`
|
||||
|
||||
* Obtains name of enum variable or default value if enum variable out of range.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns `default_value`.
|
||||
|
||||
```cpp
|
||||
auto color = Color::RED;
|
||||
NAMEOF_ENUM_OR(color, "none") -> "RED"
|
||||
NAMEOF_ENUM_OR((Color)-1, "none") -> "none"
|
||||
nameof::nameof_enum_or(color, "none") -> "RED"
|
||||
nameof::nameof_enum_or((Color)-1, "none") -> "none"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 9 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_ENUM_CONST`
|
||||
|
||||
* Obtains name of static storage enum variable.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* This version is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md#nameof-enum).
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Enum value does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
NAMEOF_ENUM_CONST(Color::GREEN) -> "GREEN"
|
||||
nameof::nameof_enum<Color::GREEN>() -> "GREEN"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 9 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_ENUM_FLAG`
|
||||
|
||||
* Obtains name of enum flag variable.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `string`, in debug occurs assert.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
enum class AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
|
||||
auto flag = AnimalFlags::Endangered;
|
||||
|
||||
NAMEOF_ENUM_FLAG(flag) -> "Endangered"
|
||||
nameof_enum_flag(flag) -> "Endangered"
|
||||
|
||||
flag = AnimalFlags::CanFly | AnimalFlags::Endangered;
|
||||
NAMEOF_ENUM_FLAG(flag) -> "CanFly|Endangered"
|
||||
nameof_enum_flag(flag) -> "CanFly|Endangered"
|
||||
nameof_enum_flag(flag, '$') -> "CanFly$Endangered"
|
||||
|
||||
NAMEOF_ENUM(HasClaws | CanFly) -> ""
|
||||
nameof_enum(HasClaws | CanFly) -> ""
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 9 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_TYPE`
|
||||
|
||||
* Obtains type name, reference and cv-qualifiers are ignored.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* In all cases, reference and cv-qualifiers are ignored by `NAMEOF_TYPE` (that is, `NAMEOF_TYPE(const T&) == NAMEOF_TYPE(T)`).
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
NAMEOF_TYPE(T) -> "int"
|
||||
nameof::nameof_type<T>() -> "int"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_FULL_TYPE`
|
||||
|
||||
* Obtains full type name, with reference and cv-qualifiers.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
NAMEOF_TYPE(T) -> "const int&"
|
||||
nameof::nameof_full_type<T>() -> "const int&"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_SHORT_TYPE`
|
||||
|
||||
* Obtains short type name.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const my::detail::SomeClass<int>&;
|
||||
NAMEOF_SHORT_TYPE(T) -> "SomeClass"
|
||||
nameof::nameof_short_type<T>() -> "SomeClass"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_TYPE_EXPR`
|
||||
|
||||
* Obtains string name type of expression, reference and cv-qualifiers are ignored.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* In all cases, reference and cv-qualifiers are ignored.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
T var = 42;
|
||||
NAMEOF_TYPE_EXPR(var) -> "int"
|
||||
nameof::nameof_type<decltype(var)>() -> "int"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_FULL_TYPE_EXPR`
|
||||
|
||||
* Obtains full type name of expression, with reference and cv-qualifiers.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
T var = 42;
|
||||
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&"
|
||||
nameof::nameof_full_type<decltype(var)>() -> "const int&"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_SHORT_TYPE_EXPR`
|
||||
|
||||
* Obtains short type name of expression.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
const my::detail::SomeClass<int> var;
|
||||
NAMEOF_SHORT_TYPE_EXPR(var) -> "SomeClass"
|
||||
nameof::nameof_short_type<decltype(var)>() -> "SomeClass"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2017 and C++ >= 17</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_TYPE_RTTI`
|
||||
|
||||
* Obtains type name, using RTTI.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
volatile const my::detail::Base* ptr = new my::detail::Derived();
|
||||
NAMEOF_TYPE_RTTI(*ptr) -> "my::detail::Derived"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17 and RTTI enabled</br>
|
||||
Visual Studio >= 2017 and C++ >= 17 and RTTI enabled</br>
|
||||
GCC >= 7 and C++ >= 17 and RTTI enabled</br>
|
||||
|
||||
## `NAMEOF_FULL_TYPE_RTTI`
|
||||
|
||||
* Obtains full type name, using RTTI.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
volatile const my::detail::Base* ptr = new my::detail::Derived();
|
||||
NAMEOF_FULL_TYPE_RTTI(cv_ref) -> "volatile const my::detail::Derived&"
|
||||
``
|
||||
|
||||
## `NAMEOF_SHORT_TYPE_RTTI`
|
||||
|
||||
* Obtains short type name, using RTTI.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
volatile const my::detail::Base* ptr = new my::detail::Derived();
|
||||
NAMEOF_SHORT_TYPE_RTTI(*ptr) -> "Derived"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17 and RTTI enabled</br>
|
||||
Visual Studio >= 2017 and C++ >= 17 and RTTI enabled</br>
|
||||
GCC >= 7 and C++ >= 17 and RTTI enabled</br>
|
||||
|
||||
## `NAMEOF_MEMBER`
|
||||
|
||||
* Obtains name of member.
|
||||
|
||||
* Returns `string_view`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
struct A {
|
||||
int this_is_the_name;
|
||||
};
|
||||
// ..
|
||||
NAMEOF_MEMBER(&A::this_is_the_name) -> "this_is_the_name"
|
||||
nameof::nameof_member(&A::this_is_the_name) -> "this_is_the_name"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2022 and C++ >= 20</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
||||
|
||||
## `NAMEOF_POINTER`
|
||||
|
||||
* Obtains name of a function, a global or class static variable.
|
||||
|
||||
* Returns `string_view`.
|
||||
|
||||
* Examples
|
||||
```cpp
|
||||
int someglobalvariable = 0;
|
||||
// ..
|
||||
NAMEOF_POINTER(&someglobalconstvariable) == "someglobalconstvariable"
|
||||
nameof::nameof_pointer(&someglobalconstvariable) == "someglobalconstvariable"
|
||||
|
||||
constexpr auto global_ptr = &someglobalvariable;
|
||||
NAMEOF_POINTER(global_ptr) == "someglobalconstvariable"
|
||||
nameof::nameof_pointer(global_ptr) == "someglobalconstvariable"
|
||||
```
|
||||
|
||||
* Compiler compatibility
|
||||
Clang/LLVM >= 5 and C++ >= 17</br>
|
||||
Visual Studio >= 2022 and C++ >= 20</br>
|
||||
GCC >= 7 and C++ >= 17</br>
|
|
@ -1,27 +1,23 @@
|
|||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||
check_cxx_compiler_flag(-std=c++17 HAS_CPP17_FLAG)
|
||||
if(!HAS_CPP17_FLAG)
|
||||
MESSAGE(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++17 support.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(OPTIONS -Wall -Wextra -pedantic-errors -Werror -std=c++17)
|
||||
set(OPTIONS -Wall -Wextra -pedantic-errors -Werror)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
check_cxx_compiler_flag(/std:c++17 HAS_CPP17_FLAG)
|
||||
if(!HAS_CPP17_FLAG)
|
||||
MESSAGE(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++17 support.")
|
||||
endif()
|
||||
|
||||
set(OPTIONS /W4 /WX /std:c++17)
|
||||
set(OPTIONS /W4 /WX)
|
||||
if(HAS_PERMISSIVE_FLAG)
|
||||
set(OPTIONS ${OPTIONS} /permissive-)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable(example
|
||||
example.cpp
|
||||
${CMAKE_SOURCE_DIR}/include/${CMAKE_PROJECT_NAME}.hpp)
|
||||
target_compile_options(example PRIVATE ${OPTIONS})
|
||||
target_link_libraries(example PRIVATE ${CMAKE_PROJECT_NAME})
|
||||
function(make_example target)
|
||||
add_executable(${target} ${target}.cpp)
|
||||
set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
|
||||
target_compile_options(${target} PRIVATE ${OPTIONS})
|
||||
target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME})
|
||||
endfunction()
|
||||
|
||||
make_example(example)
|
||||
make_example(example_custom_name)
|
||||
if(NAMEOF_MODULE)
|
||||
make_example(example_module)
|
||||
endif()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2018 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -27,17 +27,9 @@
|
|||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
std::string operator+(std::string_view lhs, std::string_view rhs) {
|
||||
return std::string{lhs.data(), lhs.length()}.append(rhs.data(), rhs.length());
|
||||
}
|
||||
struct Base { virtual ~Base() = default; };
|
||||
|
||||
constexpr long double operator"" _deg(long double deg) {
|
||||
return deg * 3.141592 / 180.0;
|
||||
}
|
||||
|
||||
std::string operator"" _string(const char* str, std::size_t) {
|
||||
return std::string{str};
|
||||
}
|
||||
struct Derived : Base {};
|
||||
|
||||
struct SomeStruct {
|
||||
int somefield = 0;
|
||||
|
@ -53,7 +45,18 @@ void SomeMethod3() {
|
|||
|
||||
template <typename T, typename U>
|
||||
std::string SomeMethod4(U value) {
|
||||
return NAMEOF(SomeMethod4<T, U>) + "<" + NAMEOF_TYPE(T) + ", " + NAMEOF_TYPE(U) + ">(" + NAMEOF_TYPE(U) + " " + NAMEOF(value) + ")";
|
||||
auto function_name = NAMEOF(SomeMethod4<T, U>).str()
|
||||
.append("<")
|
||||
.append(NAMEOF_TYPE(T))
|
||||
.append(", ")
|
||||
.append(NAMEOF_TYPE(U))
|
||||
.append(">(")
|
||||
.append(NAMEOF_TYPE(U))
|
||||
.append(" ")
|
||||
.append(NAMEOF(value).data())
|
||||
.append(")");
|
||||
|
||||
return function_name;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -80,21 +83,56 @@ struct Long {
|
|||
|
||||
enum class Color { RED, GREEN, BLUE };
|
||||
|
||||
enum AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
|
||||
|
||||
SomeStruct structvar;
|
||||
Long othervar;
|
||||
SomeStruct* ptrvar = &structvar;
|
||||
|
||||
void name_to_chars(const char* name) {
|
||||
std::cout << name << std::endl;
|
||||
}
|
||||
|
||||
void name_to_string(const std::string& name) {
|
||||
std::cout << name << std::endl;
|
||||
}
|
||||
|
||||
void name_to_string_view(std::string_view name) {
|
||||
std::cout << name << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Compile-time.
|
||||
constexpr auto name = NAMEOF(structvar);
|
||||
static_assert("structvar" == name);
|
||||
using namespace std::literals::string_view_literals;
|
||||
static_assert("structvar"sv == name);
|
||||
|
||||
name_to_chars(name.c_str()); // 'structvar'
|
||||
// or name_to_chars(name.data());
|
||||
// Note: c_str() return name as null-terminated C string, no memory allocation.
|
||||
|
||||
name_to_string(name.str()); // 'structvar'
|
||||
// Note: str() occure memory allocation to copy name to std::string.
|
||||
// or name_to_string(std::string{name});
|
||||
// or name_to_string(static_cast<std::string>(name));
|
||||
// Note: cast to std::string occure memory allocation to copy name to std::string.
|
||||
|
||||
name_to_string_view(name); // 'structvar'
|
||||
// Note: Implicit cast to std::string_view, no memory allocation.
|
||||
|
||||
#if defined(NAMEOF_ENUM_SUPPORTED)
|
||||
// Nameof enum variable.
|
||||
auto color = Color::RED;
|
||||
std::cout << nameof::nameof_enum(color) << std::endl; // 'RED'
|
||||
std::cout << NAMEOF_ENUM(color) << std::endl; // 'RED'
|
||||
std::cout << nameof::nameof_enum<Color::GREEN>() << std::endl; // 'GREEN'
|
||||
|
||||
// Nameof enum flags.
|
||||
auto flag = static_cast<AnimalFlags>(AnimalFlags::CanFly | AnimalFlags::EatsFish);
|
||||
std::cout << nameof::nameof_enum_flag(flag) << std::endl; // 'CanFly|EatsFish'
|
||||
std::cout << NAMEOF_ENUM_FLAG(flag) << std::endl; // 'CanFly|EatsFish'
|
||||
#endif
|
||||
|
||||
// Nameof.
|
||||
std::cout << NAMEOF(structvar) << std::endl; // 'structvar'
|
||||
std::cout << NAMEOF(::structvar) << std::endl; // 'structvar'
|
||||
|
@ -120,28 +158,46 @@ int main() {
|
|||
std::cout << NAMEOF_TYPE(const Long::LL&) << std::endl; // 'Long::LL'
|
||||
std::cout << nameof::nameof_full_type<const Long::LL&>() << std::endl; // 'const Long::LL &'
|
||||
std::cout << NAMEOF_FULL_TYPE(const Long::LL&) << std::endl; // 'const Long::LL &'
|
||||
std::cout << NAMEOF_SHORT_TYPE(const Long::LL&) << std::endl; // 'LL'
|
||||
std::cout << NAMEOF_SHORT_TYPE(const SomeClass<int>&) << std::endl; // 'SomeClass'
|
||||
|
||||
// Nameof variable type.
|
||||
std::cout << nameof::nameof_type<decltype(structvar)>() << std::endl; // 'SomeStruct'
|
||||
std::cout << NAMEOF_TYPE_EXPR(structvar) << std::endl; // 'SomeStruct'
|
||||
std::cout << NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'SomeClass<int>'
|
||||
std::cout << NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'const SomeClass<int> &&'
|
||||
std::cout << NAMEOF_SHORT_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'SomeClass'
|
||||
|
||||
#if defined(NAMEOF_MEMBER_SUPPORTED)
|
||||
// Nameof member
|
||||
std::cout << nameof::nameof_member<&SomeStruct::somefield>() << std::endl; // somefield
|
||||
std::cout << nameof::nameof_member<&SomeStruct::SomeMethod1>() << std::endl; // SomeMethod1
|
||||
std::cout << NAMEOF_MEMBER(&Long::LL::field) << std::endl; // field
|
||||
constexpr auto member_ptr = &SomeStruct::somefield;
|
||||
std::cout << NAMEOF_MEMBER(member_ptr) << std::endl; // somefield
|
||||
#endif
|
||||
|
||||
// Nameof macro.
|
||||
std::cout << NAMEOF(__LINE__) << std::endl; // '__LINE__'
|
||||
std::cout << NAMEOF(NAMEOF(structvar)) << std::endl; // 'NAMEOF'
|
||||
|
||||
// Nameof raw.
|
||||
std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // 'structvar.somefield'
|
||||
std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // '&SomeStruct::SomeMethod1'
|
||||
|
||||
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED)
|
||||
// Nameof type using RTTI.
|
||||
Base* ptr = new Derived();
|
||||
std::cout << NAMEOF_TYPE_RTTI(ptr) << std::endl; // 'Base *'
|
||||
std::cout << NAMEOF_TYPE_RTTI(*ptr) << std::endl; // 'Derived'
|
||||
#endif
|
||||
|
||||
// Some more complex example.
|
||||
|
||||
std::cout << SomeMethod4<int>(structvar) << std::endl; // 'SomeMethod4<int, SomeStruct>(SomeStruct value)'
|
||||
|
||||
auto div = [](int x, int y) -> int {
|
||||
if (y == 0) {
|
||||
throw std::invalid_argument(NAMEOF(y) + " should not be zero!");
|
||||
throw std::invalid_argument(NAMEOF(y).str() + " should not be zero!");
|
||||
}
|
||||
return x / y;
|
||||
};
|
||||
|
|
93
example/example_custom_name.cpp
Normal file
93
example/example_custom_name.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nameof.hpp>
|
||||
|
||||
enum class Color { RED = -10, BLUE = 0, GREEN = 10 };
|
||||
enum class Numbers { One, Two, Three };
|
||||
|
||||
#if defined(NAMEOF_ENUM_SUPPORTED)
|
||||
// Сustom definitions of names for enum.
|
||||
// Specialization of `enum_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::enum_name<Color>(Color value) noexcept {
|
||||
switch (value) {
|
||||
case Color::RED:
|
||||
return "the red color";
|
||||
case Color::BLUE:
|
||||
return "The BLUE";
|
||||
case Color::GREEN:
|
||||
return {}; // Empty string for default value.
|
||||
}
|
||||
return {}; // Empty string for unknown value.
|
||||
}
|
||||
|
||||
// Сustom definitions of names for enum.
|
||||
// Specialization of `enum_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::enum_name<Numbers>(Numbers value) noexcept {
|
||||
switch (value) {
|
||||
case Numbers::One:
|
||||
return "the one";
|
||||
default:
|
||||
return {}; // Empty string for default or unknown value.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Сustom definitions of names for type.
|
||||
// Specialization of `type_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::type_name<Color>() noexcept {
|
||||
return "The Color";
|
||||
}
|
||||
|
||||
class a1_test {};
|
||||
class a2_test {};
|
||||
|
||||
// Сustom definitions of names for type.
|
||||
// Specialization of `type_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::type_name<a1_test>() noexcept {
|
||||
return "Animal";
|
||||
}
|
||||
|
||||
int main() {
|
||||
#if defined(NAMEOF_ENUM_SUPPORTED)
|
||||
std::cout << nameof::nameof_enum(Color::RED) << std::endl; // 'the red color'
|
||||
std::cout << nameof::nameof_enum(Color::BLUE) << std::endl; // 'The BLUE'
|
||||
std::cout << nameof::nameof_enum(Color::GREEN) << std::endl; // 'GREEN'
|
||||
|
||||
std::cout << nameof::nameof_enum(Numbers::One) << std::endl; // 'the one'
|
||||
std::cout << nameof::nameof_enum(Numbers::Two) << std::endl; // 'Two'
|
||||
std::cout << nameof::nameof_enum(Numbers::Three) << std::endl; // 'Three'
|
||||
#endif
|
||||
|
||||
std::cout << nameof::nameof_type<Color>() << std::endl; // 'The Color'
|
||||
std::cout << nameof::nameof_type<Numbers>() << std::endl; // 'Numbers'
|
||||
std::cout << nameof::nameof_type<a1_test>() << std::endl; // 'Animal'
|
||||
std::cout << nameof::nameof_type<a2_test>() << std::endl; // 'a2_test'
|
||||
|
||||
return 0;
|
||||
}
|
11
example/example_module.cpp
Normal file
11
example/example_module.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
import nameof;
|
||||
#include <nameof_macro.hpp>
|
||||
|
||||
struct Test {};
|
||||
|
||||
auto main() -> int {
|
||||
auto _ = nameof::nameof_type<Test>();
|
||||
{
|
||||
auto _ = NAMEOF_TYPE(Test);
|
||||
}
|
||||
}
|
1321
include/nameof.hpp
1321
include/nameof.hpp
File diff suppressed because it is too large
Load diff
149
include/nameof_macro.hpp
Normal file
149
include/nameof_macro.hpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
#ifndef NEARGYE_NAMEOF_MACRO_HPP
|
||||
#define NEARGYE_NAMEOF_MACRO_HPP
|
||||
|
||||
// Checks nameof_type compiler compatibility.
|
||||
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || defined(_MSC_VER) && _MSC_VER >= 1910
|
||||
#undef NAMEOF_TYPE_SUPPORTED
|
||||
#define NAMEOF_TYPE_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
// Checks nameof_type_rtti compiler compatibility.
|
||||
#if defined(__clang__)
|
||||
#if __has_feature(cxx_rtti)
|
||||
#undef NAMEOF_TYPE_RTTI_SUPPORTED
|
||||
#define NAMEOF_TYPE_RTTI_SUPPORTED 1
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if defined(__GXX_RTTI)
|
||||
#undef NAMEOF_TYPE_RTTI_SUPPORTED
|
||||
#define NAMEOF_TYPE_RTTI_SUPPORTED 1
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_CPPRTTI)
|
||||
#undef NAMEOF_TYPE_RTTI_SUPPORTED
|
||||
#define NAMEOF_TYPE_RTTI_SUPPORTED 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Checks nameof_member compiler compatibility.
|
||||
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || \
|
||||
defined(_MSC_VER) && defined(_MSVC_LANG) && _MSVC_LANG >= 202002L
|
||||
#undef NAMEOF_MEMBER_SUPPORTED
|
||||
#define NAMEOF_MEMBER_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
// Checks nameof_pointer compiler compatibility.
|
||||
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || \
|
||||
defined(_MSC_VER) && defined(_MSVC_LANG) && _MSVC_LANG >= 202002L
|
||||
#undef NAMEOF_POINTER_SUPPORTED
|
||||
#define NAMEOF_POINTER_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
// Checks nameof_enum compiler compatibility.
|
||||
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910
|
||||
#undef NAMEOF_ENUM_SUPPORTED
|
||||
#define NAMEOF_ENUM_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
// Checks nameof_enum compiler aliases compatibility.
|
||||
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
|
||||
#undef NAMEOF_ENUM_SUPPORTED_ALIASES
|
||||
#define NAMEOF_ENUM_SUPPORTED_ALIASES 1
|
||||
#endif
|
||||
|
||||
// Enum value must be greater or equals than NAMEOF_ENUM_RANGE_MIN. By default NAMEOF_ENUM_RANGE_MIN = -128.
|
||||
// If need another min range for all enum types by default, redefine the macro NAMEOF_ENUM_RANGE_MIN.
|
||||
#if !defined(NAMEOF_ENUM_RANGE_MIN)
|
||||
#define NAMEOF_ENUM_RANGE_MIN -128
|
||||
#endif
|
||||
|
||||
// Enum value must be less or equals than NAMEOF_ENUM_RANGE_MAX. By default NAMEOF_ENUM_RANGE_MAX = 128.
|
||||
// If need another max range for all enum types by default, redefine the macro NAMEOF_ENUM_RANGE_MAX.
|
||||
#if !defined(NAMEOF_ENUM_RANGE_MAX)
|
||||
#define NAMEOF_ENUM_RANGE_MAX 128
|
||||
#endif
|
||||
|
||||
#define NAMEOF_VERSION_MAJOR 0
|
||||
#define NAMEOF_VERSION_MINOR 10
|
||||
#define NAMEOF_VERSION_PATCH 4
|
||||
|
||||
// Obtains name of variable, function, macro.
|
||||
#define NAMEOF(...) \
|
||||
[]() constexpr noexcept { \
|
||||
::std::void_t<decltype(__VA_ARGS__)>(); \
|
||||
constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__); \
|
||||
static_assert(!_name.empty(), "Expression does not have a name."); \
|
||||
constexpr auto _size = _name.size(); \
|
||||
constexpr auto _nameof = ::nameof::cstring<_size>{_name}; \
|
||||
return _nameof; \
|
||||
}()
|
||||
|
||||
// Obtains full name of variable, function, macro.
|
||||
#define NAMEOF_FULL(...) \
|
||||
[]() constexpr noexcept { \
|
||||
::std::void_t<decltype(__VA_ARGS__)>(); \
|
||||
constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__, false); \
|
||||
static_assert(!_name.empty(), "Expression does not have a name."); \
|
||||
constexpr auto _size = _name.size(); \
|
||||
constexpr auto _nameof_full = ::nameof::cstring<_size>{_name}; \
|
||||
return _nameof_full; \
|
||||
}()
|
||||
|
||||
// Obtains raw name of variable, function, macro.
|
||||
#define NAMEOF_RAW(...) \
|
||||
[]() constexpr noexcept { \
|
||||
::std::void_t<decltype(__VA_ARGS__)>(); \
|
||||
constexpr auto _name = ::nameof::string_view{#__VA_ARGS__}; \
|
||||
static_assert(!_name.empty(), "Expression does not have a name."); \
|
||||
constexpr auto _size = _name.size(); \
|
||||
constexpr auto _nameof_raw = ::nameof::cstring<_size>{_name}; \
|
||||
return _nameof_raw; \
|
||||
}()
|
||||
|
||||
// Obtains name of enum variable.
|
||||
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<::std::decay_t<decltype(__VA_ARGS__)>>(__VA_ARGS__)
|
||||
|
||||
// Obtains name of enum variable or default value if enum variable out of range.
|
||||
#define NAMEOF_ENUM_OR(...) ::nameof::nameof_enum_or(__VA_ARGS__)
|
||||
|
||||
// Obtains name of static storage enum variable.
|
||||
// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
|
||||
#define NAMEOF_ENUM_CONST(...) ::nameof::nameof_enum<__VA_ARGS__>()
|
||||
|
||||
// Obtains name of enum-flags variable.
|
||||
#define NAMEOF_ENUM_FLAG(...) ::nameof::nameof_enum_flag<::std::decay_t<decltype(__VA_ARGS__)>>(__VA_ARGS__)
|
||||
|
||||
// Obtains type name, reference and cv-qualifiers are ignored.
|
||||
#define NAMEOF_TYPE(...) ::nameof::nameof_type<__VA_ARGS__>()
|
||||
|
||||
// Obtains full type name, with reference and cv-qualifiers.
|
||||
#define NAMEOF_FULL_TYPE(...) ::nameof::nameof_full_type<__VA_ARGS__>()
|
||||
|
||||
// Obtains short type name.
|
||||
#define NAMEOF_SHORT_TYPE(...) ::nameof::nameof_short_type<__VA_ARGS__>()
|
||||
|
||||
// Obtains type name of expression, reference and cv-qualifiers are ignored.
|
||||
#define NAMEOF_TYPE_EXPR(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>()
|
||||
|
||||
// Obtains full type name of expression, with reference and cv-qualifiers.
|
||||
#define NAMEOF_FULL_TYPE_EXPR(...) ::nameof::nameof_full_type<decltype(__VA_ARGS__)>()
|
||||
|
||||
// Obtains short type name of expression.
|
||||
#define NAMEOF_SHORT_TYPE_EXPR(...) ::nameof::nameof_short_type<decltype(__VA_ARGS__)>()
|
||||
|
||||
// Obtains type name, with reference and cv-qualifiers, using RTTI.
|
||||
#define NAMEOF_TYPE_RTTI(...) ::nameof::detail::nameof_type_rtti<::std::void_t<decltype(__VA_ARGS__)>>(typeid(__VA_ARGS__).name())
|
||||
|
||||
// Obtains full type name, using RTTI.
|
||||
#define NAMEOF_FULL_TYPE_RTTI(...) ::nameof::detail::nameof_full_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
|
||||
|
||||
// Obtains short type name, using RTTI.
|
||||
#define NAMEOF_SHORT_TYPE_RTTI(...) ::nameof::detail::nameof_short_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
|
||||
|
||||
// Obtains name of member.
|
||||
#define NAMEOF_MEMBER(...) ::nameof::nameof_member<__VA_ARGS__>()
|
||||
|
||||
// Obtains name of a function, a global or class static variable.
|
||||
#define NAMEOF_POINTER(...) ::nameof::nameof_pointer<__VA_ARGS__>()
|
||||
|
||||
#endif
|
46
src/nameof.cpp
Normal file
46
src/nameof.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
module;
|
||||
|
||||
#ifndef NAMEOF_IMPORT_STD
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if !defined(NAMEOF_USING_ALIAS_STRING)
|
||||
#include <string>
|
||||
#endif
|
||||
#if !defined(NAMEOF_USING_ALIAS_STRING_VIEW)
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
#if __has_include(<cxxabi.h>)
|
||||
#include <cxxabi.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
export module nameof;
|
||||
|
||||
#ifdef NAMEOF_IMPORT_STD
|
||||
|
||||
import std;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NAMEOF_ATTACH_TO_GLOBAL_MODULE
|
||||
extern "C++" {
|
||||
#endif
|
||||
|
||||
#include <nameof.hpp>
|
||||
|
||||
#ifdef NAMEOF_ATTACH_TO_GLOBAL_MODULE
|
||||
} // extern "C++"
|
||||
#endif
|
5528
test/3rdparty/Catch2/catch.hpp
vendored
5528
test/3rdparty/Catch2/catch.hpp
vendored
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,5 @@
|
|||
include(CheckCXXCompilerFlag)
|
||||
|
||||
set(SOURCES test.cpp)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(OPTIONS /W4 /WX)
|
||||
check_cxx_compiler_flag(/permissive HAS_PERMISSIVE_FLAG)
|
||||
|
@ -9,22 +7,23 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|||
set(OPTIONS ${OPTIONS} /permissive-)
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag(/std:c++17 HAS_CPP17_FLAG)
|
||||
check_cxx_compiler_flag(/std:c++20 HAS_CPP20_FLAG)
|
||||
check_cxx_compiler_flag(/std:c++23 HAS_CPP23_FLAG)
|
||||
check_cxx_compiler_flag(/std:c++latest HAS_CPPLATEST_FLAG)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(OPTIONS -Wall -Wextra -pedantic-errors -Werror)
|
||||
|
||||
check_cxx_compiler_flag(-std=c++17 HAS_CPP17_FLAG)
|
||||
check_cxx_compiler_flag(-std=c++20 HAS_CPP20_FLAG)
|
||||
check_cxx_compiler_flag(-std=c++23 HAS_CPP23_FLAG)
|
||||
endif()
|
||||
|
||||
function(make_test target std)
|
||||
add_executable(${target} ${SOURCES})
|
||||
function(make_test src target std)
|
||||
add_executable(${target} ${src})
|
||||
target_compile_options(${target} PRIVATE ${OPTIONS})
|
||||
target_include_directories(${target} PRIVATE 3rdparty/Catch2)
|
||||
target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME})
|
||||
set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
|
||||
if(std)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
target_compile_options(${target} PRIVATE /std:${std})
|
||||
|
@ -35,10 +34,20 @@ function(make_test target std)
|
|||
add_test(NAME ${target} COMMAND ${target})
|
||||
endfunction()
|
||||
|
||||
if(HAS_CPP17_FLAG)
|
||||
make_test(${CMAKE_PROJECT_NAME}-cpp17.t c++17)
|
||||
make_test(test.cpp test-cpp17 c++17)
|
||||
make_test(test_aliases.cpp test_aliases-cpp17 c++17)
|
||||
|
||||
if(HAS_CPP20_FLAG)
|
||||
make_test(test.cpp test-cpp20 c++20)
|
||||
make_test(test_aliases.cpp test_aliases-cpp20 c++20)
|
||||
endif()
|
||||
|
||||
if(HAS_CPP23_FLAG)
|
||||
make_test(test.cpp test-cpp23 c++23)
|
||||
make_test(test_aliases.cpp test_aliases-cpp23 c++23)
|
||||
endif()
|
||||
|
||||
if(HAS_CPPLATEST_FLAG)
|
||||
make_test(${CMAKE_PROJECT_NAME}-cpplatest.t c++latest)
|
||||
make_test(test.cpp test-cpplatest c++latest)
|
||||
make_test(test_aliases.cpp test_aliases-cpplatest c++latest)
|
||||
endif()
|
||||
|
|
786
test/test.cpp
786
test/test.cpp
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2018 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -30,6 +30,12 @@
|
|||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define NAMEOF_DEBUG_REQUIRE(...) REQUIRE(__VA_ARGS__)
|
||||
#else
|
||||
# define NAMEOF_DEBUG_REQUIRE(...)
|
||||
#endif
|
||||
|
||||
struct SomeStruct {
|
||||
int somefield = 0;
|
||||
|
||||
|
@ -40,8 +46,16 @@ struct SomeStruct {
|
|||
int SomeMethod2() const {
|
||||
throw std::runtime_error{"should not be called!"};
|
||||
}
|
||||
|
||||
static int somestaticfield;
|
||||
constexpr static int someotherstaticfield = 21;
|
||||
};
|
||||
|
||||
int SomeStruct::somestaticfield;
|
||||
|
||||
int someglobalvariable = 0;
|
||||
const int someglobalconstvariable = 42;
|
||||
|
||||
void SomeMethod3() {
|
||||
throw std::runtime_error{"should not be called!"};
|
||||
}
|
||||
|
@ -73,26 +87,49 @@ struct Long {
|
|||
|
||||
enum class Color { RED = -12, GREEN = 7, BLUE = 15 };
|
||||
|
||||
enum class Numbers : char { one = 10, two = 20, three = 30, many = 127 };
|
||||
enum class Numbers : int { one = 1, two, three, many = 127 };
|
||||
|
||||
enum Directions { Up = 85, Down = -42, Right = 120, Left = -120 };
|
||||
|
||||
enum number : unsigned long { one = 100, two = 200, three = 300, four = 400 };
|
||||
|
||||
namespace nameof {
|
||||
enum AnimalFlags {
|
||||
HasClaws = 1,
|
||||
CanFly = 2,
|
||||
EatsFish = 4,
|
||||
Endangered = 8,
|
||||
};
|
||||
|
||||
enum class BigFlags : std::uint64_t {
|
||||
A = 1,
|
||||
B = (static_cast<std::uint64_t>(0x1) << 20),
|
||||
C = (static_cast<std::uint64_t>(0x1) << 40),
|
||||
D = (static_cast<std::uint64_t>(0x1) << 63),
|
||||
};
|
||||
|
||||
template <>
|
||||
struct enum_range<number> {
|
||||
struct nameof::customize::enum_range<number> {
|
||||
static_assert(std::is_enum_v<number>, "nameof::enum_range<number> requires enum type.");
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
static_assert(max > min, "nameof::enum_range<number> requires max > min.");
|
||||
};
|
||||
}
|
||||
|
||||
enum class OutOfRange {
|
||||
too_low = NAMEOF_ENUM_RANGE_MIN - 1,
|
||||
required_to_work = 0,
|
||||
too_high = NAMEOF_ENUM_RANGE_MAX + 1
|
||||
};
|
||||
|
||||
struct TestRtti {
|
||||
struct Base { virtual ~Base() = default; };
|
||||
struct Derived : Base {};
|
||||
};
|
||||
|
||||
SomeStruct struct_var;
|
||||
Long othervar;
|
||||
SomeStruct * ptr_s = &struct_var;
|
||||
SomeStruct & ref_s = struct_var;
|
||||
SomeStruct* ptr_s = &struct_var;
|
||||
SomeStruct& ref_s = struct_var;
|
||||
|
||||
SomeClass<int> class_var;
|
||||
const SomeClass<int> volatile * ptr_c = nullptr;
|
||||
|
@ -225,74 +262,9 @@ TEST_CASE("NAMEOF_RAW") {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 9) || defined(_MSC_VER)
|
||||
TEST_CASE("NAMEOF_ENUM") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_ENUM(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_ENUM(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_ENUM(cm[1]) == "GREEN");
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<Color>(0)).empty());
|
||||
#if defined(NAMEOF_ENUM_SUPPORTED)
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_ENUM(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::three) == "three");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::many).empty());
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_ENUM(dr);
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Left) == "Left");
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_ENUM(nt);
|
||||
REQUIRE(NAMEOF_ENUM(number::one) == "one");
|
||||
REQUIRE(NAMEOF_ENUM(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(NAMEOF_ENUM(number::four).empty());
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_CONST_ENUM") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_CONST_ENUM(cr);
|
||||
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(cm[1]) == "GREEN");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_CONST_ENUM(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(Numbers::three) == "three");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(Numbers::many) == "many");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_CONST_ENUM(dr);
|
||||
REQUIRE(NAMEOF_CONST_ENUM(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(Directions::Left) == "Left");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_CONST_ENUM(nt);
|
||||
REQUIRE(NAMEOF_CONST_ENUM(number::one) == "one");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(number::four) == "four");
|
||||
REQUIRE(NAMEOF_CONST_ENUM(static_cast<number>(0)).empty());
|
||||
}
|
||||
static_assert(nameof::is_nameof_enum_supported, "nameof::nameof_enum: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
|
||||
TEST_CASE("nameof_enum") {
|
||||
SECTION("automatic storage") {
|
||||
|
@ -302,15 +274,15 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(nameof::nameof_enum(Color::BLUE) == "BLUE");
|
||||
REQUIRE(nameof::nameof_enum(cm[1]) == "GREEN");
|
||||
REQUIRE(nameof::nameof_enum(static_cast<Color>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = nameof::nameof_enum(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(nameof::nameof_enum(Numbers::two) == "two");
|
||||
REQUIRE(nameof::nameof_enum(Numbers::three) == "three");
|
||||
REQUIRE(nameof::nameof_enum(Numbers::many).empty());
|
||||
REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(Numbers::many).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = nameof::nameof_enum(dr);
|
||||
|
@ -318,15 +290,15 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(nameof::nameof_enum(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(nameof::nameof_enum(Directions::Left) == "Left");
|
||||
REQUIRE(nameof::nameof_enum(static_cast<Directions>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = nameof::nameof_enum(nt);
|
||||
REQUIRE(nameof::nameof_enum(number::one) == "one");
|
||||
REQUIRE(nameof::nameof_enum(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(nameof::nameof_enum(number::four).empty());
|
||||
REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(number::four).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
SECTION("static storage") {
|
||||
|
@ -336,7 +308,6 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(nameof::nameof_enum<Color::BLUE>() == "BLUE");
|
||||
REQUIRE(nameof::nameof_enum<cm[1]>() == "GREEN");
|
||||
REQUIRE(nameof::nameof_enum<static_cast<Color>(0)>().empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = nameof::nameof_enum<no>();
|
||||
|
@ -344,7 +315,6 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(nameof::nameof_enum<Numbers::two>() == "two");
|
||||
REQUIRE(nameof::nameof_enum<Numbers::three>() == "three");
|
||||
REQUIRE(nameof::nameof_enum<Numbers::many>() == "many");
|
||||
REQUIRE(nameof::nameof_enum<static_cast<Numbers>(0)>().empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = nameof::nameof_enum<dr>();
|
||||
|
@ -352,7 +322,6 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(nameof::nameof_enum<Directions::Down>() == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(nameof::nameof_enum<Directions::Left>() == "Left");
|
||||
REQUIRE(nameof::nameof_enum<static_cast<Directions>(0)>().empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = nameof::nameof_enum<nt>();
|
||||
|
@ -360,111 +329,214 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(nameof::nameof_enum<number::two>() == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(nameof::nameof_enum<number::four>() == "four");
|
||||
REQUIRE(nameof::nameof_enum<static_cast<number>(0)>().empty());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE_EXPR(struct_var);
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct &");
|
||||
TEST_CASE("nameof_enum_flag") {
|
||||
constexpr AnimalFlags af = AnimalFlags::HasClaws;
|
||||
auto af_name = nameof::nameof_enum_flag(af);
|
||||
AnimalFlags afm[3] = {AnimalFlags::HasClaws, AnimalFlags::CanFly, AnimalFlags::EatsFish};
|
||||
REQUIRE(af_name == "HasClaws");
|
||||
REQUIRE(nameof::nameof_enum_flag(AnimalFlags::EatsFish) == "EatsFish");
|
||||
REQUIRE(nameof::nameof_enum_flag(afm[1]) == "CanFly");
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 2)) == "HasClaws|CanFly");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 2 | 4)) == "HasClaws|CanFly|EatsFish");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 0 | 8)) == "HasClaws|Endangered");
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int> &&");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "struct SomeStruct &");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int> const &&");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct&");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int>&&");
|
||||
#endif
|
||||
constexpr BigFlags bf = BigFlags::A;
|
||||
auto bf_name = nameof::nameof_enum_flag(bf);
|
||||
BigFlags bfm[3] = {BigFlags::A, BigFlags::B, BigFlags::C};
|
||||
REQUIRE(bf_name == "A");
|
||||
REQUIRE(nameof::nameof_enum_flag(BigFlags::C) == "C");
|
||||
REQUIRE(nameof::nameof_enum_flag(bfm[1]) == "B");
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 2)).empty());
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20))) == "A|B");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20) | (static_cast<std::uint64_t>(0x1) << 63))) == "A|B|D");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 0 | (static_cast<std::uint64_t>(0x1) << 40))) == "A|C");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 0 | (static_cast<std::uint64_t>(0x1) << 40))) == "A|C");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE(decltype(struct_var));
|
||||
TEST_CASE("NAMEOF_ENUM") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_ENUM(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_ENUM(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_ENUM(cm[1]) == "GREEN");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_ENUM(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::three) == "three");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(Numbers::many).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_ENUM(dr);
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Left) == "Left");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_ENUM(nt);
|
||||
REQUIRE(NAMEOF_ENUM(number::one) == "one");
|
||||
REQUIRE(NAMEOF_ENUM(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(number::four).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM_CONST") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_ENUM_CONST(cr);
|
||||
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(cm[1]) == "GREEN");
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_ENUM_CONST(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::three) == "three");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::many) == "many");
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_ENUM_CONST(dr);
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Left) == "Left");
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_ENUM_CONST(nt);
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::one) == "one");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::four) == "four");
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM_FLAG") {
|
||||
constexpr AnimalFlags af = AnimalFlags::HasClaws;
|
||||
auto af_name = NAMEOF_ENUM_FLAG(af);
|
||||
AnimalFlags afm[3] = {AnimalFlags::HasClaws, AnimalFlags::CanFly, AnimalFlags::EatsFish};
|
||||
REQUIRE(af_name == "HasClaws");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(afm[1]) == "CanFly");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::EatsFish) == "EatsFish");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::Endangered) == "Endangered");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 2)) == "HasClaws|CanFly");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 2 | 4)) == "HasClaws|CanFly|EatsFish");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 0 | 8)) == "HasClaws|Endangered");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
|
||||
|
||||
constexpr BigFlags bf = BigFlags::A;
|
||||
auto bf_name = NAMEOF_ENUM_FLAG(bf);
|
||||
BigFlags bfm[3] = {BigFlags::A, BigFlags::B, BigFlags::C};
|
||||
REQUIRE(bf_name == "A");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(bfm[1]) == "B");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::C) == "C");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::D) == "D");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | 2)).empty());
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20))) == "A|B");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20) | (static_cast<std::uint64_t>(0x1) << 63))) == "A|B|D");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("nameof_enum_or") {
|
||||
OutOfRange low = OutOfRange::too_low;
|
||||
OutOfRange high = OutOfRange::too_high;
|
||||
auto low_name = nameof::nameof_enum_or(low, "-121");
|
||||
auto high_name = nameof::nameof_enum_or(high, "121");
|
||||
constexpr OutOfRange oor[] = {OutOfRange::too_high, OutOfRange::too_low};
|
||||
REQUIRE(low_name == "-121");
|
||||
REQUIRE(high_name == "121");
|
||||
REQUIRE(nameof::nameof_enum_or(oor[0], "121") == "121");
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM_OR") {
|
||||
OutOfRange low = OutOfRange::too_low;
|
||||
OutOfRange high = OutOfRange::too_high;
|
||||
auto low_name = NAMEOF_ENUM_OR(low, "-121");
|
||||
auto high_name = NAMEOF_ENUM_OR(high, "121");
|
||||
constexpr OutOfRange oor[] = {OutOfRange::too_high, OutOfRange::too_low};
|
||||
REQUIRE(low_name == "-121");
|
||||
REQUIRE(high_name == "121");
|
||||
REQUIRE(NAMEOF_ENUM_OR(oor[0], "121") == "121");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NAMEOF_TYPE_SUPPORTED)
|
||||
|
||||
static_assert(nameof::is_nameof_type_supported, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
|
||||
TEST_CASE("nameof::nameof_type") {
|
||||
constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>();
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int> *");
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "struct SomeStruct const volatile *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "struct SomeStruct const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "class SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "class SomeClass<int> const volatile *");
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "class SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "struct Long::LL");
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "struct Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "enum Color");
|
||||
REQUIRE(nameof::nameof_type<Color>() == "enum Color");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int>*");
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -524,51 +596,22 @@ TEST_CASE("nameof::nameof_full_type") {
|
|||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var);
|
||||
#if defined(__clang__)
|
||||
TEST_CASE("nameof::nameof_short_type") {
|
||||
constexpr auto type_name = nameof::nameof_short_type<decltype(struct_var)>();
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<const SomeStruct volatile>() == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
REQUIRE(nameof::nameof_short_type<SomeClass<int>>() == "SomeClass");
|
||||
REQUIRE(nameof::nameof_short_type<const SomeClass<int> volatile>() == "SomeClass");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
REQUIRE(nameof::nameof_short_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_short_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_short_type<Long::LL>() == "LL");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "struct SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int>");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#endif
|
||||
REQUIRE(nameof::nameof_short_type<Color>() == "Color");
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_TYPE") {
|
||||
|
@ -627,58 +670,309 @@ TEST_CASE("NAMEOF_TYPE") {
|
|||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("nameof::nameof_type") {
|
||||
constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>();
|
||||
TEST_CASE("NAMEOF_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var);
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int> *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "struct SomeStruct const volatile *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "struct SomeStruct");
|
||||
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "class SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "class SomeClass<int> const volatile *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(nameof::nameof_type<Color>() == "enum Color");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int>");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int>*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE(decltype(struct_var));
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "struct SomeStruct const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "class SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "struct Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "enum Color");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE_EXPR(struct_var);
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct &");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int> &&");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "struct SomeStruct &");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int> const &&");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct&");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int>&&");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_SHORT_TYPE") {
|
||||
constexpr auto type_name = NAMEOF_SHORT_TYPE(decltype(struct_var));
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(decltype(ref_s)) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(SomeStruct &) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(const SomeStruct volatile) == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(SomeClass<int>) == "SomeClass");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(const SomeClass<int> volatile) == "SomeClass");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(Long::LL) == "LL");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(Color) == "Color");
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_SHORT_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_SHORT_TYPE_EXPR(struct_var);
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar.ll) == "LL");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED) && NAMEOF_TYPE_RTTI_SUPPORTED
|
||||
|
||||
TEST_CASE("NAMEOF_TYPE_RTTI") {
|
||||
TestRtti::Base* ptr = new TestRtti::Derived();
|
||||
const TestRtti::Base& const_ref = *ptr;
|
||||
volatile TestRtti::Base& volatile_ref = *ptr;
|
||||
volatile const TestRtti::Base& cv_ref = *ptr;
|
||||
#if defined(__clang__) && !defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "TestRtti::Derived");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "struct TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "struct TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "struct TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "struct TestRtti::Derived");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "TestRtti::Derived");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE_RTTI") {
|
||||
TestRtti::Base* ptr = new TestRtti::Derived();
|
||||
const TestRtti::Base& const_ref = *ptr;
|
||||
volatile TestRtti::Base& volatile_ref = *ptr;
|
||||
volatile const TestRtti::Base& cv_ref = *ptr;
|
||||
#if defined(__clang__) && !defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const TestRtti::Derived&");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "struct TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const struct TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile struct TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const struct TestRtti::Derived&");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const TestRtti::Derived&");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_SHORT_TYPE_RTTI") {
|
||||
TestRtti::Base* ptr = new TestRtti::Derived();
|
||||
const TestRtti::Base& const_ref = *ptr;
|
||||
volatile TestRtti::Base& volatile_ref = *ptr;
|
||||
volatile const TestRtti::Base& cv_ref = *ptr;
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(*ptr) == "Derived");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(const_ref) == "Derived");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(volatile_ref) == "Derived");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(cv_ref) == "Derived");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NAMEOF_MEMBER_SUPPORTED) && NAMEOF_MEMBER_SUPPORTED
|
||||
|
||||
struct StructMemberInitializationUsingNameof {
|
||||
std::string teststringfield = std::string{nameof::nameof_member<&StructMemberInitializationUsingNameof::teststringfield>()};
|
||||
};
|
||||
|
||||
struct StructWithNonConstexprDestructor {
|
||||
~StructWithNonConstexprDestructor() {}
|
||||
int somefield;
|
||||
};
|
||||
|
||||
TEST_CASE("NAMEOF_MEMBER") {
|
||||
REQUIRE(NAMEOF_MEMBER(&SomeStruct::somefield) == "somefield");
|
||||
REQUIRE(NAMEOF_MEMBER(&SomeStruct::SomeMethod1) == "SomeMethod1");
|
||||
REQUIRE(NAMEOF_MEMBER(&Long::LL::field) == "field");
|
||||
constexpr auto member_ptr = &SomeStruct::somefield;
|
||||
REQUIRE(NAMEOF_MEMBER(member_ptr) == "somefield");
|
||||
REQUIRE(NAMEOF_MEMBER(&StructMemberInitializationUsingNameof::teststringfield) == "teststringfield");
|
||||
REQUIRE(NAMEOF_MEMBER(&StructWithNonConstexprDestructor::somefield) == "somefield");
|
||||
}
|
||||
|
||||
TEST_CASE("nameof_member") {
|
||||
REQUIRE(nameof::nameof_member<&SomeStruct::somefield>() == "somefield");
|
||||
REQUIRE(nameof::nameof_member<&SomeStruct::SomeMethod1>() == "SomeMethod1");
|
||||
REQUIRE(nameof::nameof_member<&Long::LL::field>() == "field");
|
||||
constexpr auto member_ptr = &SomeStruct::somefield;
|
||||
REQUIRE(nameof::nameof_member<member_ptr>() == "somefield");
|
||||
REQUIRE(nameof::nameof_member<&StructMemberInitializationUsingNameof::teststringfield>() == "teststringfield");
|
||||
REQUIRE(nameof::nameof_member<&StructWithNonConstexprDestructor::somefield>() == "somefield");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NAMEOF_POINTER_SUPPORTED) && NAMEOF_POINTER_SUPPORTED
|
||||
|
||||
void somefunction() {}
|
||||
|
||||
TEST_CASE("NAMEOF_POINTER") {
|
||||
REQUIRE(NAMEOF_POINTER(&SomeStruct::somestaticfield) == "somestaticfield");
|
||||
REQUIRE(NAMEOF_POINTER(&SomeStruct::someotherstaticfield) == "someotherstaticfield");
|
||||
REQUIRE(NAMEOF_POINTER(static_cast<const char*>(nullptr)) == "nullptr");
|
||||
REQUIRE(NAMEOF_POINTER(static_cast<int***>(nullptr)) == "nullptr");
|
||||
constexpr auto global_ptr = &someglobalvariable;
|
||||
REQUIRE(NAMEOF_POINTER(global_ptr) == "someglobalvariable");
|
||||
REQUIRE(NAMEOF_POINTER(&someglobalconstvariable) == "someglobalconstvariable");
|
||||
REQUIRE(NAMEOF_POINTER(&somefunction) == "somefunction");
|
||||
}
|
||||
|
||||
TEST_CASE("nameof_pointer") {
|
||||
REQUIRE(nameof::nameof_pointer<&SomeStruct::somestaticfield>() == "somestaticfield");
|
||||
REQUIRE(nameof::nameof_pointer<&SomeStruct::someotherstaticfield>() == "someotherstaticfield");
|
||||
REQUIRE(nameof::nameof_pointer<static_cast<const char*>(nullptr)>() == "nullptr");
|
||||
REQUIRE(nameof::nameof_pointer<static_cast<int***>(nullptr)>() == "nullptr");
|
||||
constexpr auto global_ptr = &someglobalvariable;
|
||||
REQUIRE(nameof::nameof_pointer<global_ptr>() == "someglobalvariable");
|
||||
REQUIRE(nameof::nameof_pointer<&someglobalconstvariable>() == "someglobalconstvariable");
|
||||
REQUIRE(nameof::nameof_pointer<&somefunction>() == "somefunction");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
97
test/test_aliases.cpp
Normal file
97
test/test_aliases.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch.hpp>
|
||||
|
||||
struct MyString {
|
||||
MyString() : str{} {} // required
|
||||
MyString(const char* s) : str{s} {} // required
|
||||
MyString(const char* s, std::size_t l) : str{s, l} {} // required
|
||||
bool empty() const { return str.empty(); } // required
|
||||
MyString& append(std::size_t count, char c) { str.append(count, c); return *this; } // required
|
||||
MyString& append(const char* s, std::size_t count) { str.append(s, count); return *this; } // required
|
||||
MyString& append(const MyString& s) { str.append(s.str); return *this; } // required
|
||||
|
||||
std::size_t size() const { return str.size(); }
|
||||
int compare(const char* s) const { return str.compare(s); }
|
||||
|
||||
private:
|
||||
std::string str;
|
||||
};
|
||||
|
||||
struct MyStringView {
|
||||
using value_type = char; // required
|
||||
static constexpr auto npos = std::string_view::npos; // required
|
||||
|
||||
constexpr MyStringView() : str{} {} // required
|
||||
constexpr MyStringView(const char* s) : str{s} {} // required
|
||||
constexpr MyStringView(const char* s, std::size_t size) : str{s, size} {} // required
|
||||
constexpr bool empty() const { return str.empty(); } // required
|
||||
constexpr std::size_t size() const { return str.size(); } // required
|
||||
constexpr const char* data() const { return str.data(); } // required
|
||||
constexpr const char& operator[](std::size_t i) const { return str[i]; } // required
|
||||
constexpr void remove_prefix(std::size_t n) { str.remove_prefix(n); } // required
|
||||
constexpr void remove_suffix(std::size_t n) { str.remove_suffix(n); } // required
|
||||
constexpr int compare(MyStringView s) const { return str.compare(s.str); } // required
|
||||
|
||||
constexpr int compare(const char* s) const { return str.compare(s); }
|
||||
|
||||
private:
|
||||
std::string_view str;
|
||||
|
||||
constexpr MyStringView(std::string_view s) : str{s} {}
|
||||
};
|
||||
|
||||
#define NAMEOF_USING_ALIAS_STRING using string = MyString;
|
||||
#define NAMEOF_USING_ALIAS_STRING_VIEW using string_view = MyStringView;
|
||||
|
||||
#include <nameof.hpp>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
|
||||
TEST_CASE("string") {
|
||||
auto cr = nameof::nameof_enum_flag(Color::RED);
|
||||
REQUIRE_FALSE(cr.empty());
|
||||
REQUIRE(cr.compare("RED") == 0);
|
||||
|
||||
auto crg = nameof::nameof_enum_flag(static_cast<Color>(1 | 2));
|
||||
REQUIRE_FALSE(crg.empty());
|
||||
REQUIRE(crg.compare("RED|GREEN") == 0);
|
||||
|
||||
auto cn = nameof::nameof_enum_flag(Color{0});
|
||||
REQUIRE(cn.empty());
|
||||
REQUIRE(cn.size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("string_view") {
|
||||
auto cr = nameof::nameof_enum(Color::RED);
|
||||
REQUIRE_FALSE(cr.empty());
|
||||
REQUIRE(cr.compare("RED") == 0);
|
||||
|
||||
auto cn = nameof::nameof_enum(Color{0});
|
||||
REQUIRE(cn.empty());
|
||||
REQUIRE(cn.size() == 0);
|
||||
}
|
Loading…
Reference in a new issue