mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
79 Commits
tuple_get_
...
2.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
81
.github/workflows/ci.yml
vendored
81
.github/workflows/ci.yml
vendored
@@ -17,30 +17,41 @@ 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-12 # Do not remove! It is the only toolset that tests misc/strip_boost_namespace.sh
|
||||
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
|
||||
- toolset: gcc-9
|
||||
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"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-9"
|
||||
- toolset: clang-14
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-22.04
|
||||
- toolset: clang-13
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-22.04
|
||||
# - 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"
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -76,11 +87,6 @@ jobs:
|
||||
./b2 -d0 headers
|
||||
./b2 -j4 variant=debug tools/inspect/build
|
||||
|
||||
- name: Create user-config.jam
|
||||
if: matrix.compiler
|
||||
run: |
|
||||
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
@@ -88,7 +94,7 @@ jobs:
|
||||
dist/bin/inspect libs/$LIBRARY
|
||||
|
||||
- name: Test boost namespace stripping
|
||||
if: ${{matrix.toolset == 'gcc-9'}}
|
||||
if: ${{matrix.toolset == 'gcc-12'}}
|
||||
run: ../boost-root/libs/$LIBRARY/misc/strip_boost_namespace.sh
|
||||
|
||||
- name: Prepare coverage data
|
||||
@@ -98,9 +104,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,20 +130,21 @@ 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.0
|
||||
cxxstd: "14,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
threads: "-j3"
|
||||
- toolset: gcc
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
addrmd: 64
|
||||
os: windows-2019
|
||||
threads: "-j3"
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "20,latest"
|
||||
addrmd: 64
|
||||
os: windows-2022
|
||||
threads: "-j1"
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -170,7 +177,7 @@ jobs:
|
||||
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 ${{matrix.threads}} libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
|
||||
|
||||
finish:
|
||||
needs: posix
|
||||
|
||||
@@ -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++
|
||||
|
||||
@@ -32,9 +32,12 @@ 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\" \\
|
||||
"
|
||||
;
|
||||
|
||||
@@ -44,7 +47,7 @@ doxygen autodoc_pfr
|
||||
[ glob ../../../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,7 +55,7 @@ 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=https://www.boost.org/doc/libs/1_81_0
|
||||
#<xsl:param>boost.root=../../../.
|
||||
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
;
|
||||
|
||||
92
doc/pfr.qbk
92
doc/pfr.qbk
@@ -1,6 +1,6 @@
|
||||
[library Boost.PFR
|
||||
[quickbook 1.6]
|
||||
[version 2.0]
|
||||
[version 2.2]
|
||||
[copyright 2016-2023 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
@@ -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<std::is_aggregate_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,15 +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]
|
||||
|
||||
@@ -187,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] ]
|
||||
[
|
||||
@@ -253,6 +274,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?]
|
||||
@@ -432,12 +454,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:
|
||||
|
||||
@@ -459,6 +490,11 @@ 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 a `SimpleAggregate` with non-internal linkage (with aggregats that could be used as `extern T t;`).
|
||||
Do not use this functionality with anonymous structures, local structures
|
||||
or a structure defined inside anonymous namespace as the behavior tends to be non-portable.
|
||||
|
||||
|
||||
[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:
|
||||
@@ -469,6 +505,9 @@ By default Boost.PFR [*auto-detects your compiler abilities] and automatically d
|
||||
[[*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. ]]
|
||||
]
|
||||
|
||||
@@ -486,6 +525,29 @@ The Boost.PFRs reflection has some limitations that depend on a C++ Standard and
|
||||
* 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]
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -91,7 +91,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 +100,29 @@ 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
|
||||
//]
|
||||
}
|
||||
|
||||
// Disabled from testing since it's unportable
|
||||
#if 0
|
||||
{
|
||||
//[pfr_quick_examples_get_name
|
||||
// Get name of field by index
|
||||
|
||||
struct sample {
|
||||
int f1;
|
||||
long f2;
|
||||
};
|
||||
|
||||
std::cout << boost::pfr::get_name<0, sample>()
|
||||
<< boost::pfr::get_name<1, sample>(); // Outputs: f1 f2
|
||||
//]
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
{
|
||||
//[pfr_quick_examples_structure_to_tuple
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#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>
|
||||
|
||||
@@ -98,6 +98,33 @@
|
||||
# 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)
|
||||
# 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]]
|
||||
|
||||
@@ -30,20 +30,25 @@
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// \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) );
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(T& val
|
||||
@@ -71,6 +76,40 @@ constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::val
|
||||
}
|
||||
|
||||
|
||||
/// \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
|
||||
, 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
|
||||
/// \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");
|
||||
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) ));
|
||||
}
|
||||
|
||||
|
||||
/// \brief `tuple_element` has a member typedef `type` that returns the type of a field with index I in \aggregate T.
|
||||
///
|
||||
/// \b Example:
|
||||
@@ -181,7 +220,7 @@ constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference<T&&
|
||||
/// assert(sum == 42);
|
||||
/// \endcode
|
||||
template <class T, class F>
|
||||
void for_each_field(T&& value, F&& func) {
|
||||
constexpr 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(
|
||||
|
||||
88
include/boost/pfr/core_name.hpp
Normal file
88
include/boost/pfr/core_name.hpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// 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>
|
||||
|
||||
#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 <cstddef> // for std::size_t
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
/// \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 {
|
||||
|
||||
/// \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> >(),
|
||||
1L
|
||||
);
|
||||
}
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_CORE_NAME_HPP
|
||||
|
||||
@@ -53,7 +53,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;
|
||||
@@ -346,7 +346,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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -57,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."
|
||||
|
||||
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
|
||||
|
||||
43
include/boost/pfr/detail/core_name14_disabled.hpp
Normal file
43
include/boost/pfr/detail/core_name14_disabled.hpp
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
|
||||
//
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||
|
||||
242
include/boost/pfr/detail/core_name20_static.hpp
Normal file
242
include/boost/pfr/detail/core_name20_static.hpp
Normal file
@@ -0,0 +1,242 @@
|
||||
// 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/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/stdarray.hpp>
|
||||
#include <boost/pfr/detail/fake_object.hpp>
|
||||
#include <type_traits>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <memory> // for std::addressof
|
||||
|
||||
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(
|
||||
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: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 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>()>{});
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||
|
||||
25
include/boost/pfr/detail/fake_object.hpp
Normal file
25
include/boost/pfr/detail/fake_object.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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_FAKE_OBJECT_HPP
|
||||
#define BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T>
|
||||
extern const T fake_object;
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
|
||||
@@ -20,18 +20,18 @@ 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
|
||||
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 +41,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,12 +50,12 @@ 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
|
||||
|
||||
@@ -42,7 +42,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)
|
||||
|
||||
@@ -20,6 +20,8 @@ constexpr decltype(is_reflectable<T, WhatFor>::value) possible_reflectable(long)
|
||||
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)
|
||||
@@ -30,6 +32,16 @@ constexpr bool possible_reflectable(int) noexcept {
|
||||
# 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
|
||||
|
||||
@@ -79,6 +79,45 @@ constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class ...Values>
|
||||
struct tuple: tuple_base<
|
||||
detail::index_sequence_for<Values...>,
|
||||
@@ -88,6 +127,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 +168,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
|
||||
|
||||
|
||||
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 <utility> // metaprogramming stuff
|
||||
#include <array>
|
||||
#include <type_traits> // for std::common_type_t
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class... Types>
|
||||
constexpr auto make_stdarray(const Types&... t) noexcept {
|
||||
return std::array<std::common_type_t<Types...>, sizeof...(Types)>{t...};
|
||||
}
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdarray_from_tietuple(const T& t, std::index_sequence<I...>, int) noexcept {
|
||||
return detail::make_stdarray(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto make_stdarray_from_tietuple(const T&, std::index_sequence<>, long) noexcept {
|
||||
return std::array<std::nullptr_t, 0>{};
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_STDARRAY_HPP
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace detail {
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/// \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 +93,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 +108,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 +123,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 +138,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 +153,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 +168,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>
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// Has a static const member variable `value` when it 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.
|
||||
/// 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
|
||||
@@ -29,11 +29,9 @@ namespace boost { namespace pfr {
|
||||
/// 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 has more priority than is_implicitly_reflectable,
|
||||
/// because is_reflectable is more sharp than is_implicitly_reflectable
|
||||
///
|
||||
/// \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 { /* do not has 'value' because value is unknown */ };
|
||||
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
|
||||
@@ -46,17 +44,15 @@ struct is_reflectable<volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatF
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<const volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
|
||||
/// Checks the input type for the potential to be reflected.
|
||||
/// Specialize is_reflectable if you are disagree with is_implicitly_reflectable's default decision.
|
||||
/// 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 are disagree with is_implicitly_reflectable_v's default decision.
|
||||
/// 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;
|
||||
#endif
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
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,7 +28,7 @@
|
||||
<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-2023 Antony Polukhin
|
||||
|
||||
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()))
|
||||
|
||||
@@ -39,26 +39,46 @@ find ${TARGET_PATH}/doc -type f | xargs sed -i '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 g++-12 -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
|
||||
echo -n ", OK"
|
||||
if g++-12 -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"
|
||||
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
|
||||
if g++-12 -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 -e ", OK"
|
||||
else
|
||||
echo -e ", FAIL"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
if g++-12 -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 g++-12 -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 g++-12 -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 -e ", OK"
|
||||
else
|
||||
echo -e ", FAIL"
|
||||
exit 7
|
||||
fi
|
||||
|
||||
rm a.out || :
|
||||
|
||||
echo "***** Done"
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
#
|
||||
|
||||
build-project config ;
|
||||
build-project core ;
|
||||
build-project core ;
|
||||
build-project core_name ;
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
// 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/config.hpp> // inclusion of an another PFR header may fail when BOOST_PFR_ENABLED=0
|
||||
#include <boost/pfr/config.hpp>
|
||||
#if BOOST_PFR_ENABLED
|
||||
#include <boost/pfr.hpp>
|
||||
#endif
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -14,6 +18,9 @@ int main() {
|
||||
<< "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
|
||||
|
||||
@@ -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;
|
||||
|
||||
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-2023 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// Test case for https://github.com/boostorg/pfr/issues/33
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
@@ -14,13 +15,23 @@ struct TestStruct {
|
||||
std::vector<std::unique_ptr<int>> vec;
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
TestStruct temp;
|
||||
temp.vec.emplace_back();
|
||||
|
||||
// FIXME: https://github.com/boostorg/pfr/issues/131
|
||||
#if defined(__clang__) && __cplusplus >= 202002L
|
||||
|
||||
# if BOOST_PFR_USE_LOOPHOLE == 0 && BOOST_PFR_USE_CPP17 == 0
|
||||
# error This test should fail on classic engine
|
||||
#endif
|
||||
|
||||
#else
|
||||
boost::pfr::for_each_field(temp, [](const auto& value) {
|
||||
BOOST_TEST_EQ(value.size(), 1);
|
||||
});
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@ struct X {
|
||||
struct S { X x0; X x1; int x2; X x3; };
|
||||
|
||||
int main() {
|
||||
|
||||
#if BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
|
||||
// MSVC-14.3 fails this test
|
||||
#if !defined(_MSC_VER) || _MSC_VER < 1930 || _MSC_VER > 1939
|
||||
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
|
||||
|
||||
struct S5_0 { int x0; int x1; int x2; int x3; X x4; };
|
||||
@@ -38,6 +42,8 @@ int main() {
|
||||
|
||||
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
|
||||
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
|
||||
#endif
|
||||
|
||||
#endif // #if BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
|
||||
return boost::report_errors();
|
||||
|
||||
60
test/core_name/Jamfile.v2
Normal file
60
test/core_name/Jamfile.v2
Normal file
@@ -0,0 +1,60 @@
|
||||
# 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 testing ;
|
||||
import ../../config/checks/config : requires ;
|
||||
|
||||
########## BEGIN of helpers to detect C++20 features support
|
||||
|
||||
actions mp_simple_run_action
|
||||
{
|
||||
$(>) > $(<)
|
||||
}
|
||||
|
||||
rule mp-run-simple ( sources + : args * : input-files * : requirements * : target-name )
|
||||
{
|
||||
exe $(target-name)_exe : $(sources) : $(requirements) ;
|
||||
explicit $(target-name)_exe ;
|
||||
make $(target-name).output : $(target-name)_exe : @mp_simple_run_action ;
|
||||
explicit $(target-name).output ;
|
||||
alias $(target-name) : $(target-name).output ;
|
||||
}
|
||||
|
||||
mp-run-simple cxx20_address_of_non_static_member_tplarg_detection.cpp : : : : compiler_supports_cxx20_address_of_non_static_member_tplarg ;
|
||||
explicit compiler_supports_cxx20_address_of_non_static_member_tplarg ;
|
||||
|
||||
mp-run-simple cxx20_nontype_tplarg_detection.cpp : : : : compiler_supports_cxx20_nontype_tplarg ;
|
||||
explicit compiler_supports_cxx20_nontype_tplarg ;
|
||||
|
||||
########## END of helpers to detect C++20 features support
|
||||
|
||||
project
|
||||
: source-location .
|
||||
: requirements
|
||||
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
|
||||
[ check-target-builds ../core_name//compiler_supports_cxx20_address_of_non_static_member_tplarg : : [ check-target-builds ../core_name//compiler_supports_cxx20_nontype_tplarg : : <build>no ] ]
|
||||
;
|
||||
|
||||
test-suite pfr_name_tests
|
||||
:
|
||||
[ run print_name.cpp : : : <test-info>always_show_run_output ]
|
||||
;
|
||||
|
||||
for local source_file in [ glob ./run/*.cpp ]
|
||||
{
|
||||
pfr_name_tests += [ run $(source_file) : : : <toolset>msvc:<cxxflags>"/utf-8" <toolset>msvc:<cxxflags>"/bigobj" : ] ;
|
||||
}
|
||||
|
||||
for local source_file in [ glob ./compile-fail/*.cpp ]
|
||||
{
|
||||
pfr_name_tests += [ compile-fail $(source_file) : : ] ;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
#define BOOST_PFR_FUNCTION_SIGNATURE ""
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::get_name<0, A>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
#define BOOST_PFR_CORE_NAME_ENABLED 0
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::get_name<0, A>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
#define BOOST_PFR_CORE_NAME_ENABLED 0
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::names_as_array<A>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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/core_name.hpp>
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::get_name<0, int[10]>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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/core_name.hpp>
|
||||
|
||||
union test_union {
|
||||
const char* c;
|
||||
int i;
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::get_name<0, test_union>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
#define BOOST_PFR_FUNCTION_SIGNATURE "dummy"
|
||||
#define BOOST_PFR_CORE_NAME_PARSING (0,0,"")
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::get_name<0, A>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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/core_name.hpp>
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::names_as_array<int[10]>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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/core_name.hpp>
|
||||
|
||||
union test_union {
|
||||
const char* c;
|
||||
int i;
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::names_as_array<test_union>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
#define BOOST_PFR_FUNCTION_SIGNATURE "dummy"
|
||||
#define BOOST_PFR_CORE_NAME_PARSING (3,2,"")
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::get_name<0, A>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
25
test/core_name/compile-fail/poor_fields_name.cpp
Normal file
25
test/core_name/compile-fail/poor_fields_name.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
#define BOOST_PFR_FUNCTION_SIGNATURE " *[field] "
|
||||
#define BOOST_PFR_CORE_NAME_PARSING (3,2,"")
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
BOOST_TEST_EQ( (boost::pfr::get_name<0,A>()), "field");
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
template <int* p>
|
||||
class X {};
|
||||
|
||||
struct S
|
||||
{
|
||||
int m;
|
||||
} s;
|
||||
|
||||
X<&s.m> x4;
|
||||
|
||||
int main() {}
|
||||
|
||||
|
||||
32
test/core_name/cxx20_nontype_tplarg_detection.cpp
Normal file
32
test/core_name/cxx20_nontype_tplarg_detection.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
template <auto p>
|
||||
class X {};
|
||||
|
||||
template <class T>
|
||||
struct Store
|
||||
{
|
||||
T v;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Store(T) -> Store<T>;
|
||||
|
||||
struct S
|
||||
{
|
||||
int m;
|
||||
} s;
|
||||
|
||||
X<Store{&s.m}> x4;
|
||||
|
||||
int main() {}
|
||||
|
||||
|
||||
44
test/core_name/print_name.cpp
Normal file
44
test/core_name/print_name.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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 <iostream>
|
||||
|
||||
// This cpp file:
|
||||
// * tests BOOST_PFR_CORE_NAME_PARSING macro
|
||||
// * outputs full name of the function so that PFRs extraction of field name could be adjust to new compiler without requesting regression tester's help
|
||||
#ifndef BOOST_PFR_CORE_NAME_PARSING
|
||||
#define BOOST_PFR_CORE_NAME_PARSING (0,0,"")
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
namespace user_defined_namespace {
|
||||
struct user_defined_class { int user_defined_field; };
|
||||
}
|
||||
|
||||
using namespace boost::pfr;
|
||||
|
||||
// Cloned from core_name20_static.hpp but removed the sanity check
|
||||
template <class T, std::size_t I>
|
||||
inline constexpr auto no_check_stored_name_of_field = detail::name_of_field_impl<T,
|
||||
detail::make_clang_wrapper(std::addressof(detail::sequence_tuple::get<I>(
|
||||
detail::tie_as_tuple(detail::fake_object<T>)
|
||||
)))
|
||||
>();
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "user_defined_namespace::user_defined_class::user_defined_field: "
|
||||
<< no_check_stored_name_of_field<user_defined_namespace::user_defined_class, 0>.data() << '\n';
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
86
test/core_name/run/fields_names.cpp
Normal file
86
test/core_name/run/fields_names.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// 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/core_name.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <functional> // for std::reference_wrapper
|
||||
#include <string>
|
||||
|
||||
namespace testing {
|
||||
|
||||
struct nonconstexpr {
|
||||
nonconstexpr() {};
|
||||
};
|
||||
|
||||
struct Aggregate {
|
||||
int member1;
|
||||
nonconstexpr this_is_a_name;
|
||||
std::reference_wrapper<char> c;
|
||||
std::string Forth;
|
||||
};
|
||||
|
||||
struct A {
|
||||
int first;
|
||||
int second;
|
||||
};
|
||||
|
||||
struct empty {};
|
||||
|
||||
void test_get_name_by_id() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate>())), "member1");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<1, Aggregate>())), "this_is_a_name");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<2, Aggregate>())), "c");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<3, Aggregate>())), "Forth");
|
||||
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, A>())), "first");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<1, A>())), "second");
|
||||
}
|
||||
|
||||
void test_get_name_by_type() {
|
||||
// FIXME: implement this
|
||||
// using char_ref = std::reference_wrapper<char>;
|
||||
// BOOST_TEST_EQ( ((boost::pfr::get_name<int, Aggregate>())), "member1");
|
||||
// BOOST_TEST_EQ( ((boost::pfr::get_name<nonconstexpr, Aggregate>())), "this_is_a_name");
|
||||
// BOOST_TEST_EQ( ((boost::pfr::get_name<char_ref, Aggregate>())), "c");
|
||||
}
|
||||
|
||||
void test_names_as_array() {
|
||||
const auto expected = std::array<std::string_view, 4>{
|
||||
"member1",
|
||||
"this_is_a_name",
|
||||
"c",
|
||||
"Forth"
|
||||
};
|
||||
const auto value = boost::pfr::names_as_array<Aggregate>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_names_as_array_for_empty() {
|
||||
const auto value = boost::pfr::names_as_array<empty>();
|
||||
BOOST_TEST_EQ(value.size(), 0);
|
||||
BOOST_TEST_EQ(value.empty(), true);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_get_name_by_id();
|
||||
testing::test_get_name_by_type();
|
||||
testing::test_names_as_array();
|
||||
testing::test_names_as_array_for_empty();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
170
test/core_name/run/fields_names_big.cpp
Normal file
170
test/core_name/run/fields_names_big.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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...};
|
||||
}
|
||||
|
||||
struct Aggregate1 {
|
||||
int EXuT_0EBItazIzOuovbOSyOYGqbJw1uQ;
|
||||
|
||||
};
|
||||
struct Aggregate2 {
|
||||
int SnihXdx4VbVTcwKm2PGOy8gBYi;
|
||||
int l_hKC0UCDgf9akyA6pr1IG;
|
||||
|
||||
};
|
||||
struct Aggregate3 {
|
||||
int GWYXwjwOCC5uOWkmZjrjk95yaOQbVfUbSJRCoQoRyPXjzp7x2c7WMwvck0JeOg;
|
||||
int xdtwasd3bFi2mErdk64LyyWKcOb5gudT50eCBMUHraYYmd8Yxp9M0pO1DmDHWQZ4LEshxseqUjzoTeuwnVwA6uvStNpN0ZtZ;
|
||||
int shqTJk7vA32s2DQB5o7TyecNLMHLUogzWYO_NwRsgX;
|
||||
|
||||
};
|
||||
struct Aggregate4 {
|
||||
int ofYcwHz8V6YMDPsHqyIB5TVZckFc3cK0Da;
|
||||
int HiGE0sOlKCO;
|
||||
int F5Nrv0LUdUSmrzLgPmtENIEe5uJQyRXC0owDVh9IjRBdA_aSEqiMx_EhWXEkbddK5MCgCv223s9EXlMc55ByxpG6XYbXS6nHywEy;
|
||||
int emjjbXYK;
|
||||
|
||||
};
|
||||
struct Aggregate5 {
|
||||
int M0u7SIZSVWJ0KqQygT_6npmZv1XzZI5dJcwjQuqq6lIdlSJSpnAKhOg82qyVywwNq3cvvmnmAv7;
|
||||
int SXEUFB6z;
|
||||
int tDxT;
|
||||
int sV2m6xg3MxKN1Xln2dXyBh8rkF7lUUfHIK8nK4FRzru2DXeT;
|
||||
int ycEXe3x03PvbXqFJzOKMq8i4XLAZfyY2i4HONhv1Wx_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
void test_get_name_1() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate1>())), "EXuT_0EBItazIzOuovbOSyOYGqbJw1uQ");
|
||||
|
||||
}
|
||||
void test_get_name_2() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate2>())), "SnihXdx4VbVTcwKm2PGOy8gBYi");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<1, Aggregate2>())), "l_hKC0UCDgf9akyA6pr1IG");
|
||||
|
||||
}
|
||||
void test_get_name_3() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate3>())), "GWYXwjwOCC5uOWkmZjrjk95yaOQbVfUbSJRCoQoRyPXjzp7x2c7WMwvck0JeOg");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<1, Aggregate3>())), "xdtwasd3bFi2mErdk64LyyWKcOb5gudT50eCBMUHraYYmd8Yxp9M0pO1DmDHWQZ4LEshxseqUjzoTeuwnVwA6uvStNpN0ZtZ");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<2, Aggregate3>())), "shqTJk7vA32s2DQB5o7TyecNLMHLUogzWYO_NwRsgX");
|
||||
|
||||
}
|
||||
void test_get_name_4() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate4>())), "ofYcwHz8V6YMDPsHqyIB5TVZckFc3cK0Da");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<1, Aggregate4>())), "HiGE0sOlKCO");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<2, Aggregate4>())), "F5Nrv0LUdUSmrzLgPmtENIEe5uJQyRXC0owDVh9IjRBdA_aSEqiMx_EhWXEkbddK5MCgCv223s9EXlMc55ByxpG6XYbXS6nHywEy");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<3, Aggregate4>())), "emjjbXYK");
|
||||
|
||||
}
|
||||
void test_get_name_5() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate5>())), "M0u7SIZSVWJ0KqQygT_6npmZv1XzZI5dJcwjQuqq6lIdlSJSpnAKhOg82qyVywwNq3cvvmnmAv7");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<1, Aggregate5>())), "SXEUFB6z");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<2, Aggregate5>())), "tDxT");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<3, Aggregate5>())), "sV2m6xg3MxKN1Xln2dXyBh8rkF7lUUfHIK8nK4FRzru2DXeT");
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<4, Aggregate5>())), "ycEXe3x03PvbXqFJzOKMq8i4XLAZfyY2i4HONhv1Wx_");
|
||||
|
||||
}
|
||||
|
||||
|
||||
void test_names_as_array_1() {
|
||||
const auto expected = make_stdarray(
|
||||
std::string_view{"EXuT_0EBItazIzOuovbOSyOYGqbJw1uQ"}
|
||||
|
||||
);
|
||||
const auto value = boost::pfr::names_as_array<Aggregate1>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
void test_names_as_array_2() {
|
||||
const auto expected = make_stdarray(
|
||||
std::string_view{"SnihXdx4VbVTcwKm2PGOy8gBYi"}
|
||||
, std::string_view{"l_hKC0UCDgf9akyA6pr1IG"}
|
||||
|
||||
);
|
||||
const auto value = boost::pfr::names_as_array<Aggregate2>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
void test_names_as_array_3() {
|
||||
const auto expected = make_stdarray(
|
||||
std::string_view{"GWYXwjwOCC5uOWkmZjrjk95yaOQbVfUbSJRCoQoRyPXjzp7x2c7WMwvck0JeOg"}
|
||||
, std::string_view{"xdtwasd3bFi2mErdk64LyyWKcOb5gudT50eCBMUHraYYmd8Yxp9M0pO1DmDHWQZ4LEshxseqUjzoTeuwnVwA6uvStNpN0ZtZ"}
|
||||
, std::string_view{"shqTJk7vA32s2DQB5o7TyecNLMHLUogzWYO_NwRsgX"}
|
||||
|
||||
);
|
||||
const auto value = boost::pfr::names_as_array<Aggregate3>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
void test_names_as_array_4() {
|
||||
const auto expected = make_stdarray(
|
||||
std::string_view{"ofYcwHz8V6YMDPsHqyIB5TVZckFc3cK0Da"}
|
||||
, std::string_view{"HiGE0sOlKCO"}
|
||||
, std::string_view{"F5Nrv0LUdUSmrzLgPmtENIEe5uJQyRXC0owDVh9IjRBdA_aSEqiMx_EhWXEkbddK5MCgCv223s9EXlMc55ByxpG6XYbXS6nHywEy"}
|
||||
, std::string_view{"emjjbXYK"}
|
||||
|
||||
);
|
||||
const auto value = boost::pfr::names_as_array<Aggregate4>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
void test_names_as_array_5() {
|
||||
const auto expected = make_stdarray(
|
||||
std::string_view{"M0u7SIZSVWJ0KqQygT_6npmZv1XzZI5dJcwjQuqq6lIdlSJSpnAKhOg82qyVywwNq3cvvmnmAv7"}
|
||||
, std::string_view{"SXEUFB6z"}
|
||||
, std::string_view{"tDxT"}
|
||||
, std::string_view{"sV2m6xg3MxKN1Xln2dXyBh8rkF7lUUfHIK8nK4FRzru2DXeT"}
|
||||
, std::string_view{"ycEXe3x03PvbXqFJzOKMq8i4XLAZfyY2i4HONhv1Wx_"}
|
||||
|
||||
);
|
||||
const auto value = boost::pfr::names_as_array<Aggregate5>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_get_name_1();
|
||||
testing::test_get_name_2();
|
||||
testing::test_get_name_3();
|
||||
testing::test_get_name_4();
|
||||
testing::test_get_name_5();
|
||||
|
||||
testing::test_names_as_array_1();
|
||||
testing::test_names_as_array_2();
|
||||
testing::test_names_as_array_3();
|
||||
testing::test_names_as_array_4();
|
||||
testing::test_names_as_array_5();
|
||||
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
40
test/core_name/run/fields_names_constexpr.cpp
Normal file
40
test/core_name/run/fields_names_constexpr.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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/core_name.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
struct nonconstexpr {
|
||||
nonconstexpr() {};
|
||||
};
|
||||
|
||||
struct Aggregate {
|
||||
int member1;
|
||||
nonconstexpr this_is_a_name;
|
||||
std::reference_wrapper<char> c;
|
||||
std::string Forth;
|
||||
};
|
||||
|
||||
static_assert(boost::pfr::get_name<0, Aggregate>() == "member1");
|
||||
static_assert(boost::pfr::get_name<1, Aggregate>() == "this_is_a_name");
|
||||
static_assert(boost::pfr::get_name<2, Aggregate>() == "c");
|
||||
static_assert(boost::pfr::get_name<3, Aggregate>() == "Forth");
|
||||
|
||||
constexpr auto names_array = boost::pfr::names_as_array<Aggregate>();
|
||||
static_assert(names_array.size() == 4);
|
||||
static_assert(names_array[0] == "member1");
|
||||
static_assert(names_array[1] == "this_is_a_name");
|
||||
static_assert(names_array[2] == "c");
|
||||
static_assert(names_array[3] == "Forth");
|
||||
|
||||
int main() {}
|
||||
|
||||
47
test/core_name/run/fields_names_internal_parser.cpp
Normal file
47
test/core_name/run/fields_names_internal_parser.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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/core_name.hpp>
|
||||
#include <string_view>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing {
|
||||
|
||||
constexpr std::string_view fake_func_name = " ******************** [fake_text1->fake_text2->fake_text3] **********";
|
||||
|
||||
void test_general()
|
||||
{
|
||||
namespace detail = boost::pfr::detail;
|
||||
using detail::backward;
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, "").apply(fake_func_name), "fake_text1->fake_text2->fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, backward("->")).apply(fake_func_name), "fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, "->").apply(fake_func_name), "fake_text2->fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, backward("->")).apply(fake_func_name), "fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, "->").apply(fake_func_name), "fake_text2->fake_text3");
|
||||
}
|
||||
|
||||
void test_identity_parser()
|
||||
{
|
||||
namespace detail = boost::pfr::detail;
|
||||
using detail::backward;
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, backward("")).apply(fake_func_name), fake_func_name);
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, "").apply(fake_func_name), fake_func_name);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_general();
|
||||
testing::test_identity_parser();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
44
test/core_name/run/fields_names_nonascii.cpp
Normal file
44
test/core_name/run/fields_names_nonascii.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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)
|
||||
|
||||
/* Tesing non-ASCII field names, so we have to add th following suppression:
|
||||
boost-no-inspect
|
||||
*/
|
||||
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing {
|
||||
|
||||
struct Aggregate {
|
||||
int _πривет_мир;
|
||||
};
|
||||
|
||||
void test_get_name() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate>())), "_πривет_мир");
|
||||
}
|
||||
|
||||
void test_names_as_array() {
|
||||
const auto expected = std::array<std::string_view, 1>{
|
||||
"_πривет_мир"
|
||||
};
|
||||
const auto value = boost::pfr::names_as_array<Aggregate>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_get_name();
|
||||
testing::test_names_as_array();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user