mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
249 Commits
help
...
boost-1.90
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aa41ed4f5 | ||
|
|
7509049f2c | ||
|
|
4f9e6457b0 | ||
|
|
fc2dba87d6 | ||
|
|
d9fde1f2a0 | ||
|
|
5034bf55fb | ||
|
|
8cbffcb7ab | ||
|
|
dcf2deb959 | ||
|
|
2e3663d0df | ||
|
|
7259e35f71 | ||
|
|
f223709e42 | ||
|
|
f61b90ec59 | ||
|
|
820f56c316 | ||
|
|
9bc3cb2af7 | ||
|
|
57fa1018b0 | ||
|
|
db9451143a | ||
|
|
8417d4fd2d | ||
|
|
f004e91c9b | ||
|
|
b95fd86595 | ||
|
|
3e5c474337 | ||
|
|
c902451cc0 | ||
|
|
1756327d0a | ||
|
|
5a48d7456f | ||
|
|
3fe5ce61ee | ||
|
|
f09e6aeae9 | ||
|
|
69263f4757 | ||
|
|
469ac134f3 | ||
|
|
ff415a26ff | ||
|
|
8cd1a9675d | ||
|
|
4d912c1925 | ||
|
|
e1a0832a0e | ||
|
|
73938e0936 | ||
|
|
e4cbbc78f0 | ||
|
|
6591a8609d | ||
|
|
3d090e7c6f | ||
|
|
e1e908e804 | ||
|
|
60391652fa | ||
|
|
dec9341546 | ||
|
|
449bf360f7 | ||
|
|
5f857d5503 | ||
|
|
9b90f2f6bb | ||
|
|
8f3b819b1e | ||
|
|
4a973c5eb4 | ||
|
|
4c15f217f4 | ||
|
|
e969c57be5 | ||
|
|
16d771f498 | ||
|
|
16a97bb1f5 | ||
|
|
8a0447b486 | ||
|
|
b674d728be | ||
|
|
5b55480c65 | ||
|
|
98789f610a | ||
|
|
c695aa0b32 | ||
|
|
294a4976bd | ||
|
|
2c79036816 | ||
|
|
6b415eaa5c | ||
|
|
11133a4f63 | ||
|
|
b1432d5fa9 | ||
|
|
8a13352854 | ||
|
|
e48f84dcb1 | ||
|
|
ba25324b12 | ||
|
|
df1249f6b8 | ||
|
|
f81c54ced0 | ||
|
|
f23c003c51 | ||
|
|
95a2044e8b | ||
|
|
7738b09132 | ||
|
|
7f5895b3a3 | ||
|
|
245ac56645 | ||
|
|
ec0ea4a338 | ||
|
|
d8a10e2abd | ||
|
|
2674cf4fd4 | ||
|
|
2876b2e793 | ||
|
|
48b9be5070 | ||
|
|
226352be5e | ||
|
|
65bf6b579f | ||
|
|
c82490024c | ||
|
|
552463a4e3 | ||
|
|
642d1f7d23 | ||
|
|
ad7ab1cfc3 | ||
|
|
3438d5e815 | ||
|
|
356e937dd9 | ||
|
|
282e033e4b | ||
|
|
04aef42dcb | ||
|
|
86911e0247 | ||
|
|
f4ebd9d49d | ||
|
|
fc89551a19 | ||
|
|
7e19e45d85 | ||
|
|
53fcd78d4f | ||
|
|
833f32960a | ||
|
|
730f40b6b2 | ||
|
|
67f4fc4398 | ||
|
|
7ba81adbd6 | ||
|
|
defcf22e4d | ||
|
|
9cc76bc277 | ||
|
|
27b9706ac5 | ||
|
|
41e87fbadb | ||
|
|
3f07e7187e | ||
|
|
6dcf66cbd5 | ||
|
|
8794056e20 | ||
|
|
dd8a5277fb | ||
|
|
5a7d6524a7 | ||
|
|
0cb5cf2ae7 | ||
|
|
2c79ac703b | ||
|
|
dbbfa6ea7f | ||
|
|
fcfca74355 | ||
|
|
9b2817a52b | ||
|
|
efd25e9968 | ||
|
|
9b6a0deac6 | ||
|
|
a5b9cd567f | ||
|
|
6e23ed540f | ||
|
|
6f544ceaa7 | ||
|
|
b15196c2e0 | ||
|
|
50c9d6f6e7 | ||
|
|
196aeb6da0 | ||
|
|
fe5a70bac9 | ||
|
|
b5e523f2b3 | ||
|
|
674f3723c5 | ||
|
|
e61fa139b6 | ||
|
|
03e1d768b7 | ||
|
|
963460a3c1 | ||
|
|
275eabb7ed | ||
|
|
2fa9036d56 | ||
|
|
454947de51 | ||
|
|
f09357c1bf | ||
|
|
e8e077c346 | ||
|
|
4a1defaaeb | ||
|
|
b0bf18798c | ||
|
|
9bc057e2a6 | ||
|
|
e460ce2ddc | ||
|
|
d66c0a9551 | ||
|
|
95c06fb7c6 | ||
|
|
ab509a5b32 | ||
|
|
ed28602c2c | ||
|
|
dbc78d7dd9 | ||
|
|
551174b58c | ||
|
|
79b0d65d4f | ||
|
|
2116be9285 | ||
|
|
a9a295e4aa | ||
|
|
2775d19f34 | ||
|
|
633c4bc985 | ||
|
|
b1af355a49 | ||
|
|
ef505f10c3 | ||
|
|
1be5e116f4 | ||
|
|
bca51da20f | ||
|
|
47c6413530 | ||
|
|
52a5a489ba | ||
|
|
fd584a405d | ||
|
|
b6a960757b | ||
|
|
dac40b2153 | ||
|
|
58ce59cf38 | ||
|
|
5010309967 | ||
|
|
bf5bd10b36 | ||
|
|
3279a7b610 | ||
|
|
d7db07e98d | ||
|
|
6a38a07285 | ||
|
|
69a06b98da | ||
|
|
578b5b2ac2 | ||
|
|
f12f35ac1a | ||
|
|
2b4e2922ae | ||
|
|
b2acaacaaf | ||
|
|
ff6c2b87c0 | ||
|
|
2a3ddbfc17 | ||
|
|
5374f9aebc | ||
|
|
968d692c5e | ||
|
|
5c13668343 | ||
|
|
6f853dad2c | ||
|
|
aa5abd8d76 | ||
|
|
ba40d86097 | ||
|
|
7a3a419c35 | ||
|
|
a70d02103a | ||
|
|
d59b6f9520 | ||
|
|
69c5692cd6 | ||
|
|
8f325567eb | ||
|
|
b10c0c66ed | ||
|
|
1bb4ced005 | ||
|
|
58dcb40a49 | ||
|
|
b7d839b851 | ||
|
|
3396cdca9e | ||
|
|
fbafd21118 | ||
|
|
b0aae28eb0 | ||
|
|
9388c4e4c0 | ||
|
|
4e84a5b159 | ||
|
|
7837449ca7 | ||
|
|
9bb809d2a5 | ||
|
|
2a1fd53724 | ||
|
|
cae0eaad61 | ||
|
|
ba10f9bc94 | ||
|
|
8a8b5bc8d3 | ||
|
|
a73f25d3ff | ||
|
|
a24717a4a1 | ||
|
|
10848f71ae | ||
|
|
7d925660bb | ||
|
|
87e77b9b43 | ||
|
|
b331ef58f5 | ||
|
|
5579d11588 | ||
|
|
51f6422c07 | ||
|
|
87c9c2d76c | ||
|
|
d1e7e87a31 | ||
|
|
14185d614f | ||
|
|
0436e48a79 | ||
|
|
4d9294cb1f | ||
|
|
e75c066ddc | ||
|
|
e51a594dbb | ||
|
|
12f2b3a365 | ||
|
|
2a1b206244 | ||
|
|
b4bee46c54 | ||
|
|
444094f20d | ||
|
|
da12b52759 | ||
|
|
94315117fa | ||
|
|
9c812d4217 | ||
|
|
c9674f6164 | ||
|
|
ed82d60966 | ||
|
|
5ffd7f6317 | ||
|
|
81d33f5bc6 | ||
|
|
a6e50ccf07 | ||
|
|
a7b6dd71a6 | ||
|
|
a3adfcf44b | ||
|
|
fbfb8e4abd | ||
|
|
7ac8beae4c | ||
|
|
42d96c04fb | ||
|
|
4301765f61 | ||
|
|
5ce264629c | ||
|
|
994bc05610 | ||
|
|
b14939376d | ||
|
|
861cc9d6af | ||
|
|
2c4bfdbc68 | ||
|
|
3660cf4c83 | ||
|
|
a3c71ae77d | ||
|
|
22f85d8e90 | ||
|
|
be8e2c65bc | ||
|
|
3b967a5fa7 | ||
|
|
33250407db | ||
|
|
8aa4e0712a | ||
|
|
4e05688247 | ||
|
|
b24b7f6d62 | ||
|
|
e94b247698 | ||
|
|
ea4c6e85f7 | ||
|
|
180db174ad | ||
|
|
186d6aacb6 | ||
|
|
5646daebad | ||
|
|
f33c357af6 | ||
|
|
9390106145 | ||
|
|
3b6d3a4cb9 | ||
|
|
638fefedd0 | ||
|
|
2506fbceb8 | ||
|
|
d2e5b44aec | ||
|
|
bbffc61524 | ||
|
|
36c020b032 | ||
|
|
4b38e4a243 | ||
|
|
9ef5a5646d |
277
.github/workflows/ci.yml
vendored
Normal file
277
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- feature/**
|
||||
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
|
||||
jobs:
|
||||
posix:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-14 # Do not remove! It is the only toolset that tests CMake tests down below
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-24.04
|
||||
- toolset: gcc-12
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-12"
|
||||
- toolset: gcc-11
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-11"
|
||||
- toolset: gcc-10
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-10"
|
||||
- toolset: gcc-9
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-9"
|
||||
- toolset: clang-15
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-22.04
|
||||
- toolset: clang-19 # tests misc/strip_boost_namespace.sh and modules
|
||||
cxxstd: "20,23"
|
||||
os: ubuntu-24.04
|
||||
install: clang-19 llvm-19 libclang-rt-19-dev libc++-19-dev libc++abi-19-dev clang-tools-19
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=pfr # Note: changed from ${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init --depth 10 --jobs 2 tools/boostdep libs/filesystem tools/inspect
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 3" filesystem
|
||||
rm -rf libs/$LIBRARY/*
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--depth 10 --jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 variant=debug tools/inspect
|
||||
|
||||
- name: Run CMake tests
|
||||
if: ${{matrix.toolset == 'gcc-14'}}
|
||||
run: |
|
||||
cd ../boost-root/
|
||||
mkdir __build
|
||||
cd __build
|
||||
cmake -DBUILD_TESTING=1 -DBOOST_INCLUDE_LIBRARIES=pfr -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_C_COMPILER=gcc-14 ..
|
||||
cmake --build . --target tests
|
||||
ctest --output-on-failure --no-tests=error
|
||||
cd ..
|
||||
rm -rf __build
|
||||
|
||||
- name: Run modules tests
|
||||
if: false
|
||||
# if: ${{matrix.toolset == 'clang-19'}}
|
||||
run: |
|
||||
cd ../boost-root/libs/pfr
|
||||
mkdir build_module
|
||||
cd build_module
|
||||
cmake -DBUILD_TESTING=1 -DBOOST_USE_MODULES=1 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++ -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test
|
||||
cmake --build .
|
||||
ctest -V
|
||||
cd ..
|
||||
rm -rf build_module
|
||||
|
||||
- name: Run modules tests wihtout 'import std;'
|
||||
if: ${{matrix.toolset == 'clang-19'}}
|
||||
run: |
|
||||
cd ../boost-root/libs/pfr
|
||||
mkdir build_module
|
||||
cd build_module
|
||||
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -GNinja -DCMAKE_CXX_COMPILER=clang++-19 ../test/cmake_subdir_test
|
||||
cmake --build .
|
||||
ctest -V
|
||||
cd ..
|
||||
rm -rf build_module
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -d0 headers
|
||||
./b2 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release "${{matrix.cxxflags}}" "${{matrix.linkflags}}" "${{matrix.launcher}}"
|
||||
dist/bin/inspect libs/$LIBRARY
|
||||
|
||||
- name: Test boost namespace stripping
|
||||
if: ${{matrix.toolset == 'clang-19'}}
|
||||
run: ../boost-root/libs/$LIBRARY/misc/strip_boost_namespace.sh
|
||||
|
||||
- name: Prepare coverage data
|
||||
if: matrix.gcov_tool
|
||||
run: |
|
||||
mkdir -p $GITHUB_WORKSPACE/coveralls
|
||||
|
||||
echo -e "#!/bin/bash\nexec ${{matrix.gcov_tool}} \"\$@\"" > $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
|
||||
chmod +x $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
|
||||
wget https://github.com/linux-test-project/lcov/archive/v1.16.zip
|
||||
unzip v1.16.zip
|
||||
LCOV="`pwd`/lcov-1.16/bin/lcov --gcov-tool $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh"
|
||||
|
||||
echo "$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory `pwd`/libs/$LIBRARY/test --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info"
|
||||
$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory ../boost-root/ --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info
|
||||
$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info "/usr*" "*/$LIBRARY/test/*" ${{matrix.ignore_coverage}} "*/$LIBRARY/tests/*" "*/$LIBRARY/examples/*" "*/$LIBRARY/example/*" -o $GITHUB_WORKSPACE/coveralls/coverage.info
|
||||
|
||||
cd ../boost-root
|
||||
OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$LIBRARY\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
echo $OTHER_LIBS
|
||||
eval "$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info $OTHER_LIBS -o $GITHUB_WORKSPACE/coveralls/coverage.info"
|
||||
|
||||
- name: Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
if: matrix.gcov_tool
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ./coveralls/coverage.info
|
||||
parallel: true
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: msvc-14.3 # tests CMake tests down below, does not run b2 tests
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 64
|
||||
os: windows-2025
|
||||
threads: "-j3"
|
||||
- toolset: gcc
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
addrmd: 64
|
||||
os: windows-2025
|
||||
threads: "-j3"
|
||||
- toolset: msvc-14.3 # tests CMake tests down below
|
||||
cxxstd: "20,latest"
|
||||
addrmd: 64
|
||||
os: windows-2022
|
||||
threads: "-j1"
|
||||
# Fails with "Unexpected compiler version, expected Clang 19.0.0 or newer."
|
||||
# - toolset: clang-win
|
||||
# cxxstd: "14,17,2a,latest"
|
||||
# addrmd: 32,64
|
||||
# os: windows-2022
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
set LIBRARY=pfr
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init --depth 10 --jobs 2 tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--jobs 3" %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
|
||||
- name: Run CMake tests
|
||||
if: ${{matrix.toolset == 'msvc-14.3'}}
|
||||
shell: cmd
|
||||
run: |
|
||||
choco install --no-progress ninja
|
||||
call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64
|
||||
cd ../boost-root/
|
||||
mkdir __build
|
||||
cd __build
|
||||
cmake -DBUILD_TESTING=1 -DBOOST_INCLUDE_LIBRARIES=pfr ..
|
||||
cmake --build . --target tests --config Debug
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
cd ..
|
||||
rm -rf __build
|
||||
|
||||
- name: Run modules tests
|
||||
if: false
|
||||
# if: ${{matrix.toolset == 'msvc-14.3'}}
|
||||
shell: cmd
|
||||
run: |
|
||||
choco install --no-progress ninja
|
||||
call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64
|
||||
cd ../boost-root/libs/pfr
|
||||
mkdir build_module
|
||||
cd build_module
|
||||
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test
|
||||
cmake --build .
|
||||
ctest --no-tests=error -V
|
||||
cd ..
|
||||
rm -rf build_module
|
||||
|
||||
- name: Run modules tests wihtout 'import std;'
|
||||
if: ${{matrix.toolset == 'msvc-14.3'}}
|
||||
shell: cmd
|
||||
run: |
|
||||
choco install --no-progress ninja
|
||||
call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64
|
||||
cd ../boost-root/libs/pfr
|
||||
mkdir build_module
|
||||
cd build_module
|
||||
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -DCMAKE_CXX_STANDARD=20 -G Ninja ../test/cmake_subdir_test
|
||||
cmake --build .
|
||||
ctest --no-tests=error -V
|
||||
cd ..
|
||||
rm -rf build_module
|
||||
|
||||
- name: Run tests
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 -d0 headers
|
||||
b2 ${{matrix.threads}} libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
|
||||
|
||||
finish:
|
||||
needs: posix
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.github_token }}
|
||||
parallel-finished: true
|
||||
177
.travis.yml
177
.travis.yml
@@ -1,177 +0,0 @@
|
||||
# Use, modification, and distribution are
|
||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Copyright Antony Polukhin 2014-2020.
|
||||
|
||||
#
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
# and how it can be used with Boost libraries.
|
||||
#
|
||||
# File revision #9 (with DIFF)
|
||||
|
||||
language: cpp
|
||||
os: linux
|
||||
dist: bionic
|
||||
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
matrix:
|
||||
include:
|
||||
# - env: B2_ARGS='cxxstd=14,1y toolset=gcc-6 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD -fno-rtti" linkflags="--coverage -lasan -lubsan"'
|
||||
# name: "GCC-6, no RTTI"
|
||||
# addons:
|
||||
# apt:
|
||||
# sources: ubuntu-toolchain-r-test
|
||||
# packages: g++-6
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-10 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
|
||||
name: "GCC-10"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages: g++-10
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
|
||||
name: "GCC-8"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages: g++-8
|
||||
|
||||
- env: B2_ARGS='cxxstd=1y toolset=gcc-5 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
|
||||
name: "GCC-5"
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages: g++-5
|
||||
|
||||
# - env: B2_ARGS='cxxstd=14,1y toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD -fno-exceptions" linkflags="--coverage -lasan -lubsan"'
|
||||
# name: "GCC-8, no exceptions"
|
||||
# sudo: required # Required by leak sanitizer
|
||||
# addons:
|
||||
# apt:
|
||||
# sources: ubuntu-toolchain-r-test
|
||||
# packages: g++-8
|
||||
|
||||
- env: B2_ARGS='cxxstd=14 toolset=clang-6 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -fsanitize=address,leak,undefined"'
|
||||
name: "Clang-6"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: llvm-toolchain-trusty-6
|
||||
packages: clang-6.0
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,17,20 toolset=clang-10 cxxflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined"'
|
||||
name: "Clang-10, libc++"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: llvm-toolchain-bionic-10
|
||||
packages:
|
||||
- clang-10
|
||||
- libc++-10-dev
|
||||
- libc++abi-10-dev
|
||||
|
||||
# Sanitizers disabled for this toolset as they started causing link troubles:
|
||||
# hidden symbol `_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE11__recommendEm' isn't defined
|
||||
- env: B2_ARGS='cxxstd=14 toolset=clang-libc++ cxxflags="--coverage -DBOOST_TRAVISCI_BUILD" linkflags="--coverage"'
|
||||
name: "Clang-3.8, libc++"
|
||||
addons:
|
||||
apt:
|
||||
packages: libc++-dev
|
||||
|
||||
###############################################################################################################
|
||||
# From this point and below code is same for all the Boost libs
|
||||
###############################################################################################################
|
||||
|
||||
# Installing additional tools
|
||||
addons:
|
||||
apt:
|
||||
sources: git-core
|
||||
packages:
|
||||
- git
|
||||
- python-yaml
|
||||
|
||||
before_install:
|
||||
# Autodetect Boost branch by using the following code: - BOOST_BRANCH=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost and use the folder for tests. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_LIBS_FOLDER=$(basename $TRAVIS_BUILD_DIR)
|
||||
# This will force to use local repo content, instead of the Boost's default.
|
||||
- BOOST_LIBS_FOLDER=pfr #$(basename $TRAVIS_BUILD_DIR)
|
||||
|
||||
# Global options for sanitizers
|
||||
- UBSAN_OPTIONS=print_stacktrace=1
|
||||
- LSAN_OPTIONS=verbosity=1:log_threads=1
|
||||
|
||||
# Cloning minimal set of Boost libraries
|
||||
- BOOST=$HOME/boost-local
|
||||
- echo "Testing $BOOST_LIBS_FOLDER, to remove $BOOST/libs/$BOOST_LIBS_FOLDER, testing branch $BOOST_BRANCH"
|
||||
- git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git $BOOST
|
||||
- cd $BOOST
|
||||
- git submodule update --init --depth 10 tools/build tools/boostdep
|
||||
|
||||
# Replacing Boost module with this project and installing Boost dependencies
|
||||
- rm -rf $BOOST/libs/$BOOST_LIBS_FOLDER
|
||||
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$BOOST_LIBS_FOLDER
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$BOOST_LIBS_FOLDER
|
||||
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" -I example -I examples $(basename $TRAVIS_BUILD_DIR)
|
||||
- git status
|
||||
|
||||
# Adding missing toolsets and preparing Boost headers
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
- |-
|
||||
echo "using gcc ;" >> ~/user-config.jam
|
||||
echo "using clang ;" >> ~/user-config.jam
|
||||
echo "using clang : 3.8 : clang++-3.8 ;" >> ~/user-config.jam
|
||||
echo "using clang : 4 : clang++-4.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 5 : clang++-5.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 6 : clang++-6.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 7 : clang++-7.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 8 : clang++-8 ;" >> ~/user-config.jam
|
||||
echo "using clang : 10 : clang++-10 ;" >> ~/user-config.jam
|
||||
echo "using clang : libc++ : clang++-libc++ ;" >> ~/user-config.jam
|
||||
- cd $BOOST/libs/$BOOST_LIBS_FOLDER/test/
|
||||
|
||||
script:
|
||||
- sh -c "../../../b2 -j2 $B2_ARGS"
|
||||
|
||||
after_success:
|
||||
# Copying Coveralls data to a separate folder
|
||||
- mkdir -p $TRAVIS_BUILD_DIR/coverals
|
||||
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- find ../../../bin.v2/ -name "*.da" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- find ../../../bin.v2/ -name "*.no" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- wget https://github.com/linux-test-project/lcov/archive/v1.12.zip
|
||||
- unzip v1.12.zip
|
||||
- LCOV="`pwd`/lcov-1.12/bin/lcov"
|
||||
|
||||
# Preparing Coveralls data by changind data format to a readable one
|
||||
- echo "$LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info"
|
||||
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing /test/ /example/ folder data
|
||||
- cd $BOOST
|
||||
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$BOOST_LIBS_FOLDER/test/*" $IGNORE_COVERAGE "*/$BOOST_LIBS_FOLDER/tests/*" "*/$BOOST_LIBS_FOLDER/examples/*" "*/$BOOST_LIBS_FOLDER/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing data that is not related to this project directly
|
||||
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$BOOST_LIBS_FOLDER\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
- echo $OTHER_LIBS
|
||||
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
|
||||
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
48
CMakeLists.txt
Normal file
48
CMakeLists.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
# Copyright 2020 Peter Dimov
|
||||
# Copyright (c) 2016-2025 Antony Polukhin
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.31)
|
||||
|
||||
project(boost_pfr VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
if (BOOST_USE_MODULES)
|
||||
add_library(boost_pfr)
|
||||
target_sources(boost_pfr PUBLIC
|
||||
FILE_SET modules_public TYPE CXX_MODULES FILES modules/boost_pfr.cppm
|
||||
)
|
||||
|
||||
target_compile_features(boost_pfr PUBLIC cxx_std_20)
|
||||
target_compile_definitions(boost_pfr PUBLIC BOOST_USE_MODULES)
|
||||
if (CMAKE_CXX_COMPILER_IMPORT_STD)
|
||||
target_compile_definitions(boost_pfr PRIVATE BOOST_PFR_USE_STD_MODULE)
|
||||
message(STATUS "Using `import std;`")
|
||||
else()
|
||||
message(STATUS "`import std;` is not available")
|
||||
endif()
|
||||
target_include_directories(boost_pfr PUBLIC include)
|
||||
else()
|
||||
add_library(boost_pfr INTERFACE)
|
||||
target_include_directories(boost_pfr INTERFACE include)
|
||||
endif()
|
||||
|
||||
add_library(Boost::pfr ALIAS boost_pfr)
|
||||
|
||||
enable_testing()
|
||||
if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
if (BOOST_USE_MODULES AND BUILD_TESTING)
|
||||
add_executable(boost_pfr_module_usage modules/usage_sample.cpp)
|
||||
target_link_libraries(boost_pfr_module_usage PRIVATE Boost::pfr)
|
||||
add_test(NAME boost_pfr_module_usage COMMAND boost_pfr_module_usage)
|
||||
|
||||
# Make sure that mixing includes and imports is fine for different TU
|
||||
add_executable(boost_pfr_module_usage_mu modules/usage_test_mu1.cpp modules/usage_test_mu2.cpp)
|
||||
target_link_libraries(boost_pfr_module_usage_mu PRIVATE Boost::pfr)
|
||||
add_test(NAME boost_pfr_module_usage_mu COMMAND boost_pfr_module_usage_mu)
|
||||
endif()
|
||||
|
||||
73
README.md
73
README.md
@@ -1,16 +1,19 @@
|
||||
# Boost.PFR
|
||||
# [Boost.PFR](https://boost.org/libs/pfr)
|
||||
|
||||
This is a C++14 library for very basic reflection that gives you access to structure elements by index and provides other `std::tuple` like methods for user defined types without any macro or boilerplate code.
|
||||
|
||||
[Boost.PFR](https://boost.org/libs/pfr) is a part of the [Boost C++ Libraries](https://github.com/boostorg). However, Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder from the github into your project, and the library will work fine.
|
||||
|
||||
[Latest documentation](http://apolukhin.github.com/magic_get/index.html)
|
||||
For a version of the library without `boost::` namespace see [PFR](https://github.com/apolukhin/pfr_non_boost).
|
||||
|
||||
### Test results
|
||||
|
||||
Branches | Build | Tests coverage | More info
|
||||
----------------|-------------- | -------------- |-----------
|
||||
Develop: | [](https://travis-ci.org/apolukhin/magic_get) [](https://ci.appveyor.com/project/apolukhin/magic-get/branch/develop) | [](https://coveralls.io/github/apolukhin/magic_get?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/pfr.html)
|
||||
Master: | [](https://travis-ci.org/apolukhin/magic_get) [](https://ci.appveyor.com/project/apolukhin/magic-get/branch/master) | [](https://coveralls.io/github/apolukhin/magic_get?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/pfr.html)
|
||||
Develop: | [](https://github.com/boostorg/pfr/actions/workflows/ci.yml) [](https://ci.appveyor.com/project/apolukhin/pfr/branch/develop) | [](https://coveralls.io/github/apolukhin/magic_get?branch=develop) | [details...](https://regression.boost.io/develop/developer/pfr.html)
|
||||
Master: | [](https://github.com/boostorg/pfr/actions/workflows/ci.yml) [](https://ci.appveyor.com/project/apolukhin/pfr/branch/master) | [](https://coveralls.io/github/apolukhin/magic_get?branch=master) | [details...](https://regression.boost.io/master/developer/pfr.html)
|
||||
|
||||
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/boost_pfr.html)
|
||||
|
||||
### Motivating Example #0
|
||||
```c++
|
||||
@@ -42,11 +45,13 @@ Outputs:
|
||||
Edgar Allan Poe was born in 1809
|
||||
```
|
||||
|
||||
[Run the above sample](https://godbolt.org/z/PfYsWKb7v)
|
||||
|
||||
|
||||
### Motivating Example #1
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include "boost/pfr/precise.hpp"
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
struct my_struct { // no ostream operator defined!
|
||||
int i;
|
||||
@@ -71,7 +76,7 @@ my_struct has 3 fields: {100, H, 3.14159}
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include "boost/pfr/precise.hpp"
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
struct my_struct { // no ostream operator defined!
|
||||
std::string s;
|
||||
@@ -91,11 +96,63 @@ Outputs:
|
||||
my_struct has 2 fields: {"Das ist fantastisch!", 100}
|
||||
```
|
||||
|
||||
### Motivating Example #3
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
#include <boost/fusion/include/adapt_boost_pfr.hpp>
|
||||
|
||||
#include "boost/pfr/io.hpp"
|
||||
|
||||
namespace x3 = boost::spirit::x3;
|
||||
|
||||
struct ast_employee { // No BOOST_FUSION_ADAPT_STRUCT defined
|
||||
int age;
|
||||
std::string forename;
|
||||
std::string surname;
|
||||
double salary;
|
||||
};
|
||||
|
||||
auto const quoted_string = x3::lexeme['"' >> +(x3::ascii::char_ - '"') >> '"'];
|
||||
|
||||
x3::rule<class employee, ast_employee> const employee = "employee";
|
||||
auto const employee_def =
|
||||
x3::lit("employee")
|
||||
>> '{'
|
||||
>> x3::int_ >> ','
|
||||
>> quoted_string >> ','
|
||||
>> quoted_string >> ','
|
||||
>> x3::double_
|
||||
>> '}'
|
||||
;
|
||||
BOOST_SPIRIT_DEFINE(employee);
|
||||
|
||||
int main() {
|
||||
std::string str = R"(employee{34, "Chip", "Douglas", 2500.00})";
|
||||
ast_employee emp;
|
||||
x3::phrase_parse(str.begin(),
|
||||
str.end(),
|
||||
employee,
|
||||
x3::ascii::space,
|
||||
emp);
|
||||
std::cout << boost::pfr::io(emp) << std::endl;
|
||||
}
|
||||
|
||||
```
|
||||
Outputs:
|
||||
```
|
||||
(34 Chip Douglas 2500)
|
||||
```
|
||||
|
||||
|
||||
### Requirements and Limitations
|
||||
|
||||
[See docs](http://apolukhin.github.com/magic_get/index.html).
|
||||
[See docs](https://www.boost.org/doc/libs/develop/doc/html/boost_pfr.html).
|
||||
|
||||
### License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
Distributed under the [Boost Software License, Version 1.0](https://boost.org/LICENSE_1_0.txt).
|
||||
|
||||
20
build.jam
Normal file
20
build.jam
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright René Ferdinand Rivera Morell 2023-2024
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
project /boost/pfr
|
||||
: common-requirements
|
||||
<include>include
|
||||
;
|
||||
|
||||
explicit
|
||||
[ alias boost_pfr : : : : <library>$(boost_dependencies) ]
|
||||
[ alias all : boost_pfr test ]
|
||||
;
|
||||
|
||||
call-if : boost-library pfr
|
||||
;
|
||||
|
||||
@@ -18,7 +18,7 @@ project pfr/doc ;
|
||||
|
||||
#
|
||||
# Common params for doxygen
|
||||
#
|
||||
#
|
||||
|
||||
local doxygen_params =
|
||||
<doxygen:param>EXTRACT_ALL=NO
|
||||
@@ -32,19 +32,22 @@ local doxygen_params =
|
||||
<doxygen:param>"ALIASES= \\
|
||||
\"forcedlink{1}=\\xmlonly<link linkend='boost.pfr.\\1'>\\endxmlonly boost::pfr::\\1\\xmlonly</link>\\endxmlonly\" \\
|
||||
\"podops=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.three_ways_of_getting_operators'>\\endxmlonly 'Three ways of getting operators' \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"fnrefl=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.reflection_of_field_name'>\\endxmlonly 'Reflection of field names' \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"customio=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.custom_printing_of_aggregates'>\\endxmlonly 'Custom printing of aggregates' \\xmlonly</link>\\endxmlonly for info on how to implement your own manipulator with custom format.\" \\
|
||||
\"aggregate=\\xmlonly<link linkend='boost_pfr.limitations_and_configuration'>\\endxmlonly simple aggregate \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"BOOST_PFR_DOXYGEN_INVOKED\" \\
|
||||
"
|
||||
<doxygen:param>"PREDEFINED= \\
|
||||
\"BOOST_PFR_DOXYGEN_INVOKED=1\" \\
|
||||
"
|
||||
;
|
||||
|
||||
doxygen autodoc_pfr
|
||||
:
|
||||
[ glob ../../../boost/pfr.hpp ]
|
||||
[ glob ../../../boost/pfr/*.hpp ]
|
||||
[ glob ../include/boost/pfr.hpp ]
|
||||
[ glob ../include/boost/pfr/*.hpp ]
|
||||
:
|
||||
$(doxygen_params)
|
||||
<xsl:param>"boost.doxygen.reftitle=Reference Section"
|
||||
<xsl:param>"boost.doxygen.reftitle=Reference Section of PFR"
|
||||
;
|
||||
|
||||
boostbook pfr-doc
|
||||
@@ -52,9 +55,8 @@ boostbook pfr-doc
|
||||
pfr.qbk
|
||||
:
|
||||
<dependency>autodoc_pfr
|
||||
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_72_0
|
||||
#<xsl:param>boost.root=../../../.
|
||||
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
#<xsl:param>boost.root=https://www.boost.org/doc/libs/1_88_0
|
||||
<xsl:param>boost.root=../../../..
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
|
||||
173
doc/pfr.qbk
173
doc/pfr.qbk
@@ -1,7 +1,7 @@
|
||||
[library Boost.PFR
|
||||
[quickbook 1.6]
|
||||
[version 2.0]
|
||||
[copyright 2016-2020 Antony Polukhin]
|
||||
[version 2.3]
|
||||
[copyright 2016-2025 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -17,6 +17,7 @@ Boost.PFR is a C++14 library for a very basic reflection. It gives you access to
|
||||
[import ../example/motivating_example0.cpp]
|
||||
[pfr_motivating_example]
|
||||
|
||||
Experiment with the sample [@https://godbolt.org/z/PfYsWKb7v online].
|
||||
See [link boost_pfr.limitations_and_configuration [*limitations]].
|
||||
|
||||
|
||||
@@ -42,23 +43,23 @@ user_info retrieve_friend(std::string_view name) {
|
||||
name
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
user_info info {
|
||||
std::move(std::get<0>(info_tuple)),
|
||||
std::move(std::get<1>(info_tuple)),
|
||||
std::move(std::get<2>(info_tuple)),
|
||||
std::move(std::get<3>(info_tuple)),
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto friend_info = ask_user_for_friend(std::move(info));
|
||||
|
||||
db::insert(
|
||||
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
|
||||
std::move(friend_info.id), //////////////////////////////////////////////
|
||||
std::move(friend_info.name), // Users are forced to move individual fields
|
||||
std::move(friend_info.email), // because your library can not iterate over
|
||||
std::move(friend_info.login) // the fields of a user provided structure
|
||||
friend_info.id, //////////////////////////////////////////////////////
|
||||
friend_info.name, // Users are forced to enumerate fields because your
|
||||
friend_info.email, // library can not iterate over the fields of a user
|
||||
friend_info.login // provided structure
|
||||
);
|
||||
|
||||
return friend_info;
|
||||
@@ -80,22 +81,22 @@ user_info retrieve_friend(std::string_view name) {
|
||||
name
|
||||
);
|
||||
|
||||
////////////////// No boilerplate code to move data around /////////////////////
|
||||
////////////////// No boilerplate code to move data around //////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto friend_info = ask_user_for_friend(std::move(info));
|
||||
|
||||
db::insert(
|
||||
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
|
||||
friend_info ////////////////////////////////////////////////////////////
|
||||
// Boost.PFR allows you to iterate over all the fields of a
|
||||
// user provided structure
|
||||
friend_info /////////////////////////////////////////////////////////
|
||||
// Boost.PFR allows you to iterate over all the fields
|
||||
// of a user provided structure
|
||||
//
|
||||
);
|
||||
|
||||
@@ -119,7 +120,7 @@ struct user_info {
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
/// Customizations via hand-written code or macro like BOOST_FUSION_ADAPT_STRUCT ///
|
||||
/// Customizations via hand-written code ////////////////////////////////////////
|
||||
auto db_api_tie(user_info& ui) noexcept {
|
||||
return std::tie(ui.id, ui.name, ui.email, ui.login);
|
||||
}
|
||||
@@ -127,7 +128,7 @@ auto db_api_tie(user_info& ui) noexcept {
|
||||
auto db_api_tie(const user_info& ui) noexcept {
|
||||
return std::tie(ui.id, ui.name, ui.email, ui.login);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
```
|
||||
][
|
||||
```
|
||||
@@ -138,7 +139,7 @@ struct user_info {
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
//////// With Boost.PFR there's no need in hand written customizations /////////////
|
||||
//////// With Boost.PFR there's no need in hand written customizations //////////
|
||||
|
||||
|
||||
|
||||
@@ -146,14 +147,29 @@ struct user_info {
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
```
|
||||
]]
|
||||
]
|
||||
|
||||
|
||||
Imagine that you are writing a serialization library. Serialization of user
|
||||
provided structures (and nested structures) with Boost.PFR it is just as simple as:
|
||||
|
||||
```
|
||||
void Write(Writer& writer, int value);
|
||||
void Write(Writer& writer, std::string_view value);
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<boost::pfr::is_implicitly_reflectable_v<T>> Write(Writer& writer, const T& value) {
|
||||
boost::pfr::for_each_field(
|
||||
value, [&writer](const auto& field) { Write(writer, field); });
|
||||
}
|
||||
```
|
||||
|
||||
With Boost.PFR the code is shorter, more readable and more pleasant to write.
|
||||
|
||||
[note All the above examples were inspired by the Boost.PFR usage in [@https://github.com/userver-framework/userver 🐙 userver framework].]
|
||||
|
||||
|
||||
[h2 Out of the box functionality ]
|
||||
@@ -164,14 +180,17 @@ Boost.PFR adds the following out-of-the-box functionality for aggregate initiali
|
||||
* heterogeneous comparators
|
||||
* hash
|
||||
* IO streaming
|
||||
* access to members by index
|
||||
* access to members by index or type
|
||||
* access to member's names by index
|
||||
* member type retrieval
|
||||
* methods for cooperation with `std::tuple`
|
||||
* methods for cooperation with `std::tuple` for members
|
||||
* methods for cooperation with `std::array` for member's names
|
||||
* methods to visit each field of the structure
|
||||
* trait to detect potential ability to reflect type, and ability to override trait's decision in user-side code
|
||||
|
||||
Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder [@https://github.com/boostorg/pfr from the github] into your project, and the library will work fine.
|
||||
Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder [@https://github.com/boostorg/pfr from the Boost.PFR github] into your project, and the library will work fine. For a version of the library without `boost::` namespace see [@https://github.com/apolukhin/pfr_non_boost PFR].
|
||||
|
||||
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
|
||||
[caution Recommended C++ Standards are C++20 and above. C++17 completely enough for a user who doesn't want accessing name of structure member. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -186,6 +205,9 @@ Boost.PFR is a header only library that does not depend on Boost. You can just c
|
||||
[
|
||||
[ [pfr_quick_examples_get] ]
|
||||
[ [funcref boost::pfr::get] ]
|
||||
][
|
||||
[ [pfr_quick_examples_get_name] ]
|
||||
[ [funcref boost::pfr::get_name] ]
|
||||
][
|
||||
[ [pfr_quick_examples_ops] ]
|
||||
[
|
||||
@@ -208,6 +230,9 @@ Boost.PFR is a header only library that does not depend on Boost. You can just c
|
||||
|
||||
[funcref boost::pfr::io]
|
||||
]
|
||||
][
|
||||
[ [pfr_quick_examples_for_each_with_name] ]
|
||||
[ [funcref boost::pfr::for_each_field_with_name] ]
|
||||
][
|
||||
[ [pfr_quick_examples_functions_for] ]
|
||||
[ [macroref BOOST_PFR_FUNCTIONS_FOR] ]
|
||||
@@ -252,6 +277,7 @@ Boost.PFR is a header only library that does not depend on Boost. You can just c
|
||||
|
||||
[import ../example/sample_printing.cpp]
|
||||
[import ../example/get.cpp]
|
||||
[import ../example/get_name.cpp]
|
||||
|
||||
|
||||
[section Why tuples are bad and aggregates are more preferable?]
|
||||
@@ -431,12 +457,21 @@ error: static_assert failed "====================> Boost.PFR: For safety reasons
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Reflection of field name ]
|
||||
|
||||
[pfr_example_get_name]
|
||||
|
||||
See [link boost_pfr.limitations_and_configuration [*Limitations and Configuration]].
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Limitations and Configuration]
|
||||
|
||||
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
|
||||
[caution Recommended C++ Standards are C++20 and above. C++17 completely enough for a user who doesn't want accessing name of structure member. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
|
||||
|
||||
Boost.PFR library works with types that satisfy the requirements of `SimpleAggregate`: aggregate types without base classes, `const` fields, references, or C arrays:
|
||||
|
||||
@@ -458,14 +493,24 @@ struct aggregate : empty { // not a SimpleAggregate
|
||||
```
|
||||
The library may work with aggregates that don't satisfy the requirements of `SimpleAggregate`, but the behavior tends to be non-portable.
|
||||
|
||||
Boost.PFRs extraction of field name works with only `SimpleAggregate` types.
|
||||
|
||||
|
||||
[h2 Configuration Macro]
|
||||
|
||||
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
|
||||
[table:linkmacro Macros
|
||||
[[Macro name] [Effect]]
|
||||
[[*BOOST_PFR_USE_CPP26*] [Define to `1` if you wish to override Boost.PFR choice and use C++26 variadic structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++26 variadic structured bindings usage.]]
|
||||
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to override Boost.PFR choice and use C++17 structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++17 structured bindings usage.]]
|
||||
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]]
|
||||
[[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use Boost.PFR version of that metafunction. Define to `1` to override Boost.PFR detection logic. ]]
|
||||
[[*BOOST_PFR_HAS_GUARANTEED_COPY_ELISION*] [Define to `0` if your compiler does not implement C++17 guaranteed copy elision properly and fails to reflect aggregates with non-movable fields. Define to `1` to override Boost.PFR detection logic. ]]
|
||||
[[*BOOST_PFR_ENABLE_IMPLICIT_REFLECTION*] [Define to `0` if you are hit by lots of non-effective choices made by implicitly reflection. Define to `1` to override Boost.PFR detection logic. ]]
|
||||
[[*BOOST_PFR_CORE_NAME_ENABLED*] [On platforms where field name extraction is not supported, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_CORE_NAME_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the ability to get a field name. ]]
|
||||
[[*BOOST_PFR_FUNCTION_SIGNATURE*] [For known compilers defined to a compiler specific macro, that outputs the whole function signature including non-type template parameters. ]]
|
||||
[[*BOOST_PFR_CORE_NAME_PARSING*] [Describes extraction of field name from BOOST_PFR_FUNCTION_SIGNATURE macro. See details below. ]]
|
||||
[[*BOOST_PFR_ENABLED*] [On platforms where Boost.PFR is not supported, the `boost/pfr/config.hpp` header defines the BOOST_PFR_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the Boost.PFR library. ]]
|
||||
]
|
||||
|
||||
|
||||
@@ -474,32 +519,93 @@ By default Boost.PFR [*auto-detects your compiler abilities] and automatically d
|
||||
The Boost.PFRs reflection has some limitations that depend on a C++ Standard and compiler capabilities:
|
||||
|
||||
* Static variables are ignored
|
||||
* T must be aggregate initializable without empty base classes
|
||||
* if T contains C arrays or it is inherited from non-empty type then the result of reflection may differ depending on the C++ version and library configuration
|
||||
* T must be aggregate initializable without base classes
|
||||
* if T contains C arrays then the result of reflection may differ depending on the C++ version and library configuration
|
||||
* Additional limitations if [*BOOST_PFR_USE_CPP17 == 0]:
|
||||
* Non of the member fields should have a template constructor from one parameter.
|
||||
* Additional limitations if [*BOOST_PFR_USE_LOOPHOLE == 0]:
|
||||
* T must be constexpr aggregate initializable and all its fields must be constexpr default constructible
|
||||
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/core.hpp boost::pfr::tuple_element] require T to be a POD type with built-in types only.
|
||||
|
||||
The Boost.PFRs extraction of field name has some limitations that depend on a C++ Standard and compiler capabilities:
|
||||
|
||||
* T should be usable like `extern T t;`, i.e. has a non-internal linkage.
|
||||
|
||||
[h2 Adjusting BOOST_PFR_CORE_NAME_PARSING]
|
||||
|
||||
`BOOST_PFR_CORE_NAME_PARSING` is already set up for most of the popular compilers. You need to adjust it only
|
||||
if some static_assert in the library complained on `BOOST_PFR_CORE_NAME_PARSING`.
|
||||
|
||||
To do that:
|
||||
|
||||
# Build `test/core_name/print_name.cpp` with your compiler and run it
|
||||
# Define BOOST_PFR_CORE_NAME_PARSING to `(skip_at_begin, skip_at_end, "")`, where
|
||||
* `skip_at_begin` is equal to characters count before the first occurrence of `user_defined_field` in output
|
||||
* `skip_at_end` is equal to characters count after last occurrence of `user_defined_field` in output
|
||||
# Check that `test/core_name/print_name.cpp` returns "user_defined_field"
|
||||
# If it does not return `user_defined_field`, then define BOOST_PFR_CORE_NAME_PARSING to `(skip_at_begin, skip_at_end, "T = ")`, where
|
||||
* `skip_at_begin` is equal to `skip_at_begin` at step 2
|
||||
* `skip_at_end` is equal to `skip_at_end` at step 2
|
||||
* `"T = "` is equal to characters that are right before the `user_defined_field` in output, use `backward("T = ")` to search for the occurange in the string from the right
|
||||
# (optional, but highly recommended) [@https://github.com/boostorg/pfr/issues create ticket] with
|
||||
feature request to add your compiler to supported compilers list. Include
|
||||
parameters provided to `BOOST_PFR_CORE_NAME_PARSING` macro [*and] the initial output of `test/core_name/print_name.cpp`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section PFR as a C++20 module]
|
||||
|
||||
[caution C++20 PFR module support is on early stage, targets, flags and behavior may change in the future]
|
||||
|
||||
If using modern CMake define CMake option `-DBOOST_USE_MODULES=1` to build a C++20 module and
|
||||
make the `Boost::pfr` CMake target provide it. After that an explicit usage of C++20 module `boost.pfr` is allowed:
|
||||
|
||||
[import ../modules/usage_sample.cpp]
|
||||
[pfr_module_example]
|
||||
|
||||
The `Boost::pfr` CMake target gives an ability to mix includes and imports of the PFR library in different translation units. Moreover,
|
||||
if `BOOST_USE_MODULES` macro is defined then all the `boost/pfr/...` includes implicitly do `import boost.pfr;` to give all the
|
||||
benifits of modules without changing the existing code.
|
||||
|
||||
[note For better compile times make sure that `import std;` is available when building the `boost.pfr` module (in CMake logs there should be
|
||||
a 'Using `import std;`' message). ]
|
||||
|
||||
If not using CMake, then the module could be build manually from the `modules/boost_pfr.cppm` file.
|
||||
|
||||
For manual module build the following commands can be used for clang compiler:
|
||||
|
||||
```
|
||||
cd pfr/module
|
||||
clang++ -I ../include -std=c++20 --precompile -x c++-module boost_pfr.cppm
|
||||
```
|
||||
|
||||
After that, the module could be used in the following way:
|
||||
|
||||
```
|
||||
clang++ -std=c++20 -fmodule-file=boost_pfr.pcm boost_pfr.pcm usage_sample.cpp
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section How it works]
|
||||
|
||||
[h2 Fields count detection and getting references to members]
|
||||
|
||||
Short description:
|
||||
|
||||
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
||||
* [*BOOST_PFR_USE_CPP17 == 1]:
|
||||
* [*BOOST_PFR_USE_CPP26 == 1]:
|
||||
# at compile-time: structured bindings are used to decompose a type `T` to known variadic amount of fields
|
||||
* [*BOOST_PFR_USE_CPP26 == 0 && BOOST_PFR_USE_CPP17 == 1]:
|
||||
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
|
||||
* [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 1]:
|
||||
* [*BOOST_PFR_USE_CPP26 == 0 && BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 1]:
|
||||
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
||||
# at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
|
||||
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
|
||||
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
|
||||
# at run-time: get pointer to each field, knowing the structure address and each field offset
|
||||
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
|
||||
* [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 0]:
|
||||
* [*BOOST_PFR_USE_CPP26 == 0 && BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 0]:
|
||||
# at compile-time: let `I` be is an index of current field, it equals 0
|
||||
# at run-time: `T` is constructed and field `I` is aggregate initialized using a separate instance of structure that is convertible to anything [note Additional care is taken to make sure that all the information about `T` is available to the compiler and that operations on `T` have no side effects, so the compiler can optimize away the unnecessary temporary objects.]
|
||||
# at compile-time: `I += 1`
|
||||
@@ -513,11 +619,22 @@ Long description of some basics: [@https://youtu.be/UlNUNxLtBI0 Antony Polukhin:
|
||||
Long description of some basics of C++14 with [link boost_pfr.limitations_and_configuration [*BOOST_PFR_USE_LOOPHOLE == 0]]: [@https://youtu.be/abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling].
|
||||
Description of the [*BOOST_PFR_USE_LOOPHOLE == 1] technique by its inventor Alexandr Poltavsky [@http://alexpolt.github.io/type-loophole.html in his blog].
|
||||
|
||||
[h2 Field name retrieval]
|
||||
|
||||
# at compile-time:
|
||||
* Get references to members of an object of type `T` in `constexpr` function
|
||||
* Feed the reference from previous as a template parameter to a `constexpr` function with `template <auto member_ptr>`.
|
||||
That function returns `__PRETTY_FUNCTION__` or some other vendor specific macro that prints the whole name of a function
|
||||
along with the template arguments.
|
||||
* The returned value from previous step contains the member name ([@https://godbolt.org/z/K4aWdcE9G godbolt example]). Do some
|
||||
compiler specific parsing of the value and make a `std::string_view` that contains only the member name.
|
||||
# at run-time: return the `std::string_view` with the member name.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Acknowledgements]
|
||||
|
||||
Many thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/apolukhin/magic_get/issues/5 Manual type registering/structured bindings might be unnecessary].
|
||||
Many thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/boostorg/pfr/issues/5 Manual type registering/structured bindings might be unnecessary].
|
||||
|
||||
Many thanks to Alexandr Poltavsky for initial implementation the [*BOOST_PFR_USE_LOOPHOLE == 1] technique and for describing it [@http://alexpolt.github.io/type-loophole.html in his blog].
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2020 Antony Polukhin
|
||||
// Copyright 2016-2025 Antony Polukhin
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See the accompanying file LICENSE_1_0.txt
|
||||
|
||||
43
example/get_name.cpp
Normal file
43
example/get_name.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#include <boost/pfr/config.hpp>
|
||||
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17
|
||||
//[pfr_example_get_name
|
||||
/*`
|
||||
Since C++20 it's possible to read name of a structure field by index using Boost.PFR library.
|
||||
The following example shows how to do it using [funcref boost::pfr::get_name].
|
||||
|
||||
Let's define some structure:
|
||||
*/
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct foo { // defining structure
|
||||
int some_integer;
|
||||
char c;
|
||||
};
|
||||
|
||||
/*`
|
||||
We can access field's names of that structure by index:
|
||||
*/
|
||||
constexpr std::string_view n1 = boost::pfr::get_name<0, foo>(); // returns "some_integer"
|
||||
constexpr std::string_view n2 = boost::pfr::get_name<1, foo>(); // returns "c"
|
||||
//] [/pfr_example_get_name]
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17
|
||||
if (n1 != "some_integer") return 1;
|
||||
if (n2 != "c") return 2;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2020 Antony Polukhin
|
||||
// Copyright 2016-2025 Antony Polukhin
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See the accompanying file LICENSE_1_0.txt
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
// boost-no-inspect
|
||||
void test_examples() {
|
||||
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
@@ -55,7 +56,7 @@ void test_examples() {
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_for_each_idx
|
||||
// Iterate over fields of a varible and output index and
|
||||
// Iterate over fields of a variable and output index and
|
||||
// type of a variable.
|
||||
|
||||
struct tag0{};
|
||||
@@ -76,6 +77,35 @@ void test_examples() {
|
||||
}
|
||||
|
||||
|
||||
// Disabling for MSVC as it gives a hard error on using local types:
|
||||
//
|
||||
// error C7631:
|
||||
// 'boost::pfr::detail::do_not_use_PFR_with_local_types<test_examples::sample>':
|
||||
// variable with internal linkage declared but not defined
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17 && !defined(_MSC_VER)
|
||||
{
|
||||
//[pfr_quick_examples_for_each_with_name
|
||||
// Print the name and value
|
||||
// of each element of the structure
|
||||
|
||||
struct test {
|
||||
int n;
|
||||
std::string str;
|
||||
};
|
||||
|
||||
test var{42, "Hello, World!"};
|
||||
|
||||
// Outputs:
|
||||
// n: 42
|
||||
// str: Hello, World!
|
||||
boost::pfr::for_each_field_with_name(var,
|
||||
[](std::string_view name, const auto& value) {
|
||||
std::cout << name << ": " << value << std::endl;
|
||||
});
|
||||
//]
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_tuple_size
|
||||
// Getting fields count of some structure
|
||||
@@ -90,7 +120,7 @@ void test_examples() {
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_get
|
||||
// Get field by index and assign new value to that field
|
||||
// Get field by index/type and assign new value to that field
|
||||
|
||||
struct sample {
|
||||
char c;
|
||||
@@ -99,11 +129,33 @@ void test_examples() {
|
||||
|
||||
sample var{};
|
||||
boost::pfr::get<1>(var) = 42.01f;
|
||||
boost::pfr::get<char>(var) = 'A';
|
||||
|
||||
std::cout << var.f; // Outputs: 42.01
|
||||
std::cout << var.c << var.f; // Outputs: A 42.01
|
||||
//]
|
||||
}
|
||||
|
||||
// Disabling for MSVC as it gives a hard error on using local types:
|
||||
//
|
||||
// error C7631:
|
||||
// 'boost::pfr::detail::do_not_use_PFR_with_local_types<test_examples::sample>':
|
||||
// variable with internal linkage declared but not defined
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17 && !defined(_MSC_VER)
|
||||
{
|
||||
//[pfr_quick_examples_get_name
|
||||
// Get name of field by index
|
||||
|
||||
struct sample {
|
||||
int f_int;
|
||||
long f_long;
|
||||
};
|
||||
|
||||
std::cout << boost::pfr::get_name<0, sample>()
|
||||
<< boost::pfr::get_name<1, sample>(); // Outputs: f_int f_long
|
||||
//]
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
{
|
||||
//[pfr_quick_examples_structure_to_tuple
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2020 Antony Polukhin
|
||||
// Copyright 2016-2025 Antony Polukhin
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See the accompanying file LICENSE_1_0.txt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,7 +9,9 @@
|
||||
/// \file boost/pfr.hpp
|
||||
/// Includes all the Boost.PFR headers
|
||||
|
||||
#include <boost/pfr/config.hpp>
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
#include <boost/pfr/functors.hpp>
|
||||
#include <boost/pfr/io.hpp>
|
||||
@@ -17,5 +19,7 @@
|
||||
#include <boost/pfr/ops.hpp>
|
||||
#include <boost/pfr/ops_fields.hpp>
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
#include <boost/pfr/traits_fwd.hpp>
|
||||
#include <boost/pfr/traits.hpp>
|
||||
|
||||
#endif // BOOST_PFR_HPP
|
||||
|
||||
174
include/boost/pfr/config.hpp
Normal file
174
include/boost/pfr/config.hpp
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_CONFIG_HPP
|
||||
#define BOOST_PFR_CONFIG_HPP
|
||||
#pragma once
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) && (__cplusplus >= 201402L || (defined(_MSC_VER) && defined(_MSVC_LANG) && _MSC_VER > 1900))
|
||||
#include <type_traits> // to get non standard platform macro definitions (__GLIBCXX__ for example)
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_USE_MODULES) || __cplusplus >= 202002L
|
||||
#include <version>
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/config.hpp
|
||||
/// Contains all the macros that describe Boost.PFR configuration, like BOOST_PFR_ENABLED
|
||||
///
|
||||
/// \note This header file doesn't require C++14 Standard and supports all C++ compilers, even pre C++14 compilers (C++11, C++03...).
|
||||
|
||||
// Reminder:
|
||||
// * MSVC++ 14.2 _MSC_VER == 1927 <- Loophole is known to work (Visual Studio ????)
|
||||
// * MSVC++ 14.1 _MSC_VER == 1916 <- Loophole is known to NOT work (Visual Studio 2017)
|
||||
// * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
|
||||
// * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
|
||||
|
||||
#ifdef BOOST_PFR_NOT_SUPPORTED
|
||||
# error Please, do not set BOOST_PFR_NOT_SUPPORTED value manually, use '-DBOOST_PFR_ENABLED=0' instead of it
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# if !defined(_MSVC_LANG) || _MSC_VER <= 1900
|
||||
# define BOOST_PFR_NOT_SUPPORTED 1
|
||||
# endif
|
||||
#elif __cplusplus < 201402L
|
||||
# define BOOST_PFR_NOT_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_LOOPHOLE
|
||||
# if defined(_MSC_VER)
|
||||
# if _MSC_VER >= 1927
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# endif
|
||||
# elif defined(__clang_major__) && __clang_major__ >= 8
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_CPP26
|
||||
#if __cpp_structured_bindings >= 202411L && __cpp_lib_forward_like >= 202207L
|
||||
#define BOOST_PFR_USE_CPP26 1
|
||||
#else
|
||||
#define BOOST_PFR_USE_CPP26 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_CPP17
|
||||
# ifdef __cpp_structured_bindings
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# elif defined(_MSVC_LANG)
|
||||
# if _MSVC_LANG >= 201703L
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (!BOOST_PFR_USE_CPP26 && !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_LOOPHOLE)
|
||||
# if (defined(_MSC_VER) && _MSC_VER < 1916) ///< in Visual Studio 2017 v15.9 PFR library with classic engine normally works
|
||||
# define BOOST_PFR_NOT_SUPPORTED 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE
|
||||
# if defined(BOOST_USE_MODULES)
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
// Assume that libstdc++ since GCC-7.3 does not have linear instantiation depth in std::make_integral_sequence
|
||||
# elif defined( __GLIBCXX__) && __GLIBCXX__ >= 20180101
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
# elif defined(_MSC_VER)
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
//# elif other known working lib
|
||||
# else
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
# if defined(__cpp_guaranteed_copy_elision) && (!defined(_MSC_VER) || _MSC_VER > 1928)
|
||||
# define BOOST_PFR_HAS_GUARANTEED_COPY_ELISION 1
|
||||
# else
|
||||
# define BOOST_PFR_HAS_GUARANTEED_COPY_ELISION 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
|
||||
# if defined(__cpp_lib_is_aggregate)
|
||||
# define BOOST_PFR_ENABLE_IMPLICIT_REFLECTION 1
|
||||
# else
|
||||
// There is no way to detect potential ability to be reflectable without std::is_aggregare
|
||||
# define BOOST_PFR_ENABLE_IMPLICIT_REFLECTION 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_CORE_NAME_ENABLED
|
||||
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L))
|
||||
# if (defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911) \
|
||||
|| (defined(__clang_major__) && __clang_major__ >= 12)
|
||||
# define BOOST_PFR_CORE_NAME_ENABLED 1
|
||||
# else
|
||||
# define BOOST_PFR_CORE_NAME_ENABLED 0
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_PFR_CORE_NAME_ENABLED 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_PFR_CORE_NAME_PARSING
|
||||
# if defined(_MSC_VER) && !defined(__clang__)
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (sizeof("auto __cdecl boost::pfr::detail::name_of_field_impl<") - 1, sizeof(">(void) noexcept") - 1, backward("->"))
|
||||
# elif defined(__clang__)
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (sizeof("auto boost::pfr::detail::name_of_field_impl() [MsvcWorkaround = ") - 1, sizeof("}]") - 1, backward("."))
|
||||
# elif defined(__GNUC__)
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (sizeof("consteval auto boost::pfr::detail::name_of_field_impl() [with MsvcWorkaround = ") - 1, sizeof(")]") - 1, backward("::"))
|
||||
# else
|
||||
// Default parser for other platforms... Just skip nothing!
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (0, 0, "")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(maybe_unused)
|
||||
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_MAYBE_UNUSED
|
||||
# define BOOST_PFR_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_ENABLED
|
||||
# ifdef BOOST_PFR_NOT_SUPPORTED
|
||||
# define BOOST_PFR_ENABLED 0
|
||||
# else
|
||||
# define BOOST_PFR_ENABLED 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#undef BOOST_PFR_NOT_SUPPORTED
|
||||
|
||||
#ifdef BOOST_PFR_INTERFACE_UNIT
|
||||
# define BOOST_PFR_BEGIN_MODULE_EXPORT export {
|
||||
# define BOOST_PFR_END_MODULE_EXPORT }
|
||||
#else
|
||||
# define BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
# define BOOST_PFR_END_MODULE_EXPORT
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_USE_MODULES) && !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
import boost.pfr;
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PFR_CONFIG_HPP
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,18 +9,22 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/stdtuple.hpp>
|
||||
#include <boost/pfr/detail/for_each_field_impl.hpp>
|
||||
#include <boost/pfr/detail/for_each_field.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/tie_from_structure_tuple.hpp>
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/core.hpp
|
||||
/// Contains all the basic tuple-like interfaces \forcedlink{get}, \forcedlink{tuple_size}, \forcedlink{tuple_element_t}, and others.
|
||||
@@ -29,36 +33,53 @@
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// \brief Returns reference or const reference to a field with index `I` in \aggregate `val`.
|
||||
/// Overload taking the type `U` returns reference or const reference to a field
|
||||
/// with provided type `U` in \aggregate `val` if there's only one field of such type in `val`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
///
|
||||
/// assert(boost::pfr::get<0>(s) == 10);
|
||||
/// boost::pfr::get<1>(s) = 0;
|
||||
///
|
||||
/// assert(boost::pfr::get<int>(s) == 10);
|
||||
/// boost::pfr::get<short>(s) = 11;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(const T& val) noexcept {
|
||||
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
const auto& [... members] = val;
|
||||
return std::forward_like<const T &>(members...[I]);
|
||||
#else
|
||||
return detail::sequence_tuple::get<I>(detail::tie_as_tuple(val));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(T& val
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) noexcept {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
auto& [... members] = val;
|
||||
return std::forward_like<T &>(members...[I]);
|
||||
#else
|
||||
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17");
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17 and later");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -66,8 +87,47 @@ constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nul
|
||||
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = 0) noexcept {
|
||||
constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
auto&& [... members] = std::forward<T>(val);
|
||||
return std::move(members...[I]);
|
||||
#else
|
||||
return std::move(detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) ));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr const U& get(const T& val) noexcept {
|
||||
return detail::sequence_tuple::get_by_type_impl<const U&>( detail::tie_as_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr U& get(T& val
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) noexcept {
|
||||
return detail::sequence_tuple::get_by_type_impl<U&>( detail::tie_as_tuple(val) );
|
||||
}
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr U& get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17 and later");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr U&& get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
|
||||
return std::move(detail::sequence_tuple::get_by_type_impl<U&>( detail::tie_as_tuple(val) ));
|
||||
}
|
||||
|
||||
|
||||
@@ -97,15 +157,20 @@ using tuple_element_t = typename tuple_element<I, T>::type;
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
/// std::tuple<int, short> t = make_tuple(s);
|
||||
/// std::tuple<int, short> t = boost::pfr::structure_to_tuple(s);
|
||||
/// assert(get<0>(t) == 10);
|
||||
/// \endcode
|
||||
template <class T>
|
||||
constexpr auto structure_to_tuple(const T& val) noexcept {
|
||||
constexpr auto structure_to_tuple(const T& val) {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
const auto& [... members] = val;
|
||||
return std::make_tuple(members...);
|
||||
#else
|
||||
return detail::make_stdtuple_from_tietuple(
|
||||
detail::tie_as_tuple(val),
|
||||
detail::make_index_sequence< tuple_size_v<T> >()
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -119,39 +184,47 @@ constexpr auto structure_to_tuple(const T& val) noexcept {
|
||||
/// struct my_struct { int i, short s; };
|
||||
///
|
||||
/// const my_struct const_s{1, 2};
|
||||
/// std::apply(foo, structure_tie(const_s));
|
||||
/// std::apply(foo, boost::pfr::structure_tie(const_s));
|
||||
///
|
||||
/// my_struct s;
|
||||
/// structure_tie(s) = std::tuple<int, short>{10, 11};
|
||||
/// boost::pfr::structure_tie(s) = std::tuple<int, short>{10, 11};
|
||||
/// assert(s.s == 11);
|
||||
/// \endcode
|
||||
template <class T>
|
||||
constexpr auto structure_tie(const T& val) noexcept {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
const auto& [... members] = val;
|
||||
return std::tie(std::forward_like<const T &>(members)...);
|
||||
#else
|
||||
return detail::make_conststdtiedtuple_from_tietuple(
|
||||
detail::tie_as_tuple(const_cast<T&>(val)),
|
||||
detail::make_index_sequence< tuple_size_v<T> >()
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// \overload structure_tie
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T& val
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) noexcept {
|
||||
return detail::make_stdtiedtuple_from_tietuple(
|
||||
detail::tie_as_tuple(val),
|
||||
detail::make_index_sequence< tuple_size_v<T> >()
|
||||
);
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
auto& [... members] = val;
|
||||
return std::tie(std::forward_like<T &>(members)...);
|
||||
#else
|
||||
return detail::make_stdtiedtuple_from_tietuple(detail::tie_as_tuple(val),
|
||||
detail::make_index_sequence<tuple_size_v<T> >());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
/// \overload structure_tie
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on non const non assignable type is allowed only in C++17");
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on non const non assignable type is allowed only in C++17 and later modes");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -159,7 +232,7 @@ constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::val
|
||||
|
||||
/// \overload structure_tie
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = 0) noexcept {
|
||||
constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on rvalue references is forbidden");
|
||||
return 0;
|
||||
}
|
||||
@@ -177,29 +250,12 @@ constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference<T&&
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// int sum = 0;
|
||||
/// for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
|
||||
/// boost::pfr::for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
|
||||
/// assert(sum == 42);
|
||||
/// \endcode
|
||||
template <class T, class F>
|
||||
void for_each_field(T&& value, F&& func) {
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
value,
|
||||
[f = std::forward<F>(func)](auto&& t) mutable {
|
||||
// MSVC related workaround. Its lambdas do not capture constexprs.
|
||||
constexpr std::size_t fields_count_val_in_lambda
|
||||
= boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
|
||||
::boost::pfr::detail::for_each_field_impl(
|
||||
t,
|
||||
std::forward<F>(f),
|
||||
detail::make_index_sequence<fields_count_val_in_lambda>{},
|
||||
std::is_rvalue_reference<T&&>{}
|
||||
);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_val>{}
|
||||
);
|
||||
constexpr void for_each_field(T&& value, F&& func) {
|
||||
return ::boost::pfr::detail::for_each_field(std::forward<T>(value), std::forward<F>(func));
|
||||
}
|
||||
|
||||
/// \brief std::tie-like function that allows assigning to tied values from aggregates.
|
||||
@@ -214,13 +270,17 @@ void for_each_field(T&& value, F&& func) {
|
||||
/// return res;
|
||||
/// }
|
||||
/// auto [p, s] = f();
|
||||
/// tie_from_structure(p, s) = f();
|
||||
/// boost::pfr::tie_from_structure(p, s) = f();
|
||||
/// \endcode
|
||||
template <typename... Elements>
|
||||
constexpr detail::tie_from_structure_tuple<Elements...> tie_from_structure(Elements&... args) noexcept {
|
||||
return detail::tie_from_structure_tuple<Elements...>(args...);
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_CORE_HPP
|
||||
|
||||
118
include/boost/pfr/core_name.hpp
Normal file
118
include/boost/pfr/core_name.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_CORE_NAME_HPP
|
||||
#define BOOST_PFR_CORE_NAME_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/detail/core_name.hpp>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/stdarray.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <cstddef> // for std::size_t
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/core_name.hpp
|
||||
/// Contains functions \forcedlink{get_name} and \forcedlink{names_as_array} to know which names each field of any \aggregate has.
|
||||
///
|
||||
/// \fnrefl for details.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// \brief Returns name of a field with index `I` in \aggregate `T`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
///
|
||||
/// assert(boost::pfr::get_name<0, my_struct>() == "i");
|
||||
/// assert(boost::pfr::get_name<1, my_struct>() == "s");
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
constexpr
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
std::string_view
|
||||
#else
|
||||
auto
|
||||
#endif
|
||||
get_name() noexcept {
|
||||
return detail::get_name<T, I>();
|
||||
}
|
||||
|
||||
// FIXME: implement this
|
||||
// template<class U, class T>
|
||||
// constexpr auto get_name() noexcept {
|
||||
// return detail::sequence_tuple::get_by_type_impl<U>( detail::tie_as_names_tuple<T>() );
|
||||
// }
|
||||
|
||||
/// \brief Creates a `std::array` from names of fields of an \aggregate `T`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// std::array<std::string_view, 2> a = boost::pfr::names_as_array<my_struct>();
|
||||
/// assert(a[0] == "i");
|
||||
/// \endcode
|
||||
template <class T>
|
||||
constexpr
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
std::array<std::string_view, boost::pfr::tuple_size_v<T>>
|
||||
#else
|
||||
auto
|
||||
#endif
|
||||
names_as_array() noexcept {
|
||||
return detail::make_stdarray_from_tietuple(
|
||||
detail::tie_as_names_tuple<T>(),
|
||||
detail::make_index_sequence< tuple_size_v<T> >()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// Calls `func` for each field with its name of a `value`
|
||||
///
|
||||
/// \param func must have one of the following signatures:
|
||||
/// * any_return_type func(std::string_view name, U&& field) // field of value is perfect forwarded to function
|
||||
/// * any_return_type func(std::string_view name, U&& field, std::size_t i)
|
||||
/// * any_return_type func(std::string_view name, U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
|
||||
///
|
||||
/// \param value To each field of this variable will be the `func` applied.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct Toto { int a; char c; };
|
||||
/// Toto t {5, 'c'};
|
||||
/// auto print = [](std::string_view name, const auto& value){ std::cout << "Name: " << name << " Value: " << value << std::endl; };
|
||||
/// for_each_field_with_name(t, print);
|
||||
/// \endcode
|
||||
template <class T, class F>
|
||||
constexpr void for_each_field_with_name(T&& value, F&& func) {
|
||||
return boost::pfr::detail::for_each_field_with_name(std::forward<T>(value), std::forward<F>(func));
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_CORE_NAME_HPP
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP
|
||||
#define BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
constexpr void static_assert_layout_compatible() noexcept {
|
||||
static_assert(
|
||||
std::alignment_of<T>::value == std::alignment_of<U>::value,
|
||||
"====================> Boost.PFR: Alignment check failed, probably your structure has user-defined alignment for the whole structure or for some of the fields."
|
||||
);
|
||||
static_assert(sizeof(T) == sizeof(U), "====================> Boost.PFR: Size check failed, probably your structure has bitfields or user-defined alignment.");
|
||||
}
|
||||
|
||||
/// @cond
|
||||
#ifdef __GNUC__
|
||||
#define MAY_ALIAS __attribute__((__may_alias__))
|
||||
#else
|
||||
#define MAY_ALIAS
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
template <class To, class From>
|
||||
MAY_ALIAS const To& cast_to_layout_compatible(const From& val) noexcept {
|
||||
MAY_ALIAS const To* const t = reinterpret_cast<const To*>( std::addressof(val) );
|
||||
detail::static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
MAY_ALIAS const volatile To& cast_to_layout_compatible(const volatile From& val) noexcept {
|
||||
MAY_ALIAS const volatile To* const t = reinterpret_cast<const volatile To*>( std::addressof(val) );
|
||||
detail::static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
|
||||
|
||||
template <class To, class From>
|
||||
MAY_ALIAS volatile To& cast_to_layout_compatible(volatile From& val) noexcept {
|
||||
MAY_ALIAS volatile To* const t = reinterpret_cast<volatile To*>( std::addressof(val) );
|
||||
detail::static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
|
||||
|
||||
template <class To, class From>
|
||||
MAY_ALIAS To& cast_to_layout_compatible(From& val) noexcept {
|
||||
MAY_ALIAS To* const t = reinterpret_cast<To*>( std::addressof(val) );
|
||||
detail::static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING
|
||||
template <class To, class From>
|
||||
To&& cast_to_layout_compatible(rvalue_t<From> val) noexcept = delete;
|
||||
#endif
|
||||
|
||||
#undef MAY_ALIAS
|
||||
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -7,74 +8,19 @@
|
||||
#define BOOST_PFR_DETAIL_CONFIG_HPP
|
||||
#pragma once
|
||||
|
||||
#include <type_traits> // to get non standard platform macro definitions (__GLIBCXX__ for example)
|
||||
#include <boost/pfr/config.hpp>
|
||||
|
||||
// Reminder:
|
||||
// * MSVC++ 14.2 _MSC_VER == 1927 <- Loophole is known to work (Visual Studio ????)
|
||||
// * MSVC++ 14.1 _MSC_VER == 1916 <- Loophole is known to NOT work (Visual Studio 2017)
|
||||
// * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
|
||||
// * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
|
||||
#if !BOOST_PFR_ENABLED
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# if !defined(_MSVC_LANG) || _MSC_VER <= 1900
|
||||
# error Boost.PFR library requires more modern MSVC compiler.
|
||||
# endif
|
||||
#elif __cplusplus < 201402L
|
||||
# error Boost.PFR library requires at least C++14.
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_LOOPHOLE
|
||||
# if defined(_MSC_VER)
|
||||
# if _MSC_VER >= 1927
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# endif
|
||||
# elif defined(__clang_major__) && __clang_major__ >= 8
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_CPP17
|
||||
# ifdef __cpp_structured_bindings
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# elif defined(_MSVC_LANG)
|
||||
# if _MSVC_LANG >= 201703L
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# if !BOOST_PFR_USE_LOOPHOLE
|
||||
# error Boost.PFR requires /std:c++latest or /std:c++17 flags on your compiler.
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE
|
||||
// Assume that libstdc++ since GCC-7.3 does not have linear instantiation depth in std::make_integral_sequence
|
||||
# if defined( __GLIBCXX__) && __GLIBCXX__ >= 20180101
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
# elif defined(_MSC_VER)
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
//# elif other known working lib
|
||||
# else
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(maybe_unused)
|
||||
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_MAYBE_UNUSED
|
||||
# define BOOST_PFR_MAYBE_UNUSED
|
||||
#endif
|
||||
#error Boost.PFR library is not supported in your environment. \
|
||||
Try one of the possible solutions: \
|
||||
1. try to take away an '-DBOOST_PFR_ENABLED=0', if it exists \
|
||||
2. enable C++14; \
|
||||
3. enable C++17; \
|
||||
4. update your compiler; \
|
||||
or disable this error by '-DBOOST_PFR_ENABLED=1' if you really know what are you doing.
|
||||
|
||||
#endif // !BOOST_PFR_ENABLED
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CONFIG_HPP
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,7 +13,9 @@
|
||||
// `boost::pfr::detail::for_each_field_dispatcher` functions.
|
||||
//
|
||||
// The whole PFR library is build on top of those two functions.
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
#include <boost/pfr/detail/core26.hpp>
|
||||
#elif BOOST_PFR_USE_CPP17
|
||||
# include <boost/pfr/detail/core17.hpp>
|
||||
#elif BOOST_PFR_USE_LOOPHOLE
|
||||
# include <boost/pfr/detail/core14_loophole.hpp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,9 +9,6 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/offset_based_getter.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
@@ -21,6 +18,11 @@
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
@@ -53,7 +55,7 @@ namespace typeid_conversions {
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( push )
|
||||
// '<<': check operator precedence for possible error; use parentheses to clarify precedence
|
||||
# pragma warning( disable : 4554 )
|
||||
# pragma warning( disable : 4554 )
|
||||
#endif
|
||||
|
||||
constexpr std::size_t native_types_mask = 31;
|
||||
@@ -118,16 +120,16 @@ template <class Type> constexpr std::size_t type_to_id(identity<const Type*>) no
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type&>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>* = 0) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = 0) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>* = 0) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>* = nullptr) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = nullptr) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>* = nullptr) noexcept;
|
||||
template <class Type> constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value && !std::is_union<Type>::value>* = 0) noexcept;
|
||||
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = nullptr) noexcept;
|
||||
|
||||
|
||||
///////////////////// Definitions of type_to_id and id_to_type for fundamental types
|
||||
@@ -346,7 +348,7 @@ constexpr size_array<N> get_type_offsets() noexcept {
|
||||
return offsets;
|
||||
}
|
||||
|
||||
///////////////////// Returns array of typeids and zeros if construtor of a type accepts sizeof...(I) parameters
|
||||
///////////////////// Returns array of typeids and zeros if constructor of a type accepts sizeof...(I) parameters
|
||||
template <class T, std::size_t N, std::size_t... I>
|
||||
constexpr void* flat_type_to_array_of_type_ids(std::size_t* types, std::index_sequence<I...>) noexcept
|
||||
{
|
||||
@@ -549,6 +551,11 @@ constexpr bool is_flat_refelectable(std::index_sequence<I...>) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr bool is_flat_refelectable(std::index_sequence<>) noexcept {
|
||||
return true; ///< all empty structs always flat refelectable
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto tie_as_flat_tuple(T& lvalue) noexcept {
|
||||
static_assert(
|
||||
@@ -594,13 +601,20 @@ struct ubiq_constructor_constexpr_copy {
|
||||
/////////////////////
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
struct is_constexpr_aggregate_initializable { // TODO: try to fix it
|
||||
template <T = T{ ubiq_constructor_constexpr_copy{I}... } >
|
||||
struct is_constexpr_aggregate_initializable {
|
||||
template<class T2, std::size_t... I2>
|
||||
static constexpr void* constexpr_aggregate_initializer() noexcept {
|
||||
T2 tmp{ ubiq_constructor_constexpr_copy{I2}... };
|
||||
(void)tmp;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <void* = constexpr_aggregate_initializer<T, I...>() >
|
||||
static std::true_type test(long) noexcept;
|
||||
|
||||
static std::false_type test(...) noexcept;
|
||||
|
||||
static constexpr decltype( test(0) ) value{};
|
||||
static constexpr bool value = decltype(test(0)){};
|
||||
};
|
||||
|
||||
|
||||
@@ -671,16 +685,7 @@ void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
|
||||
/// Compile time error at this point means that you have called `for_each_field` or some other non-flat function or operator for a
|
||||
/// type that is not constexpr aggregate initializable.
|
||||
///
|
||||
/// Make sure that all the fields of your type have constexpr default construtors and trivial destructors.
|
||||
/// Or compile in C++17 mode.
|
||||
constexpr T tmp{ ubiq_constructor_constexpr_copy{I}... };
|
||||
(void)tmp;
|
||||
|
||||
//static_assert(is_constexpr_aggregate_initializable<T, I...>::value, "====================> Boost.PFR: T must be a constexpr initializable type");
|
||||
static_assert(is_constexpr_aggregate_initializable<T, I...>::value, "====================> Boost.PFR: T must be a constexpr initializable type");
|
||||
|
||||
constexpr bool is_flat_refelectable_val = detail::is_flat_refelectable<T>( std::index_sequence<I...>{} );
|
||||
detail::for_each_field_dispatcher_1(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2017-2018 Alexandr Poltavsky, Antony Polukhin.
|
||||
// Copyright (c) 2019-2020 Antony Polukhin.
|
||||
// Copyright (c) 2019-2025 Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
// The Great Type Loophole (C++14)
|
||||
// Initial implementation by Alexandr Poltavsky, http://alexpolt.github.io
|
||||
//
|
||||
// Description:
|
||||
// Description:
|
||||
// The Great Type Loophole is a technique that allows to exchange type information with template
|
||||
// instantiations. Basically you can assign and read type information during compile time.
|
||||
// Here it is used to detect data members of a data type. I described it for the first time in
|
||||
@@ -20,13 +20,10 @@
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/pfr/detail/cast_to_layout_compatible.hpp> // still needed for enums
|
||||
#include <boost/pfr/detail/offset_based_getter.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/make_flat_tuple_of_references.hpp>
|
||||
@@ -35,6 +32,9 @@
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
#include <boost/pfr/detail/unsafe_declval.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE17_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE17_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/core17_generated.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
@@ -22,7 +23,7 @@ struct do_not_define_std_tuple_size_for_me {
|
||||
template <class T>
|
||||
constexpr bool do_structured_bindings_work() noexcept { // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
|
||||
T val{};
|
||||
const auto& [a] = val; // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
|
||||
auto& [a] = val; // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
@@ -56,7 +57,7 @@ constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
}
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
constexpr void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
39
include/boost/pfr/detail/core26.hpp
Normal file
39
include/boost/pfr/detail/core26.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
// Copyright (c) 2025 Jean-Michaël Celerier
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// boost-no-inspect
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE26_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE26_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
namespace boost::pfr::detail {
|
||||
|
||||
template<class T>
|
||||
constexpr auto tie_as_tuple(T &val) noexcept {
|
||||
static_assert(!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect "
|
||||
"unions. See `Reflection of unions` section in the docs for more info.");
|
||||
auto &&[... members] = std::forward<T>(val);
|
||||
return sequence_tuple::tuple<std::add_lvalue_reference_t<decltype(members)>...>{members...};
|
||||
}
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
std::forward<F>(f)(
|
||||
detail::tie_as_tuple(t)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace boost::pfr::detail
|
||||
|
||||
#endif
|
||||
29
include/boost/pfr/detail/core_name.hpp
Normal file
29
include/boost/pfr/detail/core_name.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE_NAME_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE_NAME_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
// Each core_name provides `boost::pfr::detail::get_name` and
|
||||
// `boost::pfr::detail::tie_as_names_tuple` functions.
|
||||
//
|
||||
// The whole functional of extracting field's names is build on top of those
|
||||
// two functions.
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED
|
||||
#include <boost/pfr/detail/core_name20_static.hpp>
|
||||
#else
|
||||
#include <boost/pfr/detail/core_name14_disabled.hpp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME_HPP
|
||||
|
||||
52
include/boost/pfr/detail/core_name14_disabled.hpp
Normal file
52
include/boost/pfr/detail/core_name14_disabled.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, std::size_t I>
|
||||
constexpr auto get_name() noexcept {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"====================> Boost.PFR: Field's names extracting functionality requires C++20."
|
||||
);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_names_tuple() noexcept {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"====================> Boost.PFR: Field's names extracting functionality requires C++20."
|
||||
);
|
||||
|
||||
return detail::sequence_tuple::make_sequence_tuple();
|
||||
}
|
||||
|
||||
|
||||
template <class T, class F>
|
||||
constexpr void for_each_field_with_name(T&& /* value */, F&& /* func */) {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"====================> Boost.PFR: Field's names extracting functionality requires C++20."
|
||||
);
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||
|
||||
263
include/boost/pfr/detail/core_name20_static.hpp
Normal file
263
include/boost/pfr/detail/core_name20_static.hpp
Normal file
@@ -0,0 +1,263 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
#include <boost/pfr/detail/fake_object.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/for_each_field.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/stdarray.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <memory> // for std::addressof
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
struct core_name_skip {
|
||||
std::size_t size_at_begin;
|
||||
std::size_t size_at_end;
|
||||
bool is_backward;
|
||||
std::string_view until_runtime;
|
||||
|
||||
consteval std::string_view apply(std::string_view sv) const noexcept {
|
||||
// We use std::min here to make the compiler diagnostic shorter and
|
||||
// cleaner in case of misconfigured BOOST_PFR_CORE_NAME_PARSING
|
||||
sv.remove_prefix((std::min)(size_at_begin, sv.size()));
|
||||
sv.remove_suffix((std::min)(size_at_end, sv.size()));
|
||||
if (until_runtime.empty()) {
|
||||
return sv;
|
||||
}
|
||||
|
||||
const auto found = is_backward ? sv.rfind(until_runtime)
|
||||
: sv.find(until_runtime);
|
||||
|
||||
const auto cut_until = found + until_runtime.size();
|
||||
const auto safe_cut_until = (std::min)(cut_until, sv.size());
|
||||
return sv.substr(safe_cut_until);
|
||||
}
|
||||
};
|
||||
|
||||
struct backward {
|
||||
explicit consteval backward(std::string_view value) noexcept
|
||||
: value(value)
|
||||
{}
|
||||
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
|
||||
std::size_t size_at_end,
|
||||
std::string_view until_runtime) noexcept
|
||||
{
|
||||
return core_name_skip{size_at_begin, size_at_end, false, until_runtime};
|
||||
}
|
||||
|
||||
consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
|
||||
std::size_t size_at_end,
|
||||
backward until_runtime) noexcept
|
||||
{
|
||||
return core_name_skip{size_at_begin, size_at_end, true, until_runtime.value};
|
||||
}
|
||||
|
||||
// it might be compilation failed without this workaround sometimes
|
||||
// See https://github.com/llvm/llvm-project/issues/41751 for details
|
||||
template <class>
|
||||
consteval std::string_view clang_workaround(std::string_view value) noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class MsvcWorkaround, auto ptr>
|
||||
consteval auto name_of_field_impl() noexcept {
|
||||
// Some of the following compiler specific macro may be defined only
|
||||
// inside the function body:
|
||||
|
||||
#ifndef BOOST_PFR_FUNCTION_SIGNATURE
|
||||
# if defined(__FUNCSIG__)
|
||||
# define BOOST_PFR_FUNCTION_SIGNATURE __FUNCSIG__
|
||||
# elif defined(__PRETTY_FUNCTION__) || defined(__GNUC__) || defined(__clang__)
|
||||
# define BOOST_PFR_FUNCTION_SIGNATURE __PRETTY_FUNCTION__
|
||||
# else
|
||||
# define BOOST_PFR_FUNCTION_SIGNATURE ""
|
||||
# endif
|
||||
#endif
|
||||
|
||||
constexpr std::string_view sv = detail::clang_workaround<MsvcWorkaround>(BOOST_PFR_FUNCTION_SIGNATURE);
|
||||
static_assert(!sv.empty(),
|
||||
"====================> Boost.PFR: Field reflection parser configured in a wrong way. "
|
||||
"Please define the BOOST_PFR_FUNCTION_SIGNATURE to a compiler specific macro, "
|
||||
"that outputs the whole function signature including non-type template parameters."
|
||||
);
|
||||
|
||||
constexpr auto skip = detail::make_core_name_skip BOOST_PFR_CORE_NAME_PARSING;
|
||||
static_assert(skip.size_at_begin + skip.size_at_end + skip.until_runtime.size() < sv.size(),
|
||||
"====================> Boost.PFR: Field reflection parser configured in a wrong way. "
|
||||
"It attempts to skip more chars than available. "
|
||||
"Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
|
||||
"'Limitations and Configuration' for more information."
|
||||
);
|
||||
constexpr auto fn = skip.apply(sv);
|
||||
static_assert(
|
||||
!fn.empty(),
|
||||
"====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. "
|
||||
"It skipped all the input, leaving the field name empty. "
|
||||
"Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
|
||||
"'Limitations and Configuration' for more information."
|
||||
);
|
||||
auto res = std::array<char, fn.size()+1>{};
|
||||
|
||||
auto* out = res.data();
|
||||
for (auto x: fn) {
|
||||
*out = x;
|
||||
++out;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundefined-var-template"
|
||||
|
||||
// clang 16 and earlier don't support address of non-static member as template parameter
|
||||
// but fortunately it's possible to use C++20 non-type template parameters in another way
|
||||
// even in clang 16 and more older clangs
|
||||
// all we need is to wrap pointer into 'clang_wrapper_t' and then pass it into template
|
||||
template <class T>
|
||||
struct clang_wrapper_t {
|
||||
T v;
|
||||
};
|
||||
template <class T>
|
||||
clang_wrapper_t(T) -> clang_wrapper_t<T>;
|
||||
|
||||
template <class T>
|
||||
constexpr auto make_clang_wrapper(const T& arg) noexcept {
|
||||
return clang_wrapper_t{arg};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
constexpr const T& make_clang_wrapper(const T& arg) noexcept {
|
||||
// It's everything OK with address of non-static member as template parameter support on this compiler
|
||||
// so we don't need a wrapper here, just pass the pointer into template
|
||||
return arg;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <class MsvcWorkaround, auto ptr>
|
||||
consteval auto name_of_field() noexcept {
|
||||
// Sanity check: known field name must match the deduced one
|
||||
static_assert(
|
||||
sizeof(MsvcWorkaround) // do not trigger if `name_of_field()` is not used
|
||||
&& std::string_view{
|
||||
detail::name_of_field_impl<
|
||||
core_name_skip, detail::make_clang_wrapper(std::addressof(
|
||||
detail::fake_object<core_name_skip>().size_at_begin
|
||||
))
|
||||
>().data()
|
||||
} == "size_at_begin",
|
||||
"====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. "
|
||||
"It does not return the proper field name. "
|
||||
"Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
|
||||
"'Limitations and Configuration' for more information."
|
||||
);
|
||||
|
||||
return detail::name_of_field_impl<MsvcWorkaround, ptr>();
|
||||
}
|
||||
|
||||
// Storing part of a string literal into an array minimizes the binary size.
|
||||
//
|
||||
// Without passing 'T' into 'name_of_field' different fields from different structures might have the same name!
|
||||
// See https://developercommunity.visualstudio.com/t/__FUNCSIG__-outputs-wrong-value-with-C/10458554 for details
|
||||
template <class T, std::size_t I>
|
||||
inline constexpr auto stored_name_of_field = detail::name_of_field<T,
|
||||
detail::make_clang_wrapper(std::addressof(detail::sequence_tuple::get<I>(
|
||||
detail::tie_as_tuple(detail::fake_object<T>())
|
||||
)))
|
||||
>();
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto tie_as_names_tuple_impl(std::index_sequence<I...>) noexcept {
|
||||
return detail::sequence_tuple::make_sequence_tuple(std::string_view{stored_name_of_field<T, I>.data()}...);
|
||||
}
|
||||
|
||||
template <class T, std::size_t I>
|
||||
constexpr std::string_view get_name() noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
static_assert(
|
||||
!std::is_array<T>::value,
|
||||
"====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members"
|
||||
);
|
||||
static_assert(
|
||||
sizeof(T) && (BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_CPP26),
|
||||
"====================> Boost.PFR: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 or the BOOST_PFR_USE_CPP26 macro enabled."
|
||||
);
|
||||
|
||||
return stored_name_of_field<T, I>.data();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_names_tuple() noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
static_assert(
|
||||
!std::is_array<T>::value,
|
||||
"====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members"
|
||||
);
|
||||
static_assert(
|
||||
sizeof(T) && BOOST_PFR_USE_CPP17,
|
||||
"====================> Boost.PFR: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 macro enabled."
|
||||
);
|
||||
|
||||
return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
|
||||
}
|
||||
|
||||
template <class T, class F>
|
||||
constexpr void for_each_field_with_name(T&& value, F&& func) {
|
||||
return boost::pfr::detail::for_each_field(
|
||||
std::forward<T>(value),
|
||||
[f = std::forward<F>(func)](auto&& field, auto index) mutable {
|
||||
using IndexType = decltype(index);
|
||||
using FieldType = decltype(field);
|
||||
constexpr auto name = boost::pfr::detail::get_name<std::remove_reference_t<T>, IndexType::value>();
|
||||
if constexpr (std::is_invocable_v<F, std::string_view, FieldType, IndexType>) {
|
||||
f(name, std::forward<FieldType>(field), index);
|
||||
} else {
|
||||
f(name, std::forward<FieldType>(field));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,15 +9,17 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
|
||||
struct can_not_apply{};
|
||||
|
||||
template <template <class, class> class Detector, class Tleft, class Tright>
|
||||
struct not_appliable {
|
||||
struct not_applicable {
|
||||
static constexpr bool value = std::is_same<
|
||||
Detector<Tleft, Tright>,
|
||||
can_not_apply
|
||||
|
||||
54
include/boost/pfr/detail/fake_object.hpp
Normal file
54
include/boost/pfr/detail/fake_object.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
// Copyright (c) 2024-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
#define BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wundefined-internal"
|
||||
# pragma clang diagnostic ignored "-Wundefined-var-template"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
// This class has external linkage while T has not sure.
|
||||
template <class T>
|
||||
struct wrapper {
|
||||
const T value;
|
||||
};
|
||||
|
||||
// This variable servers as a link-time assert.
|
||||
// If linker requires it, then `fake_object()` is used at runtime.
|
||||
template <class T>
|
||||
extern const wrapper<T> do_not_use_PFR_with_local_types;
|
||||
|
||||
// For returning non default constructible types, it's exclusively used in member name retrieval.
|
||||
//
|
||||
// Neither std::declval nor boost::pfr::detail::unsafe_declval are usable there.
|
||||
// This takes advantage of C++20 features, while boost::pfr::detail::unsafe_declval works
|
||||
// with the former standards.
|
||||
template <class T>
|
||||
constexpr const T& fake_object() noexcept {
|
||||
return do_not_use_PFR_with_local_types<T>.value;
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -12,9 +12,11 @@
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
#include <boost/pfr/detail/unsafe_declval.hpp>
|
||||
|
||||
#include <climits> // CHAR_BIT
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
@@ -26,26 +28,39 @@
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// min without including <algorithm>
|
||||
constexpr std::size_t min_of_size_t(std::size_t a, std::size_t b) noexcept {
|
||||
return b < a ? b : a;
|
||||
}
|
||||
|
||||
///////////////////// Structure that can be converted to reference to anything
|
||||
struct ubiq_lref_constructor {
|
||||
std::size_t ignore;
|
||||
template <class Type> constexpr operator Type&() const && noexcept { // tweak for template_unconstrained.cpp like cases
|
||||
return detail::unsafe_declval<Type&>();
|
||||
};
|
||||
}
|
||||
|
||||
template <class Type> constexpr operator Type&() const & noexcept { // tweak for optional_chrono.cpp like cases
|
||||
return detail::unsafe_declval<Type&>();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////// Structure that can be converted to rvalue reference to anything
|
||||
struct ubiq_rref_constructor {
|
||||
std::size_t ignore;
|
||||
template <class Type> /*constexpr*/ operator Type&&() const && noexcept { // Allows initialization of rvalue reference fields and move-only types
|
||||
return detail::unsafe_declval<Type&&>();
|
||||
};
|
||||
template <class Type> /*constexpr*/ operator Type() const && noexcept { // Allows initialization of rvalue reference fields and move-only types
|
||||
return detail::unsafe_declval<Type>();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////// Hand-made is_complete<T> trait
|
||||
template <typename T, typename = void>
|
||||
struct is_complete : std::false_type
|
||||
{};
|
||||
|
||||
template <typename T>
|
||||
struct is_complete<T, decltype(void(sizeof(T)))> : std::integral_constant<bool, true>
|
||||
{};
|
||||
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
///////////////////// Hand-made is_aggregate_initializable_n<T> trait
|
||||
@@ -74,8 +89,16 @@ template <class T> struct is_single_field_and_aggregate_initializable<1, T>: std
|
||||
// Before C++20 aggregates could be constructed from `decltype(ubiq_?ref_constructor{I})...` but type traits report that
|
||||
// there's no constructor from `decltype(ubiq_?ref_constructor{I})...`
|
||||
// Special case for N == 1: `std::is_constructible<T, ubiq_?ref_constructor>` returns true if N == 1 and T is copy/move constructible.
|
||||
template <class T, std::size_t N>
|
||||
template <class T, std::size_t N, class /*Enable*/ = void>
|
||||
struct is_aggregate_initializable_n {
|
||||
static constexpr bool value =
|
||||
std::is_empty<T>::value
|
||||
|| std::is_array<T>::value
|
||||
;
|
||||
};
|
||||
|
||||
template <class T, std::size_t N>
|
||||
struct is_aggregate_initializable_n<T, N, std::enable_if_t<std::is_class<T>::value && !std::is_empty<T>::value>> {
|
||||
template <std::size_t ...I>
|
||||
static constexpr bool is_not_constructible_n(std::index_sequence<I...>) noexcept {
|
||||
return (!std::is_constructible<T, decltype(ubiq_lref_constructor{I})...>::value && !std::is_constructible<T, decltype(ubiq_rref_constructor{I})...>::value)
|
||||
@@ -83,27 +106,99 @@ struct is_aggregate_initializable_n {
|
||||
;
|
||||
}
|
||||
|
||||
static constexpr bool value =
|
||||
std::is_empty<T>::value
|
||||
|| std::is_array<T>::value
|
||||
|| std::is_fundamental<T>::value
|
||||
|| is_not_constructible_n(detail::make_index_sequence<N>{})
|
||||
;
|
||||
static constexpr bool value = is_not_constructible_n(detail::make_index_sequence<N>{});
|
||||
};
|
||||
|
||||
#endif // #ifndef __cpp_lib_is_aggregate
|
||||
|
||||
///////////////////// Helper for SFINAE on fields count
|
||||
template <class T, std::size_t... I, class /*Enable*/ = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
|
||||
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_lref_constructor{I}... })>::type;
|
||||
///////////////////// Detect aggregates with inheritance
|
||||
template <class Derived, class U>
|
||||
constexpr bool static_assert_non_inherited() noexcept {
|
||||
static_assert(
|
||||
!std::is_base_of<U, Derived>::value,
|
||||
"====================> Boost.PFR: Boost.PFR: Inherited types are not supported."
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, std::size_t... I, class /*Enable*/ = typename std::enable_if<!std::is_copy_constructible<T>::value>::type>
|
||||
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_rref_constructor{I}... })>::type;
|
||||
template <class Derived>
|
||||
struct ubiq_lref_base_asserting {
|
||||
template <class Type> constexpr operator Type&() const && // tweak for template_unconstrained.cpp like cases
|
||||
noexcept(detail::static_assert_non_inherited<Derived, Type>()) // force the computation of assert function
|
||||
{
|
||||
return detail::unsafe_declval<Type&>();
|
||||
}
|
||||
|
||||
template <class T, std::size_t N, class /*Enable*/ = decltype( enable_if_constructible_helper<T>(detail::make_index_sequence<N>()) ) >
|
||||
using enable_if_constructible_helper_t = std::size_t;
|
||||
template <class Type> constexpr operator Type&() const & // tweak for optional_chrono.cpp like cases
|
||||
noexcept(detail::static_assert_non_inherited<Derived, Type>()) // force the computation of assert function
|
||||
{
|
||||
return detail::unsafe_declval<Type&>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
struct ubiq_rref_base_asserting {
|
||||
template <class Type> /*constexpr*/ operator Type() const && // Allows initialization of rvalue reference fields and move-only types
|
||||
noexcept(detail::static_assert_non_inherited<Derived, Type>()) // force the computation of assert function
|
||||
{
|
||||
return detail::unsafe_declval<Type>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, std::size_t I0, std::size_t... I, class /*Enable*/ = std::enable_if_t<std::is_copy_constructible<T>::value>>
|
||||
constexpr auto assert_first_not_base(std::index_sequence<I0, I...>) noexcept
|
||||
-> std::add_pointer_t<decltype(T{ ubiq_lref_base_asserting<T>{}, ubiq_lref_constructor{I}... })>
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T, std::size_t I0, std::size_t... I, class /*Enable*/ = std::enable_if_t<!std::is_copy_constructible<T>::value>>
|
||||
constexpr auto assert_first_not_base(std::index_sequence<I0, I...>) noexcept
|
||||
-> std::add_pointer_t<decltype(T{ ubiq_rref_base_asserting<T>{}, ubiq_rref_constructor{I}... })>
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void* assert_first_not_base(std::index_sequence<>) noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr void assert_first_not_base(int) noexcept {}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr auto assert_first_not_base(long) noexcept
|
||||
-> std::enable_if_t<std::is_class<T>::value>
|
||||
{
|
||||
detail::assert_first_not_base<T>(detail::make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
///////////////////// Helpers for initializable detection
|
||||
// Note that these take O(N) compile time and memory!
|
||||
template <class T, std::size_t... I, class /*Enable*/ = std::enable_if_t<std::is_copy_constructible<T>::value>>
|
||||
constexpr auto enable_if_initializable_helper(std::index_sequence<I...>) noexcept
|
||||
-> std::add_pointer_t<decltype(T{ubiq_lref_constructor{I}...})>;
|
||||
|
||||
template <class T, std::size_t... I, class /*Enable*/ = std::enable_if_t<!std::is_copy_constructible<T>::value>>
|
||||
constexpr auto enable_if_initializable_helper(std::index_sequence<I...>) noexcept
|
||||
-> std::add_pointer_t<decltype(T{ubiq_rref_constructor{I}...})>;
|
||||
|
||||
template <class T, std::size_t N, class U = std::size_t, class /*Enable*/ = decltype(detail::enable_if_initializable_helper<T>(detail::make_index_sequence<N>()))>
|
||||
using enable_if_initializable_helper_t = U;
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr auto is_initializable(long) noexcept
|
||||
-> detail::enable_if_initializable_helper_t<T, N, bool>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr bool is_initializable(int) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////// Helpers for range size detection
|
||||
template <std::size_t Begin, std::size_t Last>
|
||||
@@ -112,123 +207,235 @@ using is_one_element_range = std::integral_constant<bool, Begin == Last>;
|
||||
using multi_element_range = std::false_type;
|
||||
using one_element_range = std::true_type;
|
||||
|
||||
///////////////////// Non greedy fields count search. Templates instantiation depth is log(sizeof(T)), templates instantiation count is log(sizeof(T)).
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr std::size_t detect_fields_count(detail::one_element_range, long) noexcept {
|
||||
#if !BOOST_PFR_USE_CPP26
|
||||
///////////////////// Fields count next expected compiler limitation
|
||||
constexpr std::size_t fields_count_compiler_limitation_next(std::size_t n) noexcept {
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= 1920)
|
||||
if (n < 1024)
|
||||
return 1024;
|
||||
#else
|
||||
static_cast<void>(n);
|
||||
#endif
|
||||
return (std::numeric_limits<std::size_t>::max)();
|
||||
}
|
||||
|
||||
///////////////////// Fields count upper bound based on sizeof(T)
|
||||
template <class T>
|
||||
constexpr std::size_t fields_count_upper_bound_loose() noexcept {
|
||||
return sizeof(T) * std::numeric_limits<unsigned char>::digits + 1 /* +1 for "Arrays of Length Zero" extension */;
|
||||
}
|
||||
|
||||
///////////////////// Fields count binary search.
|
||||
// Template instantiation: depth is O(log(result)), count is O(log(result)), cost is O(result * log(result)).
|
||||
template <class T, std::size_t Begin, std::size_t Last>
|
||||
constexpr std::size_t fields_count_binary_search(detail::one_element_range, long) noexcept {
|
||||
static_assert(
|
||||
Begin == Middle,
|
||||
Begin == Last,
|
||||
"====================> Boost.PFR: Internal logic error."
|
||||
);
|
||||
return Begin;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept;
|
||||
template <class T, std::size_t Begin, std::size_t Last>
|
||||
constexpr std::size_t fields_count_binary_search(detail::multi_element_range, int) noexcept;
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr auto detect_fields_count(detail::multi_element_range, long) noexcept
|
||||
-> detail::enable_if_constructible_helper_t<T, Middle>
|
||||
template <class T, std::size_t Begin, std::size_t Last>
|
||||
constexpr auto fields_count_binary_search(detail::multi_element_range, long) noexcept
|
||||
-> detail::enable_if_initializable_helper_t<T, (Begin + Last + 1) / 2>
|
||||
{
|
||||
constexpr std::size_t next_v = Middle + (Middle - Begin + 1) / 2;
|
||||
return detail::detect_fields_count<T, Middle, next_v>(detail::is_one_element_range<Middle, next_v>{}, 1L);
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept {
|
||||
constexpr std::size_t next_v = Begin + (Middle - Begin) / 2;
|
||||
return detail::detect_fields_count<T, Begin, next_v>(detail::is_one_element_range<Begin, next_v>{}, 1L);
|
||||
}
|
||||
|
||||
///////////////////// Greedy search. Templates instantiation depth is log(sizeof(T)), templates instantiation count is log(sizeof(T))*T in worst case.
|
||||
template <class T, std::size_t N>
|
||||
constexpr auto detect_fields_count_greedy_remember(long) noexcept
|
||||
-> detail::enable_if_constructible_helper_t<T, N>
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::size_t detect_fields_count_greedy_remember(int) noexcept {
|
||||
return 0;
|
||||
constexpr std::size_t next_v = (Begin + Last + 1) / 2;
|
||||
return detail::fields_count_binary_search<T, next_v, Last>(detail::is_one_element_range<next_v, Last>{}, 1L);
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Last>
|
||||
constexpr std::size_t detect_fields_count_greedy(detail::one_element_range) noexcept {
|
||||
constexpr std::size_t fields_count_binary_search(detail::multi_element_range, int) noexcept {
|
||||
constexpr std::size_t next_v = (Begin + Last + 1) / 2 - 1;
|
||||
return detail::fields_count_binary_search<T, Begin, next_v>(detail::is_one_element_range<Begin, next_v>{}, 1L);
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t N>
|
||||
constexpr std::size_t fields_count_upper_bound(int, int) noexcept {
|
||||
return N - 1;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t N>
|
||||
constexpr auto fields_count_upper_bound(long, long) noexcept
|
||||
-> std::enable_if_t<(N > detail::fields_count_upper_bound_loose<T>()), std::size_t>
|
||||
{
|
||||
static_assert(
|
||||
!detail::is_initializable<T, detail::fields_count_upper_bound_loose<T>() + 1>(1L),
|
||||
"====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported.");
|
||||
return detail::fields_count_upper_bound_loose<T>();
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t N>
|
||||
constexpr auto fields_count_upper_bound(long, int) noexcept
|
||||
-> detail::enable_if_initializable_helper_t<T, N>
|
||||
{
|
||||
constexpr std::size_t next_optimal = Begin + (N - Begin) * 2;
|
||||
constexpr std::size_t next = detail::min_of_size_t(next_optimal, detail::fields_count_compiler_limitation_next(N));
|
||||
return detail::fields_count_upper_bound<T, Begin, next>(1L, 1L);
|
||||
}
|
||||
|
||||
///////////////////// Fields count lower bound linear search.
|
||||
// Template instantiation: depth is O(log(result)), count is O(result), cost is O(result^2).
|
||||
template <class T, std::size_t Begin, std::size_t Last, class RangeSize, std::size_t Result>
|
||||
constexpr std::size_t fields_count_lower_bound(RangeSize, size_t_<Result>) noexcept {
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Last>
|
||||
constexpr std::size_t fields_count_lower_bound(detail::one_element_range, size_t_<0> = {}) noexcept {
|
||||
static_assert(
|
||||
Begin == Last,
|
||||
"====================> Boost.PFR: Internal logic error."
|
||||
);
|
||||
return detail::detect_fields_count_greedy_remember<T, Begin>(1L);
|
||||
return detail::is_initializable<T, Begin>(1L) ? Begin : 0;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Last>
|
||||
constexpr std::size_t detect_fields_count_greedy(detail::multi_element_range) noexcept {
|
||||
constexpr std::size_t fields_count_lower_bound(detail::multi_element_range, size_t_<0> = {}) noexcept {
|
||||
// Binary partition to limit template depth.
|
||||
constexpr std::size_t middle = Begin + (Last - Begin) / 2;
|
||||
constexpr std::size_t fields_count_big_range = detail::detect_fields_count_greedy<T, middle + 1, Last>(
|
||||
detail::is_one_element_range<middle + 1, Last>{}
|
||||
constexpr std::size_t result_maybe = detail::fields_count_lower_bound<T, Begin, middle>(
|
||||
detail::is_one_element_range<Begin, middle>{}
|
||||
);
|
||||
|
||||
constexpr std::size_t small_range_begin = (fields_count_big_range ? 0 : Begin);
|
||||
constexpr std::size_t small_range_last = (fields_count_big_range ? 0 : middle);
|
||||
constexpr std::size_t fields_count_small_range = detail::detect_fields_count_greedy<T, small_range_begin, small_range_last>(
|
||||
detail::is_one_element_range<small_range_begin, small_range_last>{}
|
||||
return detail::fields_count_lower_bound<T, middle + 1, Last>(
|
||||
detail::is_one_element_range<middle + 1, Last>{},
|
||||
size_t_<result_maybe>{}
|
||||
);
|
||||
return fields_count_big_range ? fields_count_big_range : fields_count_small_range;
|
||||
}
|
||||
|
||||
///////////////////// Choosing between array size, greedy and non greedy search.
|
||||
template <class T, std::size_t N>
|
||||
constexpr auto detect_fields_count_dispatch(size_t_<N>, long, long) noexcept
|
||||
-> typename std::enable_if<std::is_array<T>::value, std::size_t>::type
|
||||
template <class T, std::size_t Begin, std::size_t Result>
|
||||
constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_<Result>) noexcept {
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin>
|
||||
constexpr auto fields_count_lower_bound_unbounded(long, size_t_<0>) noexcept
|
||||
-> std::enable_if_t<(Begin >= detail::fields_count_upper_bound_loose<T>()), std::size_t>
|
||||
{
|
||||
return sizeof(T) / sizeof(typename std::remove_all_extents<T>::type);
|
||||
static_assert(
|
||||
detail::is_initializable<T, detail::fields_count_upper_bound_loose<T>()>(1L),
|
||||
"====================> Boost.PFR: Type must be aggregate initializable.");
|
||||
return detail::fields_count_upper_bound_loose<T>();
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr auto detect_fields_count_dispatch(size_t_<N>, long, int) noexcept
|
||||
template <class T, std::size_t Begin>
|
||||
constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_<0>) noexcept {
|
||||
constexpr std::size_t last = detail::min_of_size_t(Begin * 2, detail::fields_count_upper_bound_loose<T>()) - 1;
|
||||
constexpr std::size_t result_maybe = detail::fields_count_lower_bound<T, Begin, last>(
|
||||
detail::is_one_element_range<Begin, last>{}
|
||||
);
|
||||
return detail::fields_count_lower_bound_unbounded<T, last + 1>(1L, size_t_<result_maybe>{});
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////// Choosing between array size, unbounded binary search, and linear search followed by unbounded binary search.
|
||||
template <class T>
|
||||
constexpr auto fields_count_dispatch(long, long, std::false_type /*are_preconditions_met*/) noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto fields_count_dispatch(long, long, std::true_type /*are_preconditions_met*/) noexcept
|
||||
-> std::enable_if_t<std::is_array<T>::value, std::size_t>
|
||||
{
|
||||
return sizeof(T) / sizeof(std::remove_all_extents_t<T>);
|
||||
}
|
||||
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
template<class T>
|
||||
constexpr auto fields_count_dispatch_impl(const T &t) noexcept
|
||||
{
|
||||
const auto &[... elts] = t;
|
||||
return std::integral_constant<std::size_t, sizeof...(elts)>{};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr auto fields_count_dispatch(long, int, std::true_type /*are_preconditions_met*/) noexcept
|
||||
-> std::enable_if_t<std::is_scalar<T>::value, std::size_t>
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr auto fields_count_dispatch(int, int, std::true_type /*are_preconditions_met*/) noexcept
|
||||
{
|
||||
return decltype(detail::fields_count_dispatch_impl(std::declval<const T &>()))::value;
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
constexpr auto fields_count_dispatch(long, int, std::true_type /*are_preconditions_met*/) noexcept
|
||||
-> decltype(sizeof(T{}))
|
||||
{
|
||||
constexpr std::size_t middle = N / 2 + 1;
|
||||
return detail::detect_fields_count<T, 0, middle>(detail::multi_element_range{}, 1L);
|
||||
constexpr std::size_t typical_fields_count = 4;
|
||||
constexpr std::size_t last = detail::fields_count_upper_bound<T, typical_fields_count / 2, typical_fields_count>(1L, 1L);
|
||||
return detail::fields_count_binary_search<T, 0, last>(detail::is_one_element_range<0, last>{}, 1L);
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::size_t detect_fields_count_dispatch(size_t_<N>, int, int) noexcept {
|
||||
// T is not default aggregate initialzable. It means that at least one of the members is not default constructible,
|
||||
// so we have to check all the aggregate initializations for T up to N parameters and return the bigest succeeded
|
||||
// (we can not use binary search for detecting fields count).
|
||||
return detail::detect_fields_count_greedy<T, 0, N>(detail::multi_element_range{});
|
||||
template <class T>
|
||||
constexpr std::size_t fields_count_dispatch(int, int, std::true_type /*are_preconditions_met*/) noexcept {
|
||||
// T is not default aggregate initializable. This means that at least one of the members is not default-constructible.
|
||||
// Use linear search to find the smallest valid initializer, after which we unbounded binary search for the largest.
|
||||
constexpr std::size_t begin = detail::fields_count_lower_bound_unbounded<T, 1>(1L, size_t_<0>{});
|
||||
|
||||
constexpr std::size_t last = detail::fields_count_upper_bound<T, begin, begin + 1>(1L, 1L);
|
||||
return detail::fields_count_binary_search<T, begin, last>(detail::is_one_element_range<begin, last>{}, 1L);
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////// Returns fields count
|
||||
template <class T>
|
||||
constexpr std::size_t fields_count() noexcept {
|
||||
using type = std::remove_cv_t<T>;
|
||||
|
||||
constexpr bool type_is_complete = detail::is_complete<type>::value;
|
||||
static_assert(
|
||||
!std::is_reference<type>::value,
|
||||
type_is_complete,
|
||||
"====================> Boost.PFR: Type must be complete."
|
||||
);
|
||||
|
||||
constexpr bool type_is_not_a_reference = !std::is_reference<type>::value
|
||||
|| !type_is_complete // do not show assert if previous check failed
|
||||
;
|
||||
static_assert(
|
||||
type_is_not_a_reference,
|
||||
"====================> Boost.PFR: Attempt to get fields count on a reference. This is not allowed because that could hide an issue and different library users expect different behavior in that case."
|
||||
);
|
||||
|
||||
static_assert(
|
||||
#if BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
constexpr bool type_fields_are_move_constructible = true;
|
||||
#else
|
||||
constexpr bool type_fields_are_move_constructible =
|
||||
std::is_copy_constructible<std::remove_all_extents_t<type>>::value || (
|
||||
std::is_move_constructible<std::remove_all_extents_t<type>>::value
|
||||
&& std::is_move_assignable<std::remove_all_extents_t<type>>::value
|
||||
),
|
||||
)
|
||||
|| !type_is_not_a_reference // do not show assert if previous check failed
|
||||
;
|
||||
static_assert(
|
||||
type_fields_are_move_constructible,
|
||||
"====================> Boost.PFR: Type and each field in the type must be copy constructible (or move constructible and move assignable)."
|
||||
);
|
||||
#endif // #if !BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
|
||||
constexpr bool type_is_not_polymorphic = !std::is_polymorphic<type>::value;
|
||||
static_assert(
|
||||
!std::is_polymorphic<type>::value,
|
||||
type_is_not_polymorphic,
|
||||
"====================> Boost.PFR: Type must have no virtual function, because otherwise it is not aggregate initializable."
|
||||
);
|
||||
|
||||
#ifdef __cpp_lib_is_aggregate
|
||||
static_assert(
|
||||
constexpr bool type_is_aggregate =
|
||||
std::is_aggregate<type>::value // Does not return `true` for built-in types.
|
||||
|| std::is_scalar<type>::value,
|
||||
|| std::is_scalar<type>::value;
|
||||
static_assert(
|
||||
type_is_aggregate,
|
||||
"====================> Boost.PFR: Type must be aggregate initializable."
|
||||
);
|
||||
#else
|
||||
constexpr bool type_is_aggregate = true;
|
||||
#endif
|
||||
|
||||
// Can't use the following. See the non_std_layout.cpp test.
|
||||
@@ -239,18 +446,27 @@ constexpr std::size_t fields_count() noexcept {
|
||||
// );
|
||||
//#endif
|
||||
|
||||
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT); // We multiply by CHAR_BIT because the type may have bitfields in T
|
||||
constexpr std::size_t result = detail::detect_fields_count_dispatch<type>(size_t_<max_fields_count>{}, 1L, 1L);
|
||||
constexpr bool no_errors =
|
||||
type_is_complete && type_is_not_a_reference && type_fields_are_move_constructible
|
||||
&& type_is_not_polymorphic && type_is_aggregate;
|
||||
constexpr std::size_t result
|
||||
= detail::fields_count_dispatch<type>(1L, 1L, std::integral_constant<bool, no_errors>{});
|
||||
detail::assert_first_not_base<type, result>(1L);
|
||||
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
constexpr bool type_is_aggregate_initializable_n =
|
||||
detail::is_aggregate_initializable_n<type, result>::value // Does not return `true` for built-in types.
|
||||
|| std::is_scalar<type>::value;
|
||||
static_assert(
|
||||
is_aggregate_initializable_n<type, result>::value,
|
||||
type_is_aggregate_initializable_n,
|
||||
"====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported."
|
||||
);
|
||||
#else
|
||||
constexpr bool type_is_aggregate_initializable_n = true;
|
||||
#endif
|
||||
|
||||
static_assert(
|
||||
result != 0 || std::is_empty<type>::value || std::is_fundamental<type>::value || std::is_reference<type>::value,
|
||||
result != 0 || std::is_empty<type>::value || std::is_fundamental<type>::value || std::is_reference<type>::value || !no_errors || !type_is_aggregate_initializable_n,
|
||||
"====================> Boost.PFR: If there's no other failed static asserts then something went wrong. Please report this issue to the github along with the structure you're reflecting."
|
||||
);
|
||||
|
||||
|
||||
65
include/boost/pfr/detail/for_each_field.hpp
Normal file
65
include/boost/pfr/detail/for_each_field.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_FOR_EACH_FIELD_HPP
|
||||
#define BOOST_PFR_DETAIL_FOR_EACH_FIELD_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/for_each_field_impl.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits> // metaprogramming stuff
|
||||
#include <utility> // forward_like
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, class F>
|
||||
constexpr void for_each_field(T&& value, F&& func) {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
using no_ref = std::remove_reference_t<T>;
|
||||
if constexpr (std::is_aggregate_v<no_ref> || std::is_bounded_array_v<no_ref>) {
|
||||
auto &&[... members] = value;
|
||||
::boost::pfr::detail::for_each_field_impl(value,
|
||||
std::forward<F>(func),
|
||||
std::make_index_sequence<sizeof...(members)>{},
|
||||
std::is_rvalue_reference<T &&>{});
|
||||
} else {
|
||||
::boost::pfr::detail::for_each_field_impl(value,
|
||||
std::forward<F>(func),
|
||||
std::make_index_sequence<1>{},
|
||||
std::is_rvalue_reference<T &&>{});
|
||||
}
|
||||
#else
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
value,
|
||||
[f = std::forward<F>(func)](auto&& t) mutable {
|
||||
// MSVC related workaround. Its lambdas do not capture constexprs.
|
||||
constexpr std::size_t fields_count_val_in_lambda
|
||||
= boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
|
||||
::boost::pfr::detail::for_each_field_impl(
|
||||
t,
|
||||
std::forward<F>(f),
|
||||
detail::make_index_sequence<fields_count_val_in_lambda>{},
|
||||
std::is_rvalue_reference<T&&>{}
|
||||
);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_val>{}
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_FOR_EACH_FIELD_HPP
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,29 +9,55 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <utility> // metaprogramming stuff
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
template <class T, class F, class I, class = decltype(std::declval<F>()(std::declval<T>(), I{}))>
|
||||
void for_each_field_impl_apply(T&& v, F&& f, I i, long) {
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I i, long) {
|
||||
std::forward<F>(f)(std::forward<T>(v), i);
|
||||
}
|
||||
|
||||
template <class T, class F, class I>
|
||||
void for_each_field_impl_apply(T&& v, F&& f, I /*i*/, int) {
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I /*i*/, int) {
|
||||
std::forward<F>(f)(std::forward<T>(v));
|
||||
}
|
||||
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
template<class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, auto move_values) {
|
||||
if constexpr (std::is_aggregate_v<T> || std::is_bounded_array_v<T>) {
|
||||
auto &&[... members] = t;
|
||||
if constexpr (move_values)
|
||||
(detail::for_each_field_impl_apply(std::move(members...[I]),
|
||||
std::forward<F>(f),
|
||||
size_t_<I>{},
|
||||
1L),
|
||||
...);
|
||||
else
|
||||
(detail::for_each_field_impl_apply(
|
||||
members... [I], std::forward<F>(f), size_t_<I> {}, 1L),
|
||||
...);
|
||||
} else {
|
||||
if constexpr (move_values)
|
||||
(detail::for_each_field_impl_apply(std::move(t), std::forward<F>(f), size_t_<I>{}, 1L),
|
||||
...);
|
||||
else
|
||||
(detail::for_each_field_impl_apply(t, std::forward<F>(f), size_t_<I>{}, 1L), ...);
|
||||
}
|
||||
}
|
||||
#elif !defined(__cpp_fold_expressions) || __cpp_fold_expressions < 201603
|
||||
template <class T, class F, std::size_t... I>
|
||||
void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type /*move_values*/) {
|
||||
const int v[] = {(
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type /*move_values*/) {
|
||||
const int v[] = {0, (
|
||||
detail::for_each_field_impl_apply(sequence_tuple::get<I>(t), std::forward<F>(f), size_t_<I>{}, 1L),
|
||||
0
|
||||
)...};
|
||||
@@ -40,15 +66,24 @@ void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type
|
||||
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type /*move_values*/) {
|
||||
const int v[] = {(
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type /*move_values*/) {
|
||||
const int v[] = {0, (
|
||||
detail::for_each_field_impl_apply(sequence_tuple::get<I>(std::move(t)), std::forward<F>(f), size_t_<I>{}, 1L),
|
||||
0
|
||||
)...};
|
||||
(void)v;
|
||||
}
|
||||
#else
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type /*move_values*/) {
|
||||
(detail::for_each_field_impl_apply(sequence_tuple::get<I>(t), std::forward<F>(f), size_t_<I>{}, 1L), ...);
|
||||
}
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type /*move_values*/) {
|
||||
(detail::for_each_field_impl_apply(sequence_tuple::get<I>(std::move(t)), std::forward<F>(f), size_t_<I>{}, 1L), ...);
|
||||
}
|
||||
#endif
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,10 +9,13 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct equal_impl {
|
||||
@@ -116,11 +119,57 @@ namespace boost { namespace pfr { namespace detail {
|
||||
}
|
||||
};
|
||||
|
||||
// Hash combine functions copied from Boost.ContainerHash
|
||||
// https://github.com/boostorg/container_hash/blob/171c012d4723c5e93cc7cffe42919afdf8b27dfa/include/boost/container_hash/hash.hpp#L311
|
||||
// that is based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
//
|
||||
// This also contains public domain code from MurmurHash. From the
|
||||
// MurmurHash header:
|
||||
//
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
template <typename SizeT>
|
||||
constexpr void hash_combine(SizeT& seed, SizeT value) noexcept {
|
||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
constexpr auto rotl(std::uint32_t x, std::uint32_t r) noexcept {
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
constexpr void hash_combine(std::uint32_t& h1, std::uint32_t k1) noexcept {
|
||||
const std::uint32_t c1 = 0xcc9e2d51;
|
||||
const std::uint32_t c2 = 0x1b873593;
|
||||
|
||||
k1 *= c1;
|
||||
k1 = detail::rotl(k1,15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = detail::rotl(h1,13);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
}
|
||||
|
||||
#if defined(INT64_MIN) && defined(UINT64_MAX)
|
||||
constexpr void hash_combine(std::uint64_t& h, std::uint64_t k) noexcept {
|
||||
const std::uint64_t m = 0xc6a4a7935bd1e995ULL;
|
||||
const int r = 47;
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h ^= k;
|
||||
h *= m;
|
||||
|
||||
// Completely arbitrary number, to prevent 0's
|
||||
// from hashing to 0.
|
||||
h += 0xe6546b64;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
auto compute_hash(const T& value, long /*priority*/)
|
||||
-> decltype(std::hash<T>()(value))
|
||||
@@ -171,12 +220,13 @@ namespace boost { namespace pfr { namespace detail {
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
x,
|
||||
[&result, &y](const auto& lhs) {
|
||||
constexpr std::size_t fields_count_rhs_ = detail::fields_count<std::remove_reference_t<U>>();
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
y,
|
||||
[&result, &lhs](const auto& rhs) {
|
||||
result = visitor_t::cmp(lhs, rhs);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_rhs>{}
|
||||
detail::make_index_sequence<fields_count_rhs_>{}
|
||||
);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_lhs>{}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <iosfwd> // stream operators
|
||||
#include <iomanip>
|
||||
|
||||
@@ -19,6 +21,8 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
inline auto quoted_helper(const std::string& s) noexcept {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,11 +9,13 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <utility> // metaprogramming stuff
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <utility> // metaprogramming stuff
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2018 Sergei Fedorov
|
||||
// Copyright (c) 2019-2020 Antony Polukhin
|
||||
// Copyright (c) 2019-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,9 +10,11 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2017-2018 Chris Beck
|
||||
// Copyright (c) 2019-2020 Antony Polukhin
|
||||
// Copyright (c) 2019-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,12 +10,15 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <memory> // std::addressof
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
@@ -41,7 +44,7 @@ struct tuple_of_aligned_storage<sequence_tuple::tuple<Ts...>> {
|
||||
using type = sequence_tuple::tuple<internal_aligned_storage<sizeof(Ts),
|
||||
#if defined(__GNUC__) && __GNUC__ < 8 && !defined(__x86_64__) && !defined(__CYGWIN__)
|
||||
// Before GCC-8 the `alignof` was returning the optimal alignment rather than the minimal one.
|
||||
// We have to adjust the alignemnt because otherwise we get the wrong offset.
|
||||
// We have to adjust the alignment because otherwise we get the wrong offset.
|
||||
(alignof(Ts) > 4 ? 4 : alignof(Ts))
|
||||
#else
|
||||
alignof(Ts)
|
||||
|
||||
51
include/boost/pfr/detail/possible_reflectable.hpp
Normal file
51
include/boost/pfr/detail/possible_reflectable.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP
|
||||
#define BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/traits_fwd.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits> // for std::is_aggregate
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// Returns false when the type exactly wasn't be reflectable
|
||||
template <class T, class WhatFor>
|
||||
constexpr decltype(is_reflectable<T, WhatFor>::value) possible_reflectable(long) noexcept {
|
||||
return is_reflectable<T, WhatFor>::value;
|
||||
}
|
||||
|
||||
#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
|
||||
|
||||
template <class T, class WhatFor>
|
||||
constexpr bool possible_reflectable(int) noexcept {
|
||||
# if defined(__cpp_lib_is_aggregate)
|
||||
using type = std::remove_cv_t<T>;
|
||||
return std::is_aggregate<type>();
|
||||
# else
|
||||
return true;
|
||||
# endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class T, class WhatFor>
|
||||
constexpr bool possible_reflectable(int) noexcept {
|
||||
// negative answer here won't change behaviour in PFR-dependent libraries(like Fusion)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -7,8 +7,10 @@
|
||||
#define BOOST_PFR_DETAIL_RVALUE_T_HPP
|
||||
#pragma once
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <utility> // std::enable_if_t
|
||||
#endif
|
||||
|
||||
// This header provides aliases rvalue_t and lvalue_t.
|
||||
//
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,8 +10,10 @@
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <utility> // metaprogramming stuff
|
||||
#include <cstddef> // std::size_t
|
||||
#endif
|
||||
|
||||
///////////////////// Tuple that holds its values in the supplied order
|
||||
namespace boost { namespace pfr { namespace detail { namespace sequence_tuple {
|
||||
@@ -50,30 +52,74 @@ struct tuple_base<std::index_sequence<> > {
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr T& get_impl(base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr const T& get_impl(const base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr volatile T& get_impl(volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr const volatile T& get_impl(const volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr T& get_by_type_impl(base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const T& get_by_type_impl(const base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr volatile T& get_by_type_impl(volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const volatile T& get_by_type_impl(const volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr T&& get_by_type_impl(base_from_member<N, T>&& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const T&& get_by_type_impl(const base_from_member<N, T>&& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-core.CallAndMessage)
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class ...Values>
|
||||
struct tuple: tuple_base<
|
||||
detail::index_sequence_for<Values...>,
|
||||
@@ -83,6 +129,9 @@ struct tuple: tuple_base<
|
||||
detail::index_sequence_for<Values...>,
|
||||
Values...
|
||||
>::tuple_base;
|
||||
|
||||
constexpr static std::size_t size() noexcept { return sizeof...(Values); }
|
||||
constexpr static bool empty() noexcept { return size() == 0; }
|
||||
};
|
||||
|
||||
|
||||
@@ -121,6 +170,10 @@ using tuple_element = std::remove_reference< decltype(
|
||||
::boost::pfr::detail::sequence_tuple::get<I>( std::declval<T>() )
|
||||
) >;
|
||||
|
||||
template <class... Args>
|
||||
constexpr auto make_sequence_tuple(Args... args) noexcept {
|
||||
return ::boost::pfr::detail::sequence_tuple::tuple<Args...>{ args... };
|
||||
}
|
||||
|
||||
}}}} // namespace boost::pfr::detail::sequence_tuple
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,7 +9,9 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <cstddef> // metaprogramming stuff
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -7,6 +7,11 @@
|
||||
#define BOOST_PFR_DETAIL_SIZE_T_HPP
|
||||
#pragma once
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
|
||||
41
include/boost/pfr/detail/stdarray.hpp
Normal file
41
include/boost/pfr/detail/stdarray.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2023 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_STDARRAY_HPP
|
||||
#define BOOST_PFR_DETAIL_STDARRAY_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <array>
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED
|
||||
# include <string_view>
|
||||
#endif
|
||||
#include <utility> // metaprogramming stuff
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdarray_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
return std::array<std::string_view, sizeof...(I)>{
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
};
|
||||
}
|
||||
#else
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdarray_from_tietuple(const T&, std::index_sequence<I...>) noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_STDARRAY_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,15 +9,18 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <utility> // metaprogramming stuff
|
||||
#include <tuple>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
constexpr auto make_stdtuple_from_tietuple(const T& t, std::index_sequence<I...>) {
|
||||
(void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter`
|
||||
return std::make_tuple(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
@@ -25,6 +28,7 @@ constexpr auto make_stdtuple_from_tietuple(const T& t, std::index_sequence<I...>
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
(void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter`
|
||||
return std::tie(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
@@ -32,6 +36,7 @@ constexpr auto make_stdtiedtuple_from_tietuple(const T& t, std::index_sequence<I
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_conststdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
(void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter`
|
||||
return std::tuple<
|
||||
std::add_lvalue_reference_t<std::add_const_t<
|
||||
std::remove_reference_t<decltype(boost::pfr::detail::sequence_tuple::get<I>(t))>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
|
||||
// Copyright (c) 2019-2020 Antony Polukhin
|
||||
// Copyright (c) 2019-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -16,7 +16,9 @@
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <tuple>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
@@ -39,6 +41,6 @@ struct tie_from_structure_tuple : std::tuple<Elements&...> {
|
||||
}
|
||||
};
|
||||
|
||||
}}} // boost::pfr::detail
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
// Copyright (c) 2019-2020 Antony Polukhin.
|
||||
// Copyright (c) 2019-2025 Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
#define BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
@@ -24,9 +27,19 @@ template <class T>
|
||||
constexpr T unsafe_declval() noexcept {
|
||||
report_if_you_see_link_error_with_this_function();
|
||||
|
||||
typename std::remove_reference<T>::type* ptr = 0;
|
||||
#ifdef BOOST_PFR_USE_LEGACY_UNSAFE_DECLVAL_IMPLEMENTATION
|
||||
typename std::remove_reference<T>::type* ptr = nullptr;
|
||||
ptr += 42; // suppresses 'null pointer dereference' warnings
|
||||
return static_cast<T>(*ptr);
|
||||
#else
|
||||
// Looks like `static_cast<T>(*ptr)` to prvalue fails on clang in C++26.
|
||||
// If this new implementation does not work for some cases, please, fill a
|
||||
// bug report and feel free to
|
||||
// define BOOST_PFR_USE_LEGACY_UNSAFE_DECLVAL_IMPLEMENTATION.
|
||||
using func_ptr_t = T(*)();
|
||||
func_ptr_t ptr = nullptr;
|
||||
return ptr();
|
||||
#endif
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,8 +9,10 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <boost/pfr/ops_fields.hpp>
|
||||
#include <boost/pfr/io_fields.hpp>
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/functions_for.hpp
|
||||
/// Contains BOOST_PFR_FUNCTIONS_FOR macro that defined comparison and stream operators for T along with hash_value function.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
#include <boost/pfr/detail/functional.hpp>
|
||||
@@ -35,6 +37,8 @@
|
||||
/// \b Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
///////////////////// Comparisons
|
||||
|
||||
/// \brief std::equal_to like comparator that returns \forcedlink{eq}(x, y)
|
||||
@@ -216,6 +220,10 @@ template <class T> struct hash {
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_FUNCTORS_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/detail/detectors.hpp>
|
||||
#include <boost/pfr/io_fields.hpp>
|
||||
|
||||
@@ -38,25 +40,25 @@ namespace detail {
|
||||
///////////////////// Helper typedefs
|
||||
template <class Stream, class Type>
|
||||
using enable_not_ostreamable_t = std::enable_if_t<
|
||||
not_appliable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
|
||||
not_applicable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_not_istreamable_t = std::enable_if_t<
|
||||
not_appliable<istreamable_detector, Stream&, Type&>::value,
|
||||
not_applicable<istreamable_detector, Stream&, Type&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_ostreamable_t = std::enable_if_t<
|
||||
!not_appliable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
|
||||
!not_applicable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_istreamable_t = std::enable_if_t<
|
||||
!not_appliable<istreamable_detector, Stream&, Type&>::value,
|
||||
!not_applicable<istreamable_detector, Stream&, Type&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
@@ -67,6 +69,8 @@ struct io_impl {
|
||||
T value;
|
||||
};
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
enable_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, io_impl<T>&& x) {
|
||||
return out << boost::pfr::io_fields(std::forward<T>(x.value));
|
||||
@@ -87,19 +91,23 @@ enable_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_
|
||||
return in >> x.value;
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// IO manupulator to read/write \aggregate `value` using its IO stream operators or using \forcedlink{io_fields} if operators are not awailable.
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// IO manipulator to read/write \aggregate `value` using its IO stream operators or using \forcedlink{io_fields} if operators are not available.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i; short s; };
|
||||
/// my_struct s;
|
||||
/// my_struct x;
|
||||
/// std::stringstream ss;
|
||||
/// ss << "{ 12, 13 }";
|
||||
/// ss >> boost::pfr::io(s);
|
||||
/// assert(s.i == 12);
|
||||
/// assert(s.i == 13);
|
||||
/// ss >> boost::pfr::io(x);
|
||||
/// assert(x.i == 12);
|
||||
/// assert(x.s == 13);
|
||||
/// \endcode
|
||||
///
|
||||
/// \customio
|
||||
@@ -108,6 +116,10 @@ auto io(T&& value) noexcept {
|
||||
return detail::io_impl<T>{std::forward<T>(value)};
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_IO_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,18 +10,21 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/io.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/io_fields.hpp
|
||||
/// Contains IO manupulator \forcedlink{io_fields} to read/write \aggregate `value` field-by-field.
|
||||
/// Contains IO manipulator \forcedlink{io_fields} to read/write any \aggregate field-by-field.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
@@ -52,6 +55,7 @@ struct io_fields_impl {
|
||||
T value;
|
||||
};
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, io_fields_impl<const T&>&& x) {
|
||||
@@ -120,19 +124,23 @@ std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& i
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<const T&>&& ) {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Atetmpt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier.");
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier.");
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T>&& ) {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Atetmpt to use istream operator on a boost::pfr::io_fields wrapped temporary of type T.");
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped temporary of type T.");
|
||||
return in;
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// IO manupulator to read/write \aggregate `value` field-by-field.
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// IO manipulator to read/write \aggregate `value` field-by-field.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
@@ -159,6 +167,10 @@ auto io_fields(T&& value) noexcept {
|
||||
return detail::io_fields_impl<T>{std::forward<T>(value)};
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_IO_FIELDS_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/detail/detectors.hpp>
|
||||
#include <boost/pfr/ops_fields.hpp>
|
||||
|
||||
@@ -40,13 +42,13 @@ namespace detail {
|
||||
///////////////////// Helper typedefs that are used by all the ops
|
||||
template <template <class, class> class Detector, class T, class U>
|
||||
using enable_not_comp_base_t = std::enable_if_t<
|
||||
not_appliable<Detector, T const&, U const&>::value,
|
||||
not_applicable<Detector, T const&, U const&>::value,
|
||||
bool
|
||||
>;
|
||||
|
||||
template <template <class, class> class Detector, class T, class U>
|
||||
using enable_comp_base_t = std::enable_if_t<
|
||||
!not_appliable<Detector, T const&, U const&>::value,
|
||||
!not_applicable<Detector, T const&, U const&>::value,
|
||||
bool
|
||||
>;
|
||||
///////////////////// std::enable_if_t like functions that enable only if types do not support operation
|
||||
@@ -59,7 +61,7 @@ namespace detail {
|
||||
template <class T, class U> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T, U>;
|
||||
|
||||
template <class T> using enable_not_hashable_t = std::enable_if_t<
|
||||
not_appliable<hash_detector, const T&, const T&>::value,
|
||||
not_applicable<hash_detector, const T&, const T&>::value,
|
||||
std::size_t
|
||||
>;
|
||||
///////////////////// std::enable_if_t like functions that enable only if types do support operation
|
||||
@@ -72,13 +74,14 @@ namespace detail {
|
||||
template <class T, class U> using enable_ge_comp_t = enable_comp_base_t<comp_ge_detector, T, U>;
|
||||
|
||||
template <class T> using enable_hashable_t = std::enable_if_t<
|
||||
!not_appliable<hash_detector, const T&, const T&>::value,
|
||||
!not_applicable<hash_detector, const T&, const T&>::value,
|
||||
std::size_t
|
||||
>;
|
||||
} // namespace detail
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// \brief Compares lhs and rhs for equality using their own comparison and conversion operators; if no operators avalable returns \forcedlink{eq_fields}(lhs, rhs).
|
||||
/// \brief Compares lhs and rhs for equality using their own comparison and conversion operators; if no operators available returns \forcedlink{eq_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
@@ -93,7 +96,7 @@ constexpr detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for inequality using their own comparison and conversion operators; if no operators avalable returns \forcedlink{ne_fields}(lhs, rhs).
|
||||
/// \brief Compares lhs and rhs for inequality using their own comparison and conversion operators; if no operators available returns \forcedlink{ne_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is not equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
@@ -108,7 +111,7 @@ constexpr detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for less-than using their own comparison and conversion operators; if no operators avalable returns \forcedlink{lt_fields}(lhs, rhs).
|
||||
/// \brief Compares lhs and rhs for less-than using their own comparison and conversion operators; if no operators available returns \forcedlink{lt_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is less than rhs; false otherwise
|
||||
template <class T, class U>
|
||||
@@ -123,7 +126,7 @@ constexpr detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for greater-than using their own comparison and conversion operators; if no operators avalable returns \forcedlink{lt_fields}(lhs, rhs).
|
||||
/// \brief Compares lhs and rhs for greater-than using their own comparison and conversion operators; if no operators available returns \forcedlink{lt_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is greater than rhs; false otherwise
|
||||
template <class T, class U>
|
||||
@@ -138,7 +141,7 @@ constexpr detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for less-equal using their own comparison and conversion operators; if no operators avalable returns \forcedlink{le_fields}(lhs, rhs).
|
||||
/// \brief Compares lhs and rhs for less-equal using their own comparison and conversion operators; if no operators available returns \forcedlink{le_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is less or equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
@@ -153,7 +156,7 @@ constexpr detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for greater-equal using their own comparison and conversion operators; if no operators avalable returns \forcedlink{ge_fields}(lhs, rhs).
|
||||
/// \brief Compares lhs and rhs for greater-equal using their own comparison and conversion operators; if no operators available returns \forcedlink{ge_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is greater or equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
@@ -168,7 +171,7 @@ constexpr detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
|
||||
}
|
||||
|
||||
|
||||
/// \brief Hashes value using its own std::hash specialization; if no std::hash specialization avalable returns \forcedlink{hash_fields}(value).
|
||||
/// \brief Hashes value using its own std::hash specialization; if no std::hash specialization available returns \forcedlink{hash_fields}(value).
|
||||
///
|
||||
/// \returns std::size_t with hash of the value
|
||||
template <class T>
|
||||
@@ -182,6 +185,10 @@ constexpr detail::enable_hashable_t<T> hash_value(const T& value) {
|
||||
return std::hash<T>{}(value);
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_OPS_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <boost/pfr/detail/functional.hpp>
|
||||
|
||||
@@ -33,6 +35,8 @@
|
||||
/// \b Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// Does a field-by-field equality comparison.
|
||||
///
|
||||
/// \returns `L == R && tuple_size_v<T> == tuple_size_v<U>`, where `L` and
|
||||
@@ -122,6 +126,11 @@ namespace boost { namespace pfr {
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_OPS_HPP
|
||||
|
||||
71
include/boost/pfr/traits.hpp
Normal file
71
include/boost/pfr/traits.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_TRAITS_HPP
|
||||
#define BOOST_PFR_TRAITS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/detail/possible_reflectable.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/traits.hpp
|
||||
/// Contains traits \forcedlink{is_reflectable} and \forcedlink{is_implicitly_reflectable} for detecting an ability to reflect type.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// Has a static const member variable `value` when it is known that type T can or can't be reflected using Boost.PFR; otherwise, there is no member variable.
|
||||
/// Every user may (and in some difficult cases - should) specialize is_reflectable on his own.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// namespace boost { namespace pfr {
|
||||
/// template<class All> struct is_reflectable<A, All> : std::false_type {}; // 'A' won't be interpreted as reflectable everywhere
|
||||
/// template<> struct is_reflectable<B, boost_fusion_tag> : std::false_type {}; // 'B' won't be interpreted as reflectable in only Boost Fusion
|
||||
/// }}
|
||||
/// \endcode
|
||||
/// \note is_reflectable affects is_implicitly_reflectable, the decision made by is_reflectable is used by is_implicitly_reflectable.
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable { /* does not have 'value' because value is unknown */ };
|
||||
|
||||
// these specs can't be inherited from 'std::integral_constant< bool, boost::pfr::is_reflectable<T, WhatFor>::value >',
|
||||
// because it will break the sfinae-friendliness
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<const T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<const volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
/// Checks the input type for the potential to be reflected.
|
||||
/// Specialize is_reflectable if you disagree with is_implicitly_reflectable's default decision.
|
||||
template<class T, class WhatFor>
|
||||
using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::detail::possible_reflectable<T, WhatFor>(1L) >;
|
||||
|
||||
/// Checks the input type for the potential to be reflected.
|
||||
/// Specialize is_reflectable if you disagree with is_implicitly_reflectable_v's default decision.
|
||||
template<class T, class WhatFor>
|
||||
constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable<T, WhatFor>::value;
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_TRAITS_HPP
|
||||
|
||||
28
include/boost/pfr/traits_fwd.hpp
Normal file
28
include/boost/pfr/traits_fwd.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_TRAITS_FWD_HPP
|
||||
#define BOOST_PFR_DETAIL_TRAITS_FWD_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable;
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_TRAITS_FWD_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,20 +10,26 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
#if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/tuple_size.hpp
|
||||
/// Contains tuple-like interfaces to get fields count \forcedlink{tuple_size}, \forcedlink{tuple_size_v}.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
|
||||
/// Has a static const member variable `value` that contains fields count in a T.
|
||||
/// Works for any T that supports aggregate initialization.
|
||||
/// Works for any T that satisfies \aggregate.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
@@ -34,7 +40,7 @@ using tuple_size = detail::size_t_< boost::pfr::detail::fields_count<T>() >;
|
||||
|
||||
|
||||
/// `tuple_size_v` is a template variable that contains fields count in a T and
|
||||
/// works for any T that supports aggregate initialization.
|
||||
/// works for any T that satisfies \aggregate.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
@@ -43,6 +49,10 @@ using tuple_size = detail::size_t_< boost::pfr::detail::fields_count<T>() >;
|
||||
template <class T>
|
||||
constexpr std::size_t tuple_size_v = tuple_size<T>::value;
|
||||
|
||||
BOOST_PFR_END_MODULE_EXPORT
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // #if defined(BOOST_USE_MODULES) && !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
|
||||
#endif // BOOST_PFR_TUPLE_SIZE_HPP
|
||||
|
||||
32
index.html
32
index.html
@@ -1,13 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (c) 2014-2025 Antony Polukhin
|
||||
antoshkka at gmail dot com
|
||||
|
||||
Distributed under the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt
|
||||
or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
boost-no-inspect
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=../../doc/html/boost_pfr.html">
|
||||
<title>Boost.PFR</title>
|
||||
<title>Boost.Stacktrace</title>
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
a {
|
||||
color: #00f;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Redirecting you to <a href="../../doc/html/boost_pfr.html">Boost.PFR</a>
|
||||
</p>
|
||||
<p>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="../../doc/html/boost_pfr.html">../../doc/html/boost_pfr.html</a>
|
||||
</p>
|
||||
<p>
|
||||
© 2014-2024 Antony Polukhin
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2016-2020 Antony Polukhin
|
||||
# Copyright (c) 2016-2025 Antony Polukhin
|
||||
# Copyright (c) 2023 Denis Mikhailov
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -12,8 +13,10 @@ import string
|
||||
|
||||
# Skipping some letters that may produce keywords or are hard to read, or shadow template parameters
|
||||
ascii_letters = string.ascii_letters.replace("o", "").replace("O", "").replace("i", "").replace("I", "").replace("T", "")
|
||||
WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE = 3
|
||||
|
||||
PROLOGUE = """// Copyright (c) 2016-2020 Antony Polukhin
|
||||
PROLOGUE = """// Copyright (c) 2016-2025 Antony Polukhin
|
||||
// Copyright (c) 2023 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -36,6 +39,10 @@ PROLOGUE = """// Copyright (c) 2016-2020 Antony Polukhin
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
|
||||
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||
#include <type_traits> // for std::conditional_t, std::is_reference
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class... Args>
|
||||
@@ -43,20 +50,43 @@ constexpr auto make_tuple_of_references(Args&&... args) noexcept {
|
||||
return sequence_tuple::tuple<Args&...>{ args... };
|
||||
}
|
||||
|
||||
template<typename T, typename Arg>
|
||||
constexpr decltype(auto) add_cv_like(Arg& arg) noexcept {
|
||||
if constexpr (std::is_const<T>::value && std::is_volatile<T>::value) {
|
||||
return const_cast<const volatile Arg&>(arg);
|
||||
}
|
||||
else if constexpr (std::is_const<T>::value) {
|
||||
return const_cast<const Arg&>(arg);
|
||||
}
|
||||
else if constexpr (std::is_volatile<T>::value) {
|
||||
return const_cast<volatile Arg&>(arg);
|
||||
}
|
||||
else {
|
||||
return const_cast<Arg&>(arg);
|
||||
}
|
||||
}
|
||||
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78939
|
||||
template<typename T, typename Sb, typename Arg>
|
||||
constexpr decltype(auto) workaround_cast(Arg& arg) noexcept {
|
||||
using output_arg_t = std::conditional_t<!std::is_reference<Sb>(), decltype(detail::add_cv_like<T>(arg)), Sb>;
|
||||
return const_cast<output_arg_t>(arg);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
|
||||
return sequence_tuple::tuple<>{};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = 0) noexcept {
|
||||
auto& [a] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
|
||||
return ::boost::pfr::detail::make_tuple_of_references(a);
|
||||
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
|
||||
auto& [a] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
|
||||
return ::boost::pfr::detail::make_tuple_of_references(detail::workaround_cast<T, decltype(a)>(a));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class< std::remove_cv_t<T> >::value>* = 0) noexcept {
|
||||
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
|
||||
return ::boost::pfr::detail::make_tuple_of_references( val );
|
||||
}
|
||||
|
||||
@@ -77,10 +107,37 @@ constexpr void tie_as_tuple(T& /*val*/, size_t_<I>) noexcept {
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
def fold_workaround_cast(indexes, divider):
|
||||
WORKAROUND_CAST_TEMPLATE = """
|
||||
detail::workaround_cast<T, decltype({arg})>({arg})
|
||||
"""
|
||||
lines = []
|
||||
div = ''
|
||||
tokens = [x.strip() for x in indexes.split(',')]
|
||||
casts = [WORKAROUND_CAST_TEMPLATE.strip().format(arg=tok)
|
||||
for tok in tokens]
|
||||
for i in range(0, len(casts)):
|
||||
if i%WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE==0:
|
||||
div = ''
|
||||
lines.append('')
|
||||
lines[-1] += div + casts[i]
|
||||
div = ','
|
||||
return divider.join(lines)
|
||||
|
||||
def calc_indexes_count(indexes):
|
||||
tokens = [x.strip() for x in indexes.split(',')]
|
||||
return len(tokens)
|
||||
|
||||
class EmptyLinePrinter:
|
||||
def print_once(self):
|
||||
if not self.printed:
|
||||
print("")
|
||||
self.printed = True
|
||||
printed = False
|
||||
|
||||
indexes = " a"
|
||||
print(PROLOGUE)
|
||||
funcs_count = 100 if len(sys.argv) == 1 else int(sys.argv[1])
|
||||
funcs_count = 200 if len(sys.argv) == 1 else int(sys.argv[1])
|
||||
max_args_on_a_line = len(ascii_letters)
|
||||
for i in range(1, funcs_count):
|
||||
if i % max_args_on_a_line == 0:
|
||||
@@ -92,18 +149,26 @@ for i in range(1, funcs_count):
|
||||
indexes += ascii_letters[i // max_args_on_a_line - 1]
|
||||
indexes += ascii_letters[i % max_args_on_a_line]
|
||||
|
||||
printed_casts = fold_workaround_cast(indexes.strip(), ",\n ")
|
||||
indexes_count = calc_indexes_count(indexes.strip())
|
||||
empty_printer = EmptyLinePrinter()
|
||||
|
||||
print("template <class T>")
|
||||
print("constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {")
|
||||
if i < max_args_on_a_line:
|
||||
print(" auto& [" + indexes.strip() + "] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
print(" return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");")
|
||||
print(" auto& [" + indexes.strip() + "] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
else:
|
||||
print(" auto& [")
|
||||
print(indexes)
|
||||
print(" ] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
print("")
|
||||
print(" ] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
empty_printer.print_once()
|
||||
|
||||
if indexes_count < WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE:
|
||||
print(" return ::boost::pfr::detail::make_tuple_of_references(" + printed_casts + ");")
|
||||
else:
|
||||
empty_printer.print_once()
|
||||
print(" return ::boost::pfr::detail::make_tuple_of_references(")
|
||||
print(indexes)
|
||||
print(" " + printed_casts)
|
||||
print(" );")
|
||||
|
||||
print("}\n")
|
||||
|
||||
267
misc/generate_fields_names_big.cpp.py
Normal file
267
misc/generate_fields_names_big.cpp.py
Normal file
@@ -0,0 +1,267 @@
|
||||
# Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
# Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
# The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
#
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
import sys
|
||||
import string
|
||||
import random
|
||||
|
||||
# a bigger value might lead to compiler out of heap space error on MSVC
|
||||
STRUCT_COUNT = 50
|
||||
MAX_FIELD_COUNT = 50
|
||||
|
||||
MAIN_TEMPLATE = """// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov, Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Generated by misc/generate_fields_names_big.cpp.py
|
||||
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing {
|
||||
|
||||
template <class... Types>
|
||||
auto make_stdarray(const Types&... t) {
|
||||
return std::array<std::common_type_t<Types...>, sizeof...(Types)>{t...};
|
||||
}
|
||||
|
||||
%STRUCTS_LIST%
|
||||
|
||||
%TEST_GET_NAME_DEFINITIONS_LIST%
|
||||
|
||||
%TEST_GET_NAMES_AS_ARRAY_DEFINITIONS_LIST%
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
%TEST_GET_NAME_CALLS_LIST%
|
||||
%TEST_GET_NAMES_AS_ARRAY_CALLS_LIST%
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
"""
|
||||
|
||||
STRUCT_TEMPLATE = """struct Aggregate%STRUCT_ID% {
|
||||
%FIELD_DEFINITIONS_LIST%
|
||||
};
|
||||
"""
|
||||
|
||||
STRUCT_FIELD_DEFINITION_TEMPLATE = """int %FIELD_NAME%;
|
||||
"""
|
||||
|
||||
TEST_GET_NAME_TEMPLATE = """void test_get_name_%TEST_ID%() {
|
||||
%CHECKERS_LIST%
|
||||
}
|
||||
"""
|
||||
|
||||
TEST_GET_NAME_CHECKER_TEMPLATE = """BOOST_TEST_EQ( ((boost::pfr::get_name<%FIELD_ID%, Aggregate%STRUCT_ID%>())), "%FIELD_NAME%");
|
||||
"""
|
||||
|
||||
TEST_GET_NAMES_AS_ARRAY_TEMPLATE = """void test_names_as_array_%TEST_ID%() {
|
||||
const auto expected = make_stdarray(
|
||||
%FIELD_NAMES_LIST%
|
||||
);
|
||||
const auto value = boost::pfr::names_as_array<Aggregate%STRUCT_ID%>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
FIELD_NAME_TEMPLATE = """std::string_view{"%FIELD_NAME%"}
|
||||
"""
|
||||
|
||||
TEST_GET_NAME_CALL_TEMPLATE = """testing::test_get_name_%TEST_ID%();
|
||||
"""
|
||||
|
||||
TEST_GET_NAMES_AS_ARRAY_CALL_TEMPLATE = """testing::test_names_as_array_%TEST_ID%();
|
||||
"""
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
field_names = {
|
||||
"alignas": True,
|
||||
"alignof": True,
|
||||
"and": True,
|
||||
"and_eq": True,
|
||||
"asm": True,
|
||||
"atomic_cancel": True,
|
||||
"atomic_commit": True,
|
||||
"atomic_noexcept": True,
|
||||
"auto": True,
|
||||
"bitand": True,
|
||||
"bitor": True,
|
||||
"bool": True,
|
||||
"break": True,
|
||||
"case": True,
|
||||
"catch": True,
|
||||
"char": True,
|
||||
"char8_t": True,
|
||||
"char16_t": True,
|
||||
"char32_t": True,
|
||||
"class": True,
|
||||
"compl": True,
|
||||
"concept": True,
|
||||
"const": True,
|
||||
"consteval": True,
|
||||
"constexpr": True,
|
||||
"constinit": True,
|
||||
"const_cast": True,
|
||||
"continue": True,
|
||||
"co_await": True,
|
||||
"co_return": True,
|
||||
"co_yield": True,
|
||||
"decltype": True,
|
||||
"default": True,
|
||||
"delete": True,
|
||||
"do": True,
|
||||
"double": True,
|
||||
"dynamic_cast": True,
|
||||
"else": True,
|
||||
"enum": True,
|
||||
"explicit": True,
|
||||
"export": True,
|
||||
"extern": True,
|
||||
"false": True,
|
||||
"float": True,
|
||||
"for": True,
|
||||
"friend": True,
|
||||
"goto": True,
|
||||
"if": True,
|
||||
"inline": True,
|
||||
"int": True,
|
||||
"long": True,
|
||||
"mutable": True,
|
||||
"namespace": True,
|
||||
"new": True,
|
||||
"noexcept": True,
|
||||
"not": True,
|
||||
"not_eq": True,
|
||||
"nullptr": True,
|
||||
"operator": True,
|
||||
"or": True,
|
||||
"or_eq": True,
|
||||
"private": True,
|
||||
"protected": True,
|
||||
"public": True,
|
||||
"reflexpr": True,
|
||||
"register": True,
|
||||
"reinterpret_cast": True,
|
||||
"requires": True,
|
||||
"return": True,
|
||||
"short": True,
|
||||
"signed": True,
|
||||
"sizeof": True,
|
||||
"static": True,
|
||||
"static_assert": True,
|
||||
"static_cast": True,
|
||||
"struct": True,
|
||||
"switch": True,
|
||||
"synchronized": True,
|
||||
"template": True,
|
||||
"this": True,
|
||||
"thread_local": True,
|
||||
"throw": True,
|
||||
"true": True,
|
||||
"try": True,
|
||||
"typedef": True,
|
||||
"typeid": True,
|
||||
"typename": True,
|
||||
"union": True,
|
||||
"unsigned": True,
|
||||
"using": True,
|
||||
"virtual": True,
|
||||
"void": True,
|
||||
"volatile": True,
|
||||
"wchar_t": True,
|
||||
"while": True,
|
||||
"xor": True,
|
||||
"xor_eq": True
|
||||
}
|
||||
field_names_by_id = {}
|
||||
|
||||
def generate_new_field_name():
|
||||
result = ''
|
||||
name_len = random.randint(1,100)
|
||||
result += random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")
|
||||
for i in range(name_len-1):
|
||||
result += random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")
|
||||
return result
|
||||
|
||||
def generate_field_name(struct_id, field_id):
|
||||
key = (struct_id, field_id)
|
||||
if not key in field_names_by_id:
|
||||
new_name = generate_new_field_name()
|
||||
while new_name in field_names:
|
||||
new_name = generate_new_field_name()
|
||||
field_names[new_name] = True
|
||||
field_names_by_id[key] = new_name
|
||||
return field_names_by_id[key]
|
||||
|
||||
def generate_struct(struct_id):
|
||||
field_definitions = ''
|
||||
fields_count = struct_id
|
||||
for i in range(fields_count):
|
||||
field_definitions += STRUCT_FIELD_DEFINITION_TEMPLATE.replace('%FIELD_NAME%', generate_field_name(struct_id, i))
|
||||
return STRUCT_TEMPLATE.replace('%FIELD_DEFINITIONS_LIST%', field_definitions).replace('%STRUCT_ID%', str(struct_id))
|
||||
|
||||
def generate_structs_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += generate_struct(i+1)
|
||||
return result
|
||||
|
||||
def generate_test_get_name_definition(struct_id):
|
||||
checkers_list = ''
|
||||
fields_count = struct_id
|
||||
for i in range(fields_count):
|
||||
checkers_list += TEST_GET_NAME_CHECKER_TEMPLATE.replace('%FIELD_ID%', str(i)).replace('%STRUCT_ID%', str(struct_id)).replace('%FIELD_NAME%', generate_field_name(struct_id, i))
|
||||
return TEST_GET_NAME_TEMPLATE.replace('%TEST_ID%', str(struct_id)).replace('%CHECKERS_LIST%', checkers_list)
|
||||
|
||||
def generate_test_get_name_definitions_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += generate_test_get_name_definition(i+1)
|
||||
return result
|
||||
|
||||
def generate_test_names_as_array_definition(struct_id):
|
||||
field_names_list = FIELD_NAME_TEMPLATE.replace('%FIELD_NAME%', generate_field_name(struct_id, 0))
|
||||
fields_count = struct_id
|
||||
for i in range(1, fields_count):
|
||||
field_names_list += ', ' + FIELD_NAME_TEMPLATE.replace('%FIELD_NAME%', generate_field_name(struct_id, i))
|
||||
return TEST_GET_NAMES_AS_ARRAY_TEMPLATE.replace('%TEST_ID%', str(struct_id)).replace('%FIELD_NAMES_LIST%', field_names_list).replace('%STRUCT_ID%', str(struct_id))
|
||||
|
||||
def generate_test_names_as_array_definitions_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += generate_test_names_as_array_definition(i+1)
|
||||
return result
|
||||
|
||||
def generate_test_get_name_calls_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += TEST_GET_NAME_CALL_TEMPLATE.replace('%TEST_ID%', str(i+1))
|
||||
return result
|
||||
|
||||
def generate_test_names_as_array_calls_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += TEST_GET_NAMES_AS_ARRAY_CALL_TEMPLATE.replace('%TEST_ID%', str(i+1))
|
||||
return result
|
||||
|
||||
print(MAIN_TEMPLATE.replace('%STRUCTS_LIST%', generate_structs_list()).replace('%TEST_GET_NAME_DEFINITIONS_LIST%', generate_test_get_name_definitions_list()).replace('%TEST_GET_NAMES_AS_ARRAY_DEFINITIONS_LIST%', generate_test_names_as_array_definitions_list()).replace('%TEST_GET_NAME_CALLS_LIST%', generate_test_get_name_calls_list()).replace('%TEST_GET_NAMES_AS_ARRAY_CALLS_LIST%', generate_test_names_as_array_calls_list()))
|
||||
|
||||
108
misc/strip_boost_namespace.sh
Executable file
108
misc/strip_boost_namespace.sh
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2021-2025 Antony Polukhin
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
PFR_TEST_COMPILER=clang++-19
|
||||
|
||||
echo "***** Making target path"
|
||||
TARGET_PATH="`dirname \"$0\"`/../../pfr_non_boost"
|
||||
rm -rf ${TARGET_PATH}/*
|
||||
mkdir -p ${TARGET_PATH}
|
||||
TARGET_PATH=`cd "${TARGET_PATH}";pwd`
|
||||
|
||||
SOURCE_PATH="`dirname \"$0\"`/.."
|
||||
SOURCE_PATH=`cd "${SOURCE_PATH}";pwd`
|
||||
|
||||
echo "***** Copying from ${SOURCE_PATH} to ${TARGET_PATH}"
|
||||
cp -rf ${SOURCE_PATH}/* ${TARGET_PATH}
|
||||
|
||||
mv ${TARGET_PATH}/include/boost/* ${TARGET_PATH}/include/
|
||||
rm -rf ${TARGET_PATH}/include/boost
|
||||
rm -rf ${TARGET_PATH}/test
|
||||
rm ${TARGET_PATH}/misc/strip_boost_namespace.sh
|
||||
rm -rf ${TARGET_PATH}/meta
|
||||
|
||||
echo "***** Changing sources"
|
||||
find ${TARGET_PATH} -type f | xargs sed -i \
|
||||
-e 's|namespace boost { ||g' \
|
||||
-e 's|namespace boost {||g' \
|
||||
-e 's|} // namespace boost::| // namespace |g' \
|
||||
\
|
||||
-e 's/::boost::pfr/::pfr/g' \
|
||||
-e 's/boost::pfr/pfr/g' \
|
||||
-e 's/BOOST_PFR_/PFR_/g' \
|
||||
-e 's|boost/pfr|pfr|g' \
|
||||
\
|
||||
-e 's/boost_pfr /pfr /g' \
|
||||
-e 's/boost_pfr_/pfr_/g' \
|
||||
-e 's/boost_pfr)/pfr)/g' \
|
||||
-e 's/Boost::pfr/pfr::pfr/g' \
|
||||
-e 's/BOOST_USE_MODULES/PFR_USE_MODULES/g' \
|
||||
-e 's|boost\.pfr;|pfr;|g' \
|
||||
|
||||
find ${TARGET_PATH}/doc -type f | xargs sed -i \
|
||||
-e 's|boost\.pfr\.|pfr.|g' \
|
||||
-e 's|boost\.pfr`|pfr`|g' \
|
||||
-e 's/boost_pfr\./pfr./g' \
|
||||
-e 's|Boost\.PFR|PFR|g' \
|
||||
|
||||
sed -i 's|# \[Boost.PFR\](https://boost.org/libs/pfr)|# [PFR](https://apolukhin.github.io/pfr_non_boost/)|g' ${TARGET_PATH}/README.md
|
||||
|
||||
echo -n "***** Testing: "
|
||||
if ${PFR_TEST_COMPILER} -std=c++2a -DPFR_ENABLE_GET_NAME_STATIC=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n "OK"
|
||||
else
|
||||
echo -n "FAIL"
|
||||
exit 2
|
||||
fi
|
||||
if ${PFR_TEST_COMPILER} -std=c++2a -DPFR_ENABLE_GET_NAME_STATIC=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n ", OK"
|
||||
else
|
||||
echo -n ", FAIL"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
if ${PFR_TEST_COMPILER} -std=c++2a -DPFR_ENABLE_GET_NAME_STATIC=1 -DBOOST_PFR_USE_CPP17=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/get_name.cpp && ./a.out > /dev/null; then
|
||||
echo -n ", OK"
|
||||
else
|
||||
echo -n ", FAIL"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
if ${PFR_TEST_COMPILER} -std=c++2a -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n ", OK"
|
||||
else
|
||||
echo -n ", FAIL"
|
||||
exit 5
|
||||
fi
|
||||
if ${PFR_TEST_COMPILER} -std=c++2a -DPFR_USE_LOOPHOLE=1 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n ", OK"
|
||||
else
|
||||
echo -n ", FAIL"
|
||||
exit 6
|
||||
fi
|
||||
|
||||
if ${PFR_TEST_COMPILER} -std=c++2a -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/get.cpp && ./a.out > /dev/null; then
|
||||
echo -n ", OK"
|
||||
else
|
||||
echo -n ", FAIL"
|
||||
exit 7
|
||||
fi
|
||||
|
||||
mkdir build_module || :
|
||||
cd build_module
|
||||
if cmake -DPFR_USE_MODULES=1 -DBUILD_TESTING=1 -GNinja -DCMAKE_CXX_COMPILER=${PFR_TEST_COMPILER} ${TARGET_PATH} && cmake --build .; then
|
||||
echo "Modules check OK"
|
||||
else
|
||||
echo "Modules check FAIL"
|
||||
exit 8
|
||||
fi
|
||||
cd ..
|
||||
|
||||
rm -rf build_module || :
|
||||
rm a.out || :
|
||||
|
||||
echo -e "\n***** Done"
|
||||
42
modules/boost_pfr.cppm
Normal file
42
modules/boost_pfr.cppm
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// To compile manually use a command like the folowing:
|
||||
// clang++ -I ../include -std=c++20 --precompile -x c++-module pfr.cppm
|
||||
|
||||
module;
|
||||
|
||||
#include <version>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef BOOST_PFR_USE_STD_MODULE
|
||||
import std;
|
||||
#else
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
#define BOOST_PFR_INTERFACE_UNIT
|
||||
|
||||
export module boost.pfr;
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Winclude-angled-in-module-purview"
|
||||
#endif
|
||||
|
||||
#include <boost/pfr.hpp>
|
||||
|
||||
31
modules/usage_sample.cpp
Normal file
31
modules/usage_sample.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// To compile manually use a command like the folowing:
|
||||
// clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp
|
||||
|
||||
//[pfr_module_example
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
import boost.pfr;
|
||||
|
||||
struct some_person {
|
||||
std::string name;
|
||||
unsigned birth_year;
|
||||
};
|
||||
|
||||
int main() {
|
||||
some_person val{"Edgar Allan Poe", 1809};
|
||||
|
||||
std::cout << boost::pfr::get<0>(val) // No macro!
|
||||
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate!
|
||||
|
||||
std::cout << '\n' << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809}
|
||||
std::cout << "\n." << boost::pfr::get_name<0, some_person>()
|
||||
<< '=' << val.name << '\n'; // Outputs: .name=Edgar Allan Poe
|
||||
}
|
||||
//]
|
||||
27
modules/usage_test_mu1.cpp
Normal file
27
modules/usage_test_mu1.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// To compile manually use a command like the folowing:
|
||||
// clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/pfr.hpp>
|
||||
|
||||
struct some_person {
|
||||
std::string name;
|
||||
unsigned birth_year;
|
||||
};
|
||||
|
||||
void mu1_act() {
|
||||
some_person val{"Edgar Allan Poe", 1809};
|
||||
|
||||
std::cout << boost::pfr::get<0>(val) // No macro!
|
||||
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate!
|
||||
|
||||
std::cout << '\n' << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809}
|
||||
std::cout << "\n." << boost::pfr::get_name<0, some_person>()
|
||||
<< '=' << val.name << '\n'; // Outputs: .name=Edgar Allan Poe
|
||||
}
|
||||
32
modules/usage_test_mu2.cpp
Normal file
32
modules/usage_test_mu2.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// To compile manually use a command like the folowing:
|
||||
// clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
import boost.pfr;
|
||||
|
||||
struct some_person {
|
||||
std::string name;
|
||||
unsigned birth_year;
|
||||
};
|
||||
|
||||
void mu1_act();
|
||||
|
||||
int main() {
|
||||
mu1_act();
|
||||
|
||||
some_person val{"Joseph Brodsky", 1940};
|
||||
|
||||
std::cout << boost::pfr::get<0>(val) // No macro!
|
||||
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate!
|
||||
|
||||
std::cout << '\n' << boost::pfr::io(val);
|
||||
std::cout << "\n." << boost::pfr::get_name<0, some_person>()
|
||||
<< '=' << val.name << '\n';
|
||||
}
|
||||
32
test/CMakeLists.txt
Normal file
32
test/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2016-2025 Antony Polukhin
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
if(NOT TARGET tests)
|
||||
add_custom_target(tests)
|
||||
endif()
|
||||
|
||||
file(GLOB CORE_RUN_FILES "core/run/*.cpp")
|
||||
foreach (testsourcefile ${CORE_RUN_FILES})
|
||||
get_filename_component(testname ${testsourcefile} NAME_WE)
|
||||
add_executable(pfr_core_${testname} ${testsourcefile})
|
||||
target_link_libraries(pfr_core_${testname} Boost::pfr Boost::core Boost::container_hash)
|
||||
target_include_directories(pfr_core_${testname} PRIVATE ../../../)
|
||||
add_test(NAME pfr_core_${testname} COMMAND pfr_core_${testname})
|
||||
add_dependencies(tests pfr_core_${testname})
|
||||
endforeach()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.12)
|
||||
message(AUTHOR_WARNING "Disabling core_name tests as CMake version 3.12+ is required but using ${CMAKE_VERSION}")
|
||||
else()
|
||||
file(GLOB CORE_NAME_RUN_FILES "core_name/run/*.cpp")
|
||||
foreach (testsourcefile ${CORE_NAME_RUN_FILES})
|
||||
get_filename_component(testname ${testsourcefile} NAME_WE)
|
||||
add_executable(pfr_corename_${testname} ${testsourcefile})
|
||||
target_compile_features(pfr_corename_${testname} PUBLIC cxx_std_20)
|
||||
target_link_libraries(pfr_corename_${testname} Boost::pfr Boost::core Boost::container_hash)
|
||||
target_include_directories(pfr_corename_${testname} PRIVATE ../../../)
|
||||
add_test(NAME pfr_corename_${testname} COMMAND pfr_corename_${testname})
|
||||
add_dependencies(tests pfr_corename_${testname})
|
||||
endforeach()
|
||||
endif()
|
||||
10
test/Jamfile
Normal file
10
test/Jamfile
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2023 Denis Mikhailov
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
build-project config ;
|
||||
build-project core ;
|
||||
build-project core_name ;
|
||||
@@ -2,7 +2,7 @@
|
||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Copyright Antony Polukhin 2016-2019.
|
||||
# Copyright Antony Polukhin 2016-2021.
|
||||
|
||||
#
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
@@ -32,21 +32,25 @@ skip_tags: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
TOOLSET: msvc-9.0
|
||||
ADDRMD: 32
|
||||
CXXSTD: latest # fake
|
||||
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
# TOOLSET: msvc # TODO: clang-win ???
|
||||
# ADDRMD: 32,64
|
||||
# CXXSTD: 17,latest
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correctly use std::tuple_size
|
||||
ADDRMD: 32,64
|
||||
CXXSTD: 17,latest
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correctly use std::tuple_size
|
||||
ADDRMD: 32,64
|
||||
CXXSTD: 17,latest
|
||||
CXXFLAGS: /permissive-
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correctly use std::tuple_size
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
|
||||
21
test/cmake_subdir_test/CMakeLists.txt
Normal file
21
test/cmake_subdir_test/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright (c) 2016-2025 Antony Polukhin
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...4.0)
|
||||
|
||||
project(pfr_subdir_test LANGUAGES CXX)
|
||||
|
||||
add_subdirectory(../../../assert boostorg/assert)
|
||||
add_subdirectory(../../../container_hash boostorg/container_hash)
|
||||
add_subdirectory(../../../core boostorg/core)
|
||||
add_subdirectory(../../../config boostorg/config)
|
||||
add_subdirectory(../../../detail boostorg/detail)
|
||||
add_subdirectory(../../../describe boostorg/describe)
|
||||
add_subdirectory(../../../integer boostorg/integer)
|
||||
add_subdirectory(../../../mp11 boostorg/mp11)
|
||||
add_subdirectory(../../../static_assert boostorg/static_assert)
|
||||
add_subdirectory(../../../throw_exception boostorg/throw_exception)
|
||||
add_subdirectory(../../../type_traits boostorg/type_traits)
|
||||
|
||||
add_subdirectory(../../ boostorg/pfr)
|
||||
26
test/config/Jamfile.v2
Normal file
26
test/config/Jamfile.v2
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2023 Denis Mikhailov
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
import-search /boost/config/checks ;
|
||||
|
||||
import python ;
|
||||
import testing ;
|
||||
import config : requires ;
|
||||
|
||||
project
|
||||
: source-location .
|
||||
: requirements
|
||||
<library>/boost/config//boost_config
|
||||
<library>/boost/preprocessor//boost_preprocessor
|
||||
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
|
||||
;
|
||||
|
||||
|
||||
test-suite pfr_tests
|
||||
:
|
||||
[ run print_config.cpp : : : <test-info>always_show_run_output : auto_engine_config ]
|
||||
;
|
||||
@@ -1,17 +1,28 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <boost/pfr/config.hpp>
|
||||
#if BOOST_PFR_ENABLED
|
||||
#include <boost/pfr.hpp>
|
||||
#endif
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Platform info:" << '\n'
|
||||
<< "BOOST_PFR_USE_CPP17 == " << BOOST_PFR_USE_CPP17 << '\n'
|
||||
<< "BOOST_PFR_USE_CPP26 == " << BOOST_PFR_USE_CPP26 << '\n'
|
||||
<< "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n'
|
||||
<< "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n'
|
||||
<< "BOOST_PFR_HAS_GUARANTEED_COPY_ELISION == " << BOOST_PFR_HAS_GUARANTEED_COPY_ELISION << '\n'
|
||||
<< "BOOST_PFR_ENABLE_IMPLICIT_REFLECTION == " << BOOST_PFR_ENABLE_IMPLICIT_REFLECTION << '\n'
|
||||
<< "BOOST_PFR_CORE_NAME_ENABLED == " << BOOST_PFR_CORE_NAME_ENABLED << '\n'
|
||||
<< "BOOST_PFR_FUNCTION_SIGNATURE == " << BOOST_PP_STRINGIZE(BOOST_PFR_FUNCTION_SIGNATURE) << '\n'
|
||||
<< "BOOST_PFR_CORE_NAME_PARSING == " << BOOST_PP_STRINGIZE(BOOST_PFR_CORE_NAME_PARSING) << '\n'
|
||||
<< "BOOST_PFR_ENABLED == " << BOOST_PFR_ENABLED << '\n'
|
||||
<< "__cplusplus == " << __cplusplus << '\n'
|
||||
#ifdef __cpp_structured_bindings
|
||||
<< "__cpp_structured_bindings == " << __cpp_structured_bindings << '\n'
|
||||
@@ -1,23 +1,29 @@
|
||||
# Copyright (C) 2016-2020, Antony Polukhin.
|
||||
# Copyright (C) 2016-2025 Antony Polukhin.
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
import-search /boost/config/checks ;
|
||||
|
||||
import python ;
|
||||
import testing ;
|
||||
import ../../config/checks/config : requires ;
|
||||
import config : requires ;
|
||||
|
||||
project
|
||||
: source-location .
|
||||
: requirements
|
||||
<toolset>msvc:<cxxflags>"/std:c++latest"
|
||||
<library>/boost/config//boost_config
|
||||
<library>/boost/core//boost_core
|
||||
<library>/boost/container_hash//boost_container_hash
|
||||
<library>/boost/type_index//boost_type_index
|
||||
|
||||
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
|
||||
[ requires cxx14_constexpr ]
|
||||
;
|
||||
|
||||
########## BEGIN of helpers to detect Loophole trick support
|
||||
########## BEGIN of helpers to detect Loophole and variadic structured binding support
|
||||
|
||||
actions mp_simple_run_action
|
||||
{
|
||||
@@ -36,24 +42,31 @@ rule mp-run-simple ( sources + : args * : input-files * : requirements * : targe
|
||||
mp-run-simple loophole_detection.cpp : : : : compiler_supports_loophole ;
|
||||
explicit compiler_supports_loophole ;
|
||||
|
||||
mp-run-simple variadic_structured_binding_detection.cpp : : : : compiler_supports_vsb ;
|
||||
explicit compiler_supports_vsb ;
|
||||
|
||||
########## END of helpers to detect Loophole trick support
|
||||
|
||||
|
||||
local DISABLE_ON_MSVC = <toolset>msvc:<build>no ;
|
||||
local DISABLE_ON_MSVC = ; #<toolset>msvc:<build>no ;
|
||||
local REQUIRE_LOOPHOLE =
|
||||
[ check-target-builds ../test//compiler_supports_loophole : : <build>no ]
|
||||
[ check-target-builds ../core//compiler_supports_loophole : : <build>no ]
|
||||
;
|
||||
local REQUIRE_VSB =
|
||||
[ check-target-builds ../core//compiler_supports_vsb : : <build>no ]
|
||||
;
|
||||
|
||||
local STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=1 [ requires cxx17_structured_bindings ] ;
|
||||
local LOOPHOLE_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=1 <define>BOOST_PFR_USE_CPP17=0 $(REQUIRE_LOOPHOLE) ;
|
||||
local CLASSIC_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 $(DISABLE_ON_MSVC) ;
|
||||
local VARIADIC_STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=1 $(REQUIRE_VSB) ;
|
||||
local STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=1 <define>BOOST_PFR_USE_CPP26=0 [ requires cxx17_structured_bindings ] ;
|
||||
local LOOPHOLE_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=1 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 $(REQUIRE_LOOPHOLE) ;
|
||||
local CLASSIC_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 $(DISABLE_ON_MSVC) ;
|
||||
|
||||
test-suite pfr_tests
|
||||
:
|
||||
[ run print_config.cpp : : : <test-info>always_show_run_output : auto_engine_config ]
|
||||
|
||||
[ run offset_based_getter.cpp ]
|
||||
|
||||
[ run can_be_as_fallback_in_the_fusion.cpp ]
|
||||
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ]
|
||||
@@ -61,9 +74,13 @@ test-suite pfr_tests
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON="std::size_t" : test_tuple_sizes_on_size_ts ]
|
||||
|
||||
[ run run/motivating_example.cpp : : : : auto_engine_motivating ]
|
||||
[ run ../example/sample_printing.cpp : : : : auto_engine_sample_printing ]
|
||||
[ run ../example/get.cpp : : : : auto_engine_get ]
|
||||
[ run ../example/quick_examples.cpp : : : : auto_engine_quick ]
|
||||
[ run ../../example/sample_printing.cpp : : : : auto_engine_sample_printing ]
|
||||
[ run ../../example/get.cpp : : : : auto_engine_get ]
|
||||
[ run ../../example/quick_examples.cpp : : : : auto_engine_quick ]
|
||||
|
||||
[ compile-fail fields_count_on_incomplete_type.cpp : <define>BOOST_PFR_RUN_TEST_ON=void : fields_count_on_incomplete_type_void ]
|
||||
[ compile-fail fields_count_on_incomplete_type.cpp : <define>BOOST_PFR_RUN_TEST_ON="void()" : fields_count_on_incomplete_type_function ]
|
||||
[ compile-fail fields_count_on_incomplete_type.cpp : <define>BOOST_PFR_RUN_TEST_ON="struct Foo" : fields_count_on_incomplete_type_struct ]
|
||||
;
|
||||
|
||||
local BLACKLIST_TESTS_FOR_LOOPHOLE =
|
||||
@@ -74,7 +91,7 @@ local BLACKLIST_TESTS_FOR_LOOPHOLE =
|
||||
tie_anonymous_const_field # boost::pfr::structure_tie gives compile time error on const fields
|
||||
;
|
||||
|
||||
# Those tests are either
|
||||
# Those tests are either
|
||||
# * reflecting a non literal type
|
||||
# * or calling boost::pfr::get and the result is a user defined structure
|
||||
local BLACKLIST_TESTS_FOR_CLASSIC =
|
||||
@@ -96,11 +113,12 @@ local BLACKLIST_TESTS_FOR_CLASSIC =
|
||||
tie_anonymous_const_field
|
||||
;
|
||||
|
||||
for local source_file in [ glob ./run/*.cpp ] [ glob ../example/*.cpp ]
|
||||
for local source_file in [ glob ./run/*.cpp ] [ glob ../../example/*.cpp ]
|
||||
{
|
||||
local target_name = $(source_file[1]:B) ;
|
||||
pfr_tests += [ run $(source_file) : : : $(VARIADIC_STRUCTURED_BINDING_ENGINE) : $(target_name)_vsb ] ;
|
||||
pfr_tests += [ run $(source_file) : : : $(STRUCTURED_BINDING_ENGINE) : $(target_name)_sb ] ;
|
||||
|
||||
|
||||
if ! $(target_name) in $(BLACKLIST_TESTS_FOR_LOOPHOLE)
|
||||
{
|
||||
pfr_tests += [ run $(source_file) : : : $(LOOPHOLE_ENGINE) : $(target_name)_lh ] ;
|
||||
@@ -130,5 +148,5 @@ for local source_file in [ glob ./compile-fail/*.cpp ]
|
||||
|
||||
if [ python.configured ]
|
||||
{
|
||||
testing.make-test run-pyd : ../misc/generate_cpp17.py ;
|
||||
testing.make-test run-pyd : ../../misc/generate_cpp17.py ;
|
||||
}
|
||||
37
test/core/can_be_as_fallback_in_the_fusion.cpp
Normal file
37
test/core/can_be_as_fallback_in_the_fusion.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
struct Aggregate {};
|
||||
using NonAggregate = int;
|
||||
|
||||
template<class T>
|
||||
struct is_implicitly_reflectable : std::false_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_implicitly_reflectable<Aggregate> : std::true_type
|
||||
{};
|
||||
|
||||
template<class T, class E=void>
|
||||
struct tag_of_fallback {
|
||||
using type = int; // unknown
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct tag_of_fallback<T, std::enable_if_t<std::is_same<T,T>::value>>
|
||||
{
|
||||
using type = std::conditional_t<
|
||||
is_implicitly_reflectable<T>::value
|
||||
, std::true_type
|
||||
, std::false_type
|
||||
>;
|
||||
};
|
||||
|
||||
static_assert(tag_of_fallback<Aggregate>::type::value == true, "");
|
||||
static_assert(tag_of_fallback<NonAggregate>::type::value == false, "");
|
||||
|
||||
int main() { }
|
||||
10
test/core/compile-fail/boost_pfr_disabled_via_macro.cpp
Normal file
10
test/core/compile-fail/boost_pfr_disabled_via_macro.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_PFR_ENABLED 0
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
int main() { }
|
||||
|
||||
15
test/core/compile-fail/constructible_0_or_more_args.cpp
Normal file
15
test/core/compile-fail/constructible_0_or_more_args.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2023-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
struct A {
|
||||
template <typename... Args>
|
||||
explicit A(Args&&...) {}
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<A>::value; // Must be a compile time error
|
||||
}
|
||||
15
test/core/compile-fail/constructible_1_or_more_args.cpp
Normal file
15
test/core/compile-fail/constructible_1_or_more_args.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2023-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
struct A {
|
||||
template <typename Arg0, typename... Args>
|
||||
explicit A(Arg0&&, Args&&...) {}
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<A>::value; // Must be a compile time error
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
21
test/core/compile-fail/inherited.cpp
Normal file
21
test/core/compile-fail/inherited.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2021 Denis Mikhailov
|
||||
// Copyright (c) 2021 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
struct A
|
||||
{};
|
||||
|
||||
struct B : A
|
||||
{
|
||||
int one;
|
||||
int two;
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<B>::value; // Must be a compile time error
|
||||
}
|
||||
|
||||
20
test/core/compile-fail/inherited_nonempty.cpp
Normal file
20
test/core/compile-fail/inherited_nonempty.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2021 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
struct A {
|
||||
int zero;
|
||||
};
|
||||
|
||||
struct B : public A {
|
||||
int one;
|
||||
int two;
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<B>::value; // Must be a compile time error
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 Antony Polukhin
|
||||
// Copyright (c) 2020-2025 Antony Polukhin
|
||||
// Copyright (c) 2020 Richard Hodges
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 Antony Polukhin
|
||||
// Copyright (c) 2020-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
37
test/core/fields_count_immutable.cpp
Normal file
37
test/core/fields_count_immutable.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2025-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Test from https://github.com/boostorg/pfr/issues/126
|
||||
|
||||
#include <boost/pfr.hpp>
|
||||
|
||||
struct NoCopy {
|
||||
NoCopy() = default;
|
||||
NoCopy(NoCopy const&) = delete;
|
||||
NoCopy(NoCopy&&) = delete;
|
||||
NoCopy& operator=(NoCopy&&) = delete;
|
||||
NoCopy& operator=(NoCopy const&) = delete;
|
||||
};
|
||||
|
||||
struct Group {
|
||||
NoCopy m;
|
||||
NoCopy m2;
|
||||
NoCopy m3;
|
||||
NoCopy m4;
|
||||
};
|
||||
|
||||
Group ReturnGroup() { return {};}
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef __cpp_lib_is_aggregate
|
||||
static_assert(std::is_aggregate_v<Group>, "Group is totally an aggregate");
|
||||
#endif
|
||||
static_assert(BOOST_PFR_HAS_GUARANTEED_COPY_ELISION, "Compiler implements mandatory copy elision");
|
||||
Group aggregate_init_test{{}, {}, {}, {}};
|
||||
Group elision_test = ReturnGroup();
|
||||
return boost::pfr::tuple_size_v<Group>;
|
||||
}
|
||||
|
||||
10
test/core/fields_count_on_incomplete_type.cpp
Normal file
10
test/core/fields_count_on_incomplete_type.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2023-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
|
||||
int main() {
|
||||
return static_cast<int>(boost::pfr::detail::fields_count<BOOST_PFR_RUN_TEST_ON>());
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 Antony Polukhin
|
||||
// Copyright (c) 2020-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2019 Ilya Kiselev
|
||||
// Copyright (c) 2019-2020 Antony Polukhin
|
||||
// Copyright (c) 2019-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
86
test/core/run/bitfields_count.cpp
Normal file
86
test/core/run/bitfields_count.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct bf7 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf7) == 1, "");
|
||||
|
||||
struct bf8 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
uint8_t b7 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf8) == 1, "");
|
||||
|
||||
struct bf16 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
uint8_t b7 : 1;
|
||||
uint8_t b8 : 1;
|
||||
uint8_t b9 : 1;
|
||||
uint8_t b10 : 1;
|
||||
uint8_t b11 : 1;
|
||||
uint8_t b12 : 1;
|
||||
uint8_t b13 : 1;
|
||||
uint8_t b14 : 1;
|
||||
uint8_t b15 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf16) == 2, "");
|
||||
|
||||
struct bf24 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
uint8_t b7 : 1;
|
||||
uint8_t b8 : 1;
|
||||
uint8_t b9 : 1;
|
||||
uint8_t b10 : 1;
|
||||
uint8_t b11 : 1;
|
||||
uint8_t b12 : 1;
|
||||
uint8_t b13 : 1;
|
||||
uint8_t b14 : 1;
|
||||
uint8_t b15 : 1;
|
||||
uint8_t b16 : 1;
|
||||
uint8_t b17 : 1;
|
||||
uint8_t b18 : 1;
|
||||
uint8_t b19 : 1;
|
||||
uint8_t b20 : 1;
|
||||
uint8_t b21 : 1;
|
||||
uint8_t b22 : 1;
|
||||
uint8_t b23 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf24) == 3, "");
|
||||
|
||||
int main() {
|
||||
static_assert(boost::pfr::tuple_size_v<bf7> == 7, "");
|
||||
static_assert(boost::pfr::tuple_size_v<bf8> == 8, "");
|
||||
static_assert(boost::pfr::tuple_size_v<bf16> == 16, "");
|
||||
static_assert(boost::pfr::tuple_size_v<bf24> == 24, "");
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
125
test/core/run/core17_generated.cpp
Normal file
125
test/core/run/core17_generated.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2023 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <type_traits> // for std::is_same
|
||||
|
||||
struct A {
|
||||
const volatile int cv_value = 0;
|
||||
volatile int v_value = 0;
|
||||
const int c_value = 0;
|
||||
int value = 0;
|
||||
|
||||
const volatile int& cv_ref;
|
||||
volatile int& v_ref;
|
||||
const int& c_ref;
|
||||
int& ref;
|
||||
|
||||
const volatile int&& cv_rref;
|
||||
volatile int&& v_rref;
|
||||
const int&& c_rref;
|
||||
int&& rref;
|
||||
};
|
||||
|
||||
int main() {
|
||||
#if BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26 && !defined(BOOST_USE_MODULES) // TODO: fix for BOOST_USE_MODULES
|
||||
const volatile int cv_value = 0;
|
||||
volatile int v_value = 0;
|
||||
const int c_value = 0;
|
||||
int value = 0;
|
||||
|
||||
typedef boost::pfr::detail::size_t_<12> fields_count_tag;
|
||||
|
||||
{
|
||||
A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
const A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
volatile A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
const volatile A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
|
||||
// Copyright (c) 2019-2020 Antony Polukhin
|
||||
// Copyright (c) 2019-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Example from https://github.com/apolukhin/magic_get/issues/21
|
||||
// Example from https://github.com/boostorg/pfr/issues/21
|
||||
|
||||
|
||||
// boost::pfr::for_each_field crashes when sizeof(MyConfig) > 248 (probably >= 256)
|
||||
@@ -13,6 +13,11 @@
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(BOOST_USE_MODULES) // TODO: fix for BOOST_USE_MODULES
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
template <typename T>
|
||||
class CfgAttrib {
|
||||
public:
|
||||
@@ -99,3 +104,5 @@ int main() {
|
||||
boost::pfr::get<0>(aCfg); // also C1202
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
// Copyright (c) 2018-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -54,6 +54,23 @@ struct simple {
|
||||
short d;
|
||||
};
|
||||
|
||||
struct empty{};
|
||||
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
constexpr std::size_t get_field_count_through_for_each_field() {
|
||||
std::size_t counter = 0;
|
||||
boost::pfr::for_each_field(simple{}, [&counter](auto&& /*val*/, std::size_t /*i*/) {
|
||||
++ counter;
|
||||
});
|
||||
return counter;
|
||||
}
|
||||
|
||||
// MSVC-14.1 fails to compile the following code
|
||||
#if !defined(_MSC_VER) || _MSC_VER > 1916
|
||||
static_assert(3 == get_field_count_through_for_each_field());
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
int main () {
|
||||
std::size_t control = 0;
|
||||
@@ -108,6 +125,13 @@ int main () {
|
||||
ss << val << ' ';
|
||||
});
|
||||
BOOST_TEST_EQ("42 a 3 ", ss.str());
|
||||
ss.str("");
|
||||
|
||||
boost::pfr::for_each_field(empty{}, [&ss](auto&& val) {
|
||||
ss << val << ' ';
|
||||
});
|
||||
BOOST_TEST_EQ("", ss.str());
|
||||
ss.str("");
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
// Copyright (c) 2016-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
struct adl_hash {
|
||||
@@ -73,7 +73,7 @@ void test_empty_struct() {
|
||||
|
||||
namespace foo {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
BOOST_PFR_FUNCTIONS_FOR(testing);
|
||||
BOOST_PFR_FUNCTIONS_FOR(testing)
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
67
test/core/run/get_by_type.cpp
Normal file
67
test/core/run/get_by_type.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2020-2025 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Aggregate {
|
||||
int a;
|
||||
const int b;
|
||||
double c;
|
||||
double d;
|
||||
short e;
|
||||
};
|
||||
|
||||
void test_get_by_type() {
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
Aggregate t{1, 2, 3.4, 5.6, 7};
|
||||
|
||||
BOOST_TEST_EQ(boost::pfr::get<int>(t), 1);
|
||||
BOOST_TEST_EQ(boost::pfr::get<const int>(t), 2);
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(t), 7);
|
||||
|
||||
boost::pfr::get<int>(t) = 11;
|
||||
boost::pfr::get<short>(t) = 77;
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_const_get_by_type() {
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
const Aggregate t{1, 2, 3.4, 5.6, 7};
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(t), 7);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_get_by_type_pod() {
|
||||
struct PodAggregate {
|
||||
int i;
|
||||
short s;
|
||||
};
|
||||
|
||||
PodAggregate pod{1, 2};
|
||||
BOOST_TEST_EQ(boost::pfr::get<int>(pod), 1);
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(pod), 2);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_get_by_type();
|
||||
testing::test_const_get_by_type();
|
||||
testing::test_get_by_type_pod();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user