mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 16:32:13 +00:00
Compare commits
177 Commits
boost-1.81
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
228922fdb5 | ||
|
|
ebcac93bcf | ||
|
|
79a8290374 | ||
|
|
1b0506f44f | ||
|
|
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 | ||
|
|
b10c0c66ed | ||
|
|
1bb4ced005 | ||
|
|
14185d614f |
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
181
.github/workflows/ci.yml
vendored
181
.github/workflows/ci.yml
vendored
@@ -17,35 +17,42 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-7
|
||||
cxxstd: "03,11,14,17"
|
||||
os: ubuntu-18.04
|
||||
- toolset: gcc-9 # Do not remove! It is the only toolset that tests misc/strip_boost_namespace.sh
|
||||
- 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-18.04
|
||||
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-18.04
|
||||
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: clang
|
||||
compiler: clang++-10
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
cxxflags: "cxxflags=-fsanitize=address,undefined,integer -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=-fsanitize=address,undefined,integer"
|
||||
# To low quota to use
|
||||
#- toolset: clang
|
||||
# cxxstd: "03,11,14,17,2a"
|
||||
# os: macos-10.15
|
||||
# cxxflags: "cxxflags=-fsanitize=address,undefined -fno-sanitize-recover=undefined"
|
||||
# linkflags: "linkflags=-fsanitize=address,undefined"
|
||||
- toolset: clang-15
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-22.04
|
||||
- toolset: clang-18
|
||||
cxxstd: "03,11,14,17,20,23"
|
||||
os: ubuntu-24.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
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
@@ -67,28 +74,60 @@ jobs:
|
||||
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 tools/inspect libs/filesystem
|
||||
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 -d0 headers
|
||||
./b2 -j4 variant=debug tools/inspect/build
|
||||
./b2 variant=debug tools/inspect
|
||||
|
||||
- name: Create user-config.jam
|
||||
if: matrix.compiler
|
||||
- name: Run CMake tests
|
||||
if: ${{matrix.toolset == 'gcc-14'}}
|
||||
run: |
|
||||
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
|
||||
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 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release "${{matrix.cxxflags}}" "${{matrix.linkflags}}" "${{matrix.launcher}}"
|
||||
./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 == 'gcc-9'}}
|
||||
if: ${{matrix.toolset == 'clang-19'}}
|
||||
run: ../boost-root/libs/$LIBRARY/misc/strip_boost_namespace.sh
|
||||
|
||||
- name: Prepare coverage data
|
||||
@@ -98,9 +137,9 @@ jobs:
|
||||
|
||||
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.15.zip
|
||||
unzip v1.15.zip
|
||||
LCOV="`pwd`/lcov-1.15/bin/lcov --gcov-tool $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
|
||||
@@ -124,25 +163,31 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# TODO: fails the loophole tests
|
||||
#- toolset: msvc
|
||||
# cxxstd: "14,17,latest"
|
||||
# addrmd: 32,64
|
||||
# os: windows-2022
|
||||
# TODO: fails the loophole tests
|
||||
#- toolset: msvc-14.2
|
||||
# cxxstd: "14,17,latest"
|
||||
# addrmd: 32,64
|
||||
# os: windows-2019
|
||||
- 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-2019
|
||||
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
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
@@ -161,16 +206,62 @@ jobs:
|
||||
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 tools/boostdep
|
||||
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
|
||||
b2 -d0 headers
|
||||
|
||||
- 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 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
|
||||
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
|
||||
|
||||
@@ -1,20 +1,48 @@
|
||||
# Generated by `boostdep --cmake pfr`
|
||||
# Copyright 2020 Peter Dimov
|
||||
# Copyright (c) 2016-2026 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.16)
|
||||
cmake_minimum_required(VERSION 3.5...3.31)
|
||||
|
||||
project(boost_pfr VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_pfr INTERFACE)
|
||||
add_library(Boost::pfr ALIAS boost_pfr)
|
||||
|
||||
target_include_directories(boost_pfr INTERFACE include)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
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()
|
||||
|
||||
|
||||
58
README.md
58
README.md
@@ -10,8 +10,8 @@ For a version of the library without `boost::` namespace see [PFR](https://githu
|
||||
|
||||
Branches | Build | Tests coverage | More info
|
||||
----------------|-------------- | -------------- |-----------
|
||||
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://www.boost.org/development/tests/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://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)
|
||||
|
||||
@@ -45,6 +45,8 @@ Outputs:
|
||||
Edgar Allan Poe was born in 1809
|
||||
```
|
||||
|
||||
[Run the above sample](https://godbolt.org/z/PfYsWKb7v)
|
||||
|
||||
|
||||
### Motivating Example #1
|
||||
```c++
|
||||
@@ -94,6 +96,58 @@ 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
|
||||
|
||||
|
||||
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=../../../..
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
|
||||
160
doc/pfr.qbk
160
doc/pfr.qbk
@@ -1,7 +1,7 @@
|
||||
[library Boost.PFR
|
||||
[quickbook 1.6]
|
||||
[version 2.0]
|
||||
[copyright 2016-2022 Antony Polukhin]
|
||||
[version 2.3]
|
||||
[copyright 2016-2026 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,20 +43,20 @@ 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)",
|
||||
friend_info.id, /////////////////////////////////////////////////////////
|
||||
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
|
||||
@@ -80,20 +81,20 @@ 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 ////////////////////////////////////////////////////////////
|
||||
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 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,15 +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. ]]
|
||||
]
|
||||
|
||||
|
||||
@@ -475,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`
|
||||
@@ -514,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-2022 Antony Polukhin
|
||||
// Copyright 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright 2016-2026 Antony Polukhin
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See the accompanying file LICENSE_1_0.txt
|
||||
@@ -77,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
|
||||
@@ -91,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;
|
||||
@@ -100,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-2022 Antony Polukhin
|
||||
// Copyright 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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,85 +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
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (!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
|
||||
# error Boost.PFR requires /std:c++latest or /std:c++17 flags on your compiler.
|
||||
# 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
|
||||
|
||||
#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
|
||||
|
||||
#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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2017-2018 Alexandr Poltavsky, Antony Polukhin.
|
||||
// Copyright (c) 2019-2022 Antony Polukhin.
|
||||
// Copyright (c) 2019-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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,6 +28,11 @@
|
||||
|
||||
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;
|
||||
@@ -46,6 +53,14 @@ struct ubiq_rref_constructor {
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////// 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,12 +106,7 @@ 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
|
||||
@@ -127,16 +145,16 @@ struct ubiq_rref_base_asserting {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, std::size_t I0, std::size_t... I, class /*Enable*/ = typename std::enable_if<std::is_copy_constructible<T>::value>::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
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_lref_base_asserting<T>{}, ubiq_lref_constructor{I}... })>::type
|
||||
-> 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*/ = typename std::enable_if<!std::is_copy_constructible<T>::value>::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
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_rref_base_asserting<T>{}, ubiq_rref_constructor{I}... })>::type
|
||||
-> std::add_pointer_t<decltype(T{ ubiq_rref_base_asserting<T>{}, ubiq_rref_constructor{I}... })>
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -147,17 +165,40 @@ constexpr void* assert_first_not_base(std::index_sequence<>) noexcept
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////// 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;
|
||||
template <class T, std::size_t N>
|
||||
constexpr void assert_first_not_base(int) noexcept {}
|
||||
|
||||
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 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>{});
|
||||
}
|
||||
|
||||
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;
|
||||
///////////////////// 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>
|
||||
@@ -166,125 +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."
|
||||
);
|
||||
|
||||
#if !BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
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.
|
||||
@@ -295,26 +446,27 @@ constexpr std::size_t fields_count() noexcept {
|
||||
// );
|
||||
//#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= 1920)
|
||||
// Workaround for msvc compilers. Versions <= 1920 have a limit of max 1024 elements in template parameter pack
|
||||
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT >= 1024 ? 1024 : sizeof(type) * CHAR_BIT);
|
||||
#else
|
||||
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT); // We multiply by CHAR_BIT because the type may have bitfields in T
|
||||
#endif
|
||||
|
||||
constexpr std::size_t result = detail::detect_fields_count_dispatch<type>(size_t_<max_fields_count>{}, 1L, 1L);
|
||||
|
||||
detail::assert_first_not_base<type>(detail::make_index_sequence<result>{});
|
||||
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-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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,54 @@
|
||||
|
||||
#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 !defined(__cpp_fold_expressions) || __cpp_fold_expressions < 201603
|
||||
#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*/) {
|
||||
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
|
||||
@@ -41,7 +66,7 @@ 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*/) {
|
||||
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
|
||||
@@ -50,17 +75,15 @@ void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type
|
||||
}
|
||||
#else
|
||||
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*/) {
|
||||
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>
|
||||
void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type /*move_values*/) {
|
||||
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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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 <functional>
|
||||
#include <cstdint>
|
||||
|
||||
#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 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2019-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2019-2026 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,13 +10,15 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <memory> // std::addressof
|
||||
#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 {
|
||||
|
||||
@@ -42,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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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,35 +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)
|
||||
// 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)
|
||||
// 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)
|
||||
// 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)
|
||||
// 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)
|
||||
// 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...>,
|
||||
@@ -88,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; }
|
||||
};
|
||||
|
||||
|
||||
@@ -126,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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2019-2026 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 {
|
||||
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
// Copyright (c) 2019-2022 Antony Polukhin.
|
||||
// Copyright (c) 2019-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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) {
|
||||
@@ -130,9 +134,13 @@ std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& i
|
||||
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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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
|
||||
|
||||
10
index.html
10
index.html
@@ -1,16 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (c) 2014-2022 Antony Polukhin
|
||||
Copyright (c) 2014-2026 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=https://www.boost.org/doc/libs/master/doc/html/boost_pfr.html">
|
||||
<meta http-equiv="refresh" content="0; url=../../doc/html/boost_pfr.html">
|
||||
<title>Boost.Stacktrace</title>
|
||||
<style>
|
||||
body {
|
||||
@@ -26,10 +28,10 @@
|
||||
<body>
|
||||
<p>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="https://www.boost.org/doc/libs/master/doc/html/boost_pfr.html">https://www.boost.org/doc/libs/master/doc/html/boost_pfr.html</a>
|
||||
<a href="../../doc/html/boost_pfr.html">../../doc/html/boost_pfr.html</a>
|
||||
</p>
|
||||
<p>
|
||||
© 2014-2022 Antony Polukhin
|
||||
© 2014-2024 Antony Polukhin
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2016-2022 Antony Polukhin
|
||||
# Copyright (c) 2016-2026 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-2026 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()))
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2021 Antony Polukhin
|
||||
# Copyright (c) 2021-2026 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}/*
|
||||
@@ -24,41 +26,83 @@ rm ${TARGET_PATH}/misc/strip_boost_namespace.sh
|
||||
rm -rf ${TARGET_PATH}/meta
|
||||
|
||||
echo "***** Changing sources"
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|namespace boost { ||g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|namespace boost {||g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|} // namespace boost::| // namespace |g'
|
||||
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} -type f | xargs sed -i 's/::boost::pfr/::pfr/g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's/boost::pfr/pfr/g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's/BOOST_PFR_/PFR_/g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|boost/pfr|pfr|g'
|
||||
|
||||
find ${TARGET_PATH}/doc -type f | xargs sed -i 's|boost.pfr.|pfr.|g'
|
||||
find ${TARGET_PATH}/doc -type f | xargs sed -i '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 g++-9 -std=c++17 -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
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 g++-9 -std=c++17 -DPFR_USE_LOOPHOLE=1 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
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 g++-9 -std=c++17 -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/get.cpp && ./a.out > /dev/null; then
|
||||
echo -e ", OK"
|
||||
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 -e ", FAIL"
|
||||
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 "***** Done"
|
||||
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-2026 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-2026 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-2026 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-2026 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-2026 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 ;
|
||||
@@ -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-2026 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,18 +1,28 @@
|
||||
// Copyright (c) 2016-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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,22 +1,29 @@
|
||||
# Copyright (C) 2016-2022 Antony Polukhin.
|
||||
# Copyright (C) 2016-2026 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
|
||||
<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
|
||||
{
|
||||
@@ -35,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 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 ]
|
||||
@@ -60,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 =
|
||||
@@ -73,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 =
|
||||
@@ -95,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 ] ;
|
||||
@@ -129,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-2026 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-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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) 2021 Denis Mikhailov
|
||||
// Copyright (c) 2021 Antony Polukhin
|
||||
// Copyright (c) 2021-2026 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) 2021 Antony Polukhin
|
||||
// Copyright (c) 2021-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2020-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2020-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2026 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-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2020-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2019-2026 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-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2019-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2018-2026 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-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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)
|
||||
@@ -56,6 +56,21 @@ struct simple {
|
||||
|
||||
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;
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2022 Antony Polukhin
|
||||
// Copyright (c) 2016-2026 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 {
|
||||
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-2026 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