2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-20 04:42:22 +00:00

Compare commits

..

319 Commits

Author SHA1 Message Date
Antony Polukhin
50d58a2e84 Clean up and update the docs 2020-08-19 23:02:34 +03:00
Antony Polukhin
76ac44a9ca Add missing include 2020-08-19 20:41:07 +03:00
Antony Polukhin
4205a2e553 Improve diagnostics for structures with huge amount of fields 2020-08-19 19:45:05 +03:00
Antony Polukhin
89b1d45ff7 fix definition 2020-08-16 10:59:27 +03:00
Antony Polukhin
26867f47b7 fix warnings in tests 2020-08-16 10:58:36 +03:00
Antony Polukhin
b9166fd38e avoid copy-paste 2020-08-16 09:54:53 +03:00
Antony Polukhin
915bd9217c add link-time assertion to the unsafe_declval() function 2020-08-16 09:51:07 +03:00
Antony Polukhin
0885412a7d MSVC test fix 2020-08-13 21:46:06 +03:00
Antony Polukhin
86ebac6e0c reproduced and fixed the "type without linkage" error 2020-08-13 20:38:22 +03:00
Antony Polukhin
39e9b4c5fe attempt to reproduce a "type without linkage" warning 2020-08-13 18:27:00 +03:00
Antony Polukhin
01fd8db5b4 fix warning and add more tests 2020-08-13 18:13:57 +03:00
Antony Polukhin
077ea5451c Fix issues found by Boosts inspect tool 2020-07-07 09:42:19 +03:00
Antony Polukhin
3a36467d96 Typo fix 2020-07-07 09:29:27 +03:00
Antony Polukhin
3eee880972 Test on Clang-10 in C++20 mode 2020-07-07 09:28:40 +03:00
Antony Polukhin
41a22fcd21 Avoid defining complilcated is_aggregate_initializable_n if std::is_aggregate available 2020-07-07 09:28:21 +03:00
Antony Polukhin
e354ba8b25 Simplify assertions if std::is_aggregate is available 2020-07-07 09:16:06 +03:00
Antony Polukhin
7a0f5f90df Disable weird tests 2020-07-06 21:48:28 +03:00
Antony Polukhin
041b0dd226 Fix attempt 2020-07-06 21:27:25 +03:00
Antony Polukhin
ff1c5e3a7f One step closer to working C++20 solution (1) 2020-07-06 20:42:47 +03:00
Antony Polukhin
4c48a220c2 One step closer to working C++20 solution 2020-07-06 20:12:50 +03:00
Antony Polukhin
ed6fe1431d Attempt to find function that breaks GCC-10 constexpr 2020-07-06 18:45:18 +03:00
Antony Polukhin
16db439e8c More C++20 fixes 2020-07-06 18:28:19 +03:00
Antony Polukhin
c3ccb7a525 Fixes for C++20 2020-07-06 18:07:40 +03:00
Antony Polukhin
d6e44dde8f fix 2020-07-06 17:23:13 +03:00
Antony Polukhin
63b5f1f791 GCC-10 fixes 2020-07-06 17:17:00 +03:00
Antony Polukhin
dc814c7e7f build fix for GCC-10 2020-07-06 17:06:09 +03:00
Antony Polukhin
671cc3f282 typo fixed 2020-07-06 16:39:52 +03:00
Antony Polukhin
8ca6b531a6 Attempt to fix PFRs error detection on GCC-10 2020-07-06 16:30:23 +03:00
Antony Polukhin
f24698f131 Updates for C++20 mode (workaround compiler idiosyncrasies 3) 2020-07-06 14:24:02 +03:00
Antony Polukhin
950e4aa0ee disable more weird tests 2020-07-06 14:08:50 +03:00
Antony Polukhin
b9bea47e4f Comment out weird test 2020-07-06 13:54:05 +03:00
Antony Polukhin
6d1fc03667 Avoid using deprecated std::is_pod 2020-07-06 13:40:24 +03:00
Antony Polukhin
ba65dd23ef Updates for C++20 mode (workaround compiler idiosyncrasies 2) 2020-07-06 13:22:17 +03:00
Antony Polukhin
5b28535b8e Updates for C++20 mode (workaround compiler idiosyncrasies) 2020-07-06 13:01:40 +03:00
Antony Polukhin
802c7033ba Updates for C++20 mode (refs #44) 2020-07-06 12:41:53 +03:00
Antony Polukhin
4a593c0628 CI experiment: use GCC-10 2020-07-06 12:10:12 +03:00
Antony Polukhin
b603f6fdef CI experiment: use Bionic 2020-07-06 11:49:04 +03:00
Antony Polukhin
1a620d36dd CI fixes (1) 2020-07-06 11:35:17 +03:00
Antony Polukhin
93cb89cf05 revert the gcc-10 CI attempt 2020-07-05 19:15:47 +03:00
Antony Polukhin
d2964544a4 attempt to add GCC-10 to CI 2020-07-05 19:08:57 +03:00
Antony Polukhin
74c460fd18 update copyright 2020-01-18 13:52:29 +03:00
Antony Polukhin
abb467c0e2 Merge pull request #41 from ofats/fix-mask-typo
Fix typo in extension_mask in core14_classics.hpp.
2019-09-02 16:59:33 +03:00
ofats
a22f9bd5ec Fix typo in extension_mask in core14_classics.hpp. 2019-09-02 15:17:44 +03:00
Antony Polukhin
b53c54688f Merge pull request #40 from ofats/binsearch-overflow
Fix possible overflow during binary search in detect_fields_count.
2019-09-01 23:13:00 +03:00
ofats
aeaca7ece5 Fix possible overflow during binary search in detect_fields_count. 2019-08-30 19:55:47 +03:00
Antony Polukhin
a651c13c19 start using [ requires XXX ] in Jamfile 2019-08-12 22:59:35 +03:00
Antony Polukhin
eca39f2c5f Add missing comment 2019-07-29 09:04:03 +03:00
Antony Polukhin
74a62a24af Add some tests for #39 2019-07-28 23:08:10 +03:00
Antony Polukhin
8f5aaf41ce Fix GCC warning 'constexpr function wihtout a body' 2019-07-28 23:06:43 +03:00
Antony Polukhin
ff778d5430 Add information about C++14 limitations (refs #39) 2019-07-28 16:45:06 +03:00
Antony Polukhin
449d6769a2 Fix docs rendering on narrow screens 2019-07-28 12:44:08 +03:00
Antony Polukhin
72df78ad28 Fix alignment detection for cygwin 2019-06-20 09:14:28 +03:00
Antony Polukhin
f4ce2d25f1 workaround issue with pre-GCC-8 on a 32bit platforms 2019-06-19 23:37:40 +03:00
Antony Polukhin
82658caf7c Attempt to workaround MSVC limitations 2019-05-30 13:25:28 +03:00
Antony Polukhin
d9ade9ca8d Attempt to workaround MSVC issues with templates 2019-05-04 12:16:20 +03:00
Antony Polukhin
c7ea287362 Test MSVC with /permissive- 2019-05-03 22:03:24 +03:00
Antony Polukhin
48180bd6bf Attempt to fix clang-8 build 2019-05-03 20:34:24 +03:00
Antony Polukhin
f64ee68961 Use Boost testing 2019-05-03 18:03:03 +03:00
Antony Polukhin
eac7e089cf Fix test 2019-05-02 21:14:07 +03:00
Antony Polukhin
07e155aa53 Fixing clang-8 build 2019-05-02 17:59:09 +03:00
Antony Polukhin
2b75edf571 Another clang-8 build fix 2019-05-02 16:22:44 +03:00
Antony Polukhin
6c576cd436 Fix clang-8 build (another attempt) 2019-05-02 16:01:32 +03:00
Antony Polukhin
72e218fb2e Another attempt to fix clang-8 build 2019-05-02 15:00:33 +03:00
Antony Polukhin
e2e6a2d13f Workaround clang-8 build failure 2019-05-02 14:37:01 +03:00
Antony Polukhin
e1e74817ee Update .travis.yml 2019-05-02 12:19:17 +03:00
Antony Polukhin
291ca069ca Update .travis.yml 2019-05-02 11:17:47 +03:00
Antony Polukhin
68d04a99a7 Do not run loophole tests on clang-8 and above 2019-05-01 20:04:22 +03:00
Antony Polukhin
8a1471a387 Do not use loophole on clang-8 and above 2019-05-01 19:57:44 +03:00
Antony Polukhin
d84cd84c34 CI fixes 2019-05-01 19:30:04 +03:00
Antony Polukhin
259cc9470f CI fixes 2019-05-01 16:56:00 +03:00
Antony Polukhin
c2adec8743 Update .travis.yml 2019-05-01 13:34:29 +03:00
Antony Polukhin
afa3cc8483 Fixes after MSVC workaround 2019-05-01 12:46:31 +03:00
Antony Polukhin
556e3f479a Apply MSVC workarounds from #21 2019-05-01 11:00:32 +03:00
Antony Polukhin
ceb9e352b0 Update appveyor.yml 2019-04-24 10:12:18 +03:00
Antony Polukhin
447bfcc3c3 Workaround msvc 2019 limitations 2019-04-24 09:45:39 +03:00
Antony Polukhin
6f35c872c8 add link to another video that describes PFR library internals 2019-01-30 23:05:45 +03:00
Antony Polukhin
6b03224636 Fix reflection of Standard Library containers in C++14 loophole (fixes #33) 2019-01-23 23:26:01 +03:00
Antony Polukhin
8e9ac75fd7 Bigger checkout depth in scripts 2019-01-08 01:21:32 +03:00
Antony Polukhin
e993693cb4 Add MSVC runs with c++17 and c++latest flags 2019-01-07 23:01:28 +03:00
Antony Polukhin
8bb5eb2f33 Update copyright 2019-01-06 20:46:45 +03:00
Antony Polukhin
129d8d9471 Merge pull request #32 from apolukhin/feature/reflecting-unique
Fixes #30
2019-01-05 13:42:27 +03:00
Antony Polukhin
9520aa703f Use MSVC implementation of make_integer_sequence 2019-01-05 02:23:34 +03:00
Antony Polukhin
dd556977c0 Comment out bogus test and implement a human readable loophole_type_list lazy evaluation (that also may workaround the MSVC crashes) 2019-01-04 21:29:56 +03:00
Antony Polukhin
7e299067eb fix typos in Jamfile and rename some test files 2019-01-03 22:25:44 +03:00
Antony Polukhin
f7df20f4f8 workaround bugs in b2 2019-01-03 21:28:58 +03:00
Antony Polukhin
7f506ece26 Fix clang compilation 2019-01-03 12:22:19 +03:00
Antony Polukhin
eebc3241e1 More tests and update comment 2019-01-03 12:15:46 +03:00
Antony Polukhin
38cfc1dbbd Add test case from #30 and make it work 2019-01-03 11:57:02 +03:00
Antony Polukhin
cf3094e63e Restore UBSAN 2018-12-08 11:33:53 +03:00
Antony Polukhin
c4b5538024 Add slightly modified test for #21 2018-12-02 17:59:03 +03:00
Antony Polukhin
aa663303ed Shorten the .travisci 2018-11-29 21:13:41 +03:00
Antony Polukhin
d665911f2c Do not use MinGW 32 in Appweyor CI 2018-11-24 16:58:42 +03:00
Antony Polukhin
46d2f2f91b Shorten the names for the sake of cygwin 2018-11-24 13:03:13 +03:00
Antony Polukhin
aaa47e7858 Disable clang-4 + libstdc++ testing in TravisCI 2018-11-24 12:33:12 +03:00
Antony Polukhin
1f463688ea Revert "ci fixes (1)"
This reverts commit 3229e76d48.
2018-11-23 23:20:53 +03:00
Antony Polukhin
5bcbfa810d Revert "use our own index_sequence"
This reverts commit 5365521f8f.
2018-11-23 23:20:42 +03:00
Antony Polukhin
5365521f8f use our own index_sequence 2018-11-23 23:01:48 +03:00
Antony Polukhin
3229e76d48 ci fixes (1) 2018-11-23 22:52:58 +03:00
Antony Polukhin
eaf13a38ca ci fixes 2018-11-23 22:47:30 +03:00
Antony Polukhin
f026cc6c8a Use clang-4, not clang-6 2018-11-22 20:24:59 +03:00
Antony Polukhin
f486a148b4 Use clang 6 in ci 2018-11-22 11:37:59 +03:00
Antony Polukhin
f0d9551a01 Disable clang 6 in ci 2018-11-22 11:26:57 +03:00
Antony Polukhin
158f3e779c Update CI (11) 2018-11-22 11:00:30 +03:00
Antony Polukhin
3630668c2d Update CI (10) 2018-11-22 10:43:57 +03:00
Antony Polukhin
7ee6c785d8 Update CI (9) 2018-11-22 09:11:30 +03:00
Antony Polukhin
606e6c34b2 Update CI (8) 2018-11-22 01:12:11 +03:00
Antony Polukhin
9ab62bf32e Update CI (7) 2018-11-22 00:54:03 +03:00
Antony Polukhin
a9b25ef1c3 Update CI (6) 2018-11-22 00:53:20 +03:00
Antony Polukhin
40ade16430 Update CI (4) 2018-11-22 00:35:20 +03:00
Antony Polukhin
354f9f00d5 Update CI (3) 2018-11-22 00:03:32 +03:00
Antony Polukhin
4a9452318c Update CI (2) 2018-11-21 23:33:57 +03:00
Antony Polukhin
e2f9f0df5c Update CI (1) 2018-11-21 23:26:42 +03:00
Antony Polukhin
2921e8a1a9 Update CI 2018-11-21 22:43:36 +03:00
Antony Polukhin
953bdc9bf9 Merge pull request #29 from zmij/feature/make_integer_sequence_workaround
Add a workaround for broken std::make_integer_sequence.
2018-11-21 22:13:03 +03:00
zmij
88c65b3af3 cc: move make_index_sequence and sequence_for outside ifdefs 2018-11-21 17:23:37 +03:00
zmij
3e46450ee1 feat: Use compiler builtin if available 2018-11-21 17:16:30 +03:00
zmij
d1ee7629c9 fix: add header includes 2018-11-21 16:40:47 +03:00
zmij
6bfa69b15d cc: remove unused specializations, add details namespace to uses of make_integer_sequence 2018-11-21 16:36:15 +03:00
zmij
6d8caf8ca7 cc: Simplify integer sequence building 2018-11-21 16:12:57 +03:00
zmij
cf30a51da4 fix: typo 2018-11-21 15:49:11 +03:00
zmij
6052d93b75 Logarithmic sequence build 2018-11-21 15:46:09 +03:00
zmij
757b02f7c6 Add a workaround for broken std::make_integer_sequence. 2018-11-21 14:14:37 +03:00
Antony Polukhin
4ce90db718 Disabled ADL for many internal functions (those functions are not customization points) 2018-11-04 21:23:58 +03:00
Antony Polukhin
15549e642b Allow reflection of move-only types (refs #27). Speedup reflection of arrays. 2018-11-04 05:07:00 +03:00
Antony Polukhin
79d87e37f4 Fixed typo in docs 2018-10-27 20:56:32 +03:00
Antony Polukhin
068f98346a Update the docs: remove outdated notes about using reinterpret_cast. We do not do it any more 2018-10-27 20:49:48 +03:00
Antony Polukhin
1b49ad3791 Workaround GCC-8 bug 2018-10-20 22:53:24 +03:00
Antony Polukhin
c5130dd9e5 Merge pull request #24 from Kojoley/patch-1
Replace hard-coded byte bit count with CHAR_BIT
2018-09-09 20:54:50 +03:00
Antony Polukhin
6304fc6b29 Fix missing && 2018-09-09 13:12:26 +03:00
Antony Polukhin
5439885958 Add missing parenthesis 2018-09-09 12:15:27 +03:00
Antony Polukhin
437308871b Disable for msvc one of the tests 2018-09-09 11:42:39 +03:00
Antony Polukhin
5b79f61e07 Merge pull request #26 from Kojoley/patch-2
Check field values directly with BOOST_TEST_EQ
2018-09-04 09:39:07 +03:00
Nikita Kniazev
0f9edaf9ad Check field values directly with BOOST_TEST_EQ 2018-09-04 02:19:03 +03:00
Antony Polukhin
2169841e68 Fix #25 2018-09-03 23:06:39 +03:00
Antony Polukhin
d8cb24b660 Even better note for the #25 2018-09-03 23:04:40 +03:00
Antony Polukhin
09266c929c Better message for #25 2018-09-03 22:56:48 +03:00
Antony Polukhin
42f707b388 Merge pull request #23 from abutcher-gh/destructuring-tie
tie: Support multiple lvalue de-structuring assignment.
2018-09-03 10:52:29 +03:00
Nikita Kniazev
793842e94e Replace hard-coded byte bit count with CHAR_BIT 2018-08-31 00:40:46 +03:00
Adam Butcher
c53f623d4d tie: Remove tie_ignore.hpp from this branch and disable ADL for tie_as*_tuple calls. 2018-08-28 21:49:20 +01:00
Adam Butcher
89d41cb599 test/Jamfile.v2: Fix typo causing flat destructuring tie test to build on MSVC where it is not supported. 2018-08-25 07:49:43 +01:00
Adam Butcher
bcc2101fa0 test/*/destructuring_tie: Skip on C++14 with loophole disabled. 2018-08-24 21:44:57 +01:00
Adam Butcher
060437a01d tie: Support flat_tie_from_structure.
Rename `tie` to `tie_from_structure`.  Move `boost::pfr::ignore` definition to `pfr/common`.
2018-08-24 21:01:07 +01:00
Adam Butcher
8470938009 tie: Add test and fix some trivialities. 2018-08-11 21:54:51 +01:00
Adam Butcher
86c9934c40 tie: Support multiple lvalue de-structuring assignment. 2018-08-11 19:05:47 +01:00
Antony Polukhin
b0229248de Fix a warning 2018-06-15 00:50:02 +03:00
Antony Polukhin
7d4a705f74 Update years in docs 2018-06-12 17:52:41 +03:00
Antony Polukhin
7a098eea97 Typo fixed 2018-06-12 13:11:51 +03:00
Antony Polukhin
e27bb2a979 Add helper GIT files 2018-06-12 13:08:15 +03:00
Antony Polukhin
aec668962d Document the unions behavior and fix #22 2018-06-12 13:06:37 +03:00
Antony Polukhin
8efe184b7a Fix test compilation on MSVC (2) 2018-06-02 20:18:16 +03:00
Antony Polukhin
4ca855fdbb Fix test compilation on MSVC 2018-06-02 19:58:47 +03:00
Antony Polukhin
ee7a716b6d Update copyrights 2018-06-02 12:21:56 +03:00
Antony Polukhin
d36729a3ad Make static_assert messages more visible 2018-06-02 00:18:27 +03:00
Antony Polukhin
4a6d8d10c7 More static asserts and tests on unions (#22) 2018-05-31 23:26:15 +03:00
Antony Polukhin
cb12e9a05d Disable all the flat reflection for unions (refs #22) 2018-05-30 23:33:19 +03:00
Antony Polukhin
ea47144b60 More tests on unions (refs #22) 2018-05-30 23:04:03 +03:00
Antony Polukhin
e7abff68f6 Some tests for unions #22 2018-05-24 20:36:20 +03:00
Antony Polukhin
8b575abe43 We can pass string_view by copy now (like all the cool people do\!), because we do not use forward declared string_view any more. 2018-02-21 23:29:26 +03:00
Antony Polukhin
d9735b867c Set sudo to true to make sanitizers comfortable 2018-02-20 23:31:43 +03:00
Antony Polukhin
a229d560ee Remove leak sanitizer comand line option (address sanitizer includes leak sanitizer). This may probably fix the CI failures with GCC-7 2018-02-20 23:16:18 +03:00
Antony Polukhin
a11ff11ab4 Do not forward declare basic_string_view. Fixes #19 2018-02-20 22:52:48 +03:00
Antony Polukhin
250d5011f4 Travis CI related fixes 2017-10-20 18:02:26 +03:00
Antony Polukhin
30d65a2ad4 Test on GCC7 in C++14 and C++17 modes instead of testing on clang 2017-10-20 17:08:44 +03:00
Antony Polukhin
2007f2f339 Test on clang too in TravisCI 2017-10-20 16:46:57 +03:00
Antony Polukhin
1bdc6cae9b Made tests more strict and updated MSVC bersion in readme 2017-10-20 16:45:55 +03:00
Antony Polukhin
72b69d3288 GCC related fixes and simplifications 2017-10-20 14:26:07 +03:00
Antony Polukhin
8031f575fe Ironed out the lvalues and rvalues in detail namespace. Less template instantiations must happen now 2017-10-18 22:40:54 +03:00
Antony Polukhin
999e7d8619 Dropped BOOST_PFR_NO_STRICT_ALIASING macro 2017-10-18 22:38:32 +03:00
Antony Polukhin
b8f5ddd70f MSVC related checks improved and Appveyor fixes applied 2017-10-18 22:37:29 +03:00
Antony Polukhin
f686c9a77e Fixes for autotesting on MinGW 2017-10-18 11:05:10 +03:00
Antony Polukhin
6a5a04de55 Run MinGW instead of MSVC in Appveyor. Apveyor does not have the latest MSVC, required for PFR library build 2017-10-17 23:20:41 +03:00
Antony Polukhin
372f72a9fd Appveyor script fixes 2017-10-17 22:23:07 +03:00
Antony Polukhin
a9e5e73c30 Simplifications for MSVC and some polishing 2017-10-17 22:02:31 +03:00
Antony Polukhin
0c0332fe97 Use preview version of msvc in appveyor 2017-10-17 10:11:01 +03:00
Antony Polukhin
ab5140df52 Relax MSVC check 2017-10-17 09:00:26 +03:00
Antony Polukhin
d487496605 Appveyor fixes and badges update 2017-10-17 00:06:50 +03:00
Antony Polukhin
52b7f8f83a Final MSVC fixes, including detection idiom rewrite and simplifications of some tests. Docs updated to show MSVC usage ability 2017-10-17 00:01:15 +03:00
Antony Polukhin
d7cfbef235 MSVC fixes 2017-10-16 23:59:21 +03:00
Antony Polukhin
c48df9ba12 Multiple small fixes and improved testing 2017-10-16 23:58:34 +03:00
Antony Polukhin
12f8e1baa1 Fixes for non default constructible classes in loophole impl 2017-10-16 23:56:32 +03:00
Antony Polukhin
1b138a4bd7 Fixes for classes that could be constructed from everything. Fixes #15 2017-10-16 23:55:05 +03:00
Antony Polukhin
623e0ec093 More compile time checks and tests for #14 2017-10-13 21:30:06 +03:00
Antony Polukhin
5770f67671 Polishing: use std::addressof for getting address of user provided type, make some functions static and constexpr 2017-10-13 20:33:39 +03:00
Antony Polukhin
6814449a82 Merge pull request #13 from cbeck88/develop
Attempt to factor out cast_to_layout_compatible
2017-10-12 14:52:03 +03:00
Antony Polukhin
f91d809fc0 Polished readme 2017-10-01 22:10:34 +03:00
Antony Polukhin
41d73e45d4 Added one more example and some tests 2017-10-01 21:57:27 +03:00
Chris Beck
d37163cc98 use internal implementation of std::aligned_storage, remove constexpr
this fixes msvc2017 issues in godbolt
2017-09-28 15:40:39 -07:00
Chris Beck
29ab2524aa massaging of offset_based_getter offset calculation and code comments 2017-09-28 15:13:38 -07:00
Chris Beck
96b7c38666 fixup handling of volatile qualified user-defined types in offset_based_getter 2017-09-28 12:37:57 -07:00
Chris Beck
a9b952cdb8 add a configuration flag to control the use of offset_based_getter
this might be useful if on some compilers, cast_to_layout_compatible
leads to better codegen
2017-09-28 12:33:52 -07:00
Antony Polukhin
f75fa56076 Fixed issue #11 - incorrect fields count detection for non-default-constructible types 2017-09-28 21:08:32 +03:00
Chris Beck
af8be96595 adjust a code comment in offset_based_getter 2017-09-28 07:55:34 -07:00
Chris Beck
3aba48c9a9 use cast_to_layout_compatible again for enums in core14_loophole
this partially reverts a subtle change to static_cast in
551b36a536

the reason that is wrong is that the static_cast produces a new value,
while we need to produce a reference to the underlying type of the enum
essentially.
2017-09-28 07:13:55 -07:00
Chris Beck
62b972e500 comment out rvalue-reference overloads of offset_based_getter
this mirrors the earlier practice of commenting this out in
cast_to_layout_compatible
2017-09-28 07:03:50 -07:00
Chris Beck
6844dcb48f attempt to fixup value category logic changes introduced in the refactor
i didn't think intuitively that these changes were significant but they
appear to be necessary to pass the tests
2017-09-27 23:23:53 -07:00
Chris Beck
2a6a4752b8 add support for volatile qualifier to offset_based_getter 2017-09-27 22:14:21 -07:00
Chris Beck
f0dfa5ed4e add some more code comments around offset_based_getter 2017-09-27 21:48:36 -07:00
Chris Beck
6cab0a9684 add another static_assert regarding offset_based_getter 2017-09-27 21:38:31 -07:00
Chris Beck
c03977e29f fix compilation of previous commit on gcc 7.2 WIP 2017-09-27 18:57:22 -07:00
Antony Polukhin
49ae43f99f Started work on issue #11 (wrong fields count if class member is not default constructible) 2017-09-27 20:30:28 +03:00
Chris Beck
551b36a536 initial commit of offset-based getter
The idea here is to try to remove "cast_to_layout_compatible", which
technically violates strict aliasing rules. Instead, we want to try
to compute something like "offsetof" at compile-time for each struct member,
and use pointer arithmetic and reinterpret casts to do this legally.

The basic idea is to take the function "make_flat_tuple_of_references"
and generalize it, so that it need not actually work with tuples.
Instead, it can work with any class type, provided that it is also given
a "getter" function object which it can use to do "get<idx>".

We provide a trivial getter, which calls sequence_tuple::get.

We also provide a "offset_based_getter" which can work with user-defined
structure types, provided we are given a layout-compatible tuple as a template
parameter.

The basic idea is to take the layout-compatible tuple, then replace all the
members with corresponding `std::aligned_storage_t`. This doesn't change the
layout, but it makes everything trivially constructible and constexpr and all that.

Then we can construct that on the stack, and take differences between the main tuple
address, and the members' addresses.

At time of writing the tests are passing for me, but I haven't tested with compilers
other than gcc, or examined assembly to see if this method is being optimized the
way I hope it is.

This commit changes both core14_classic and core14_loophole to use the offset_based_getter,
but until further testing it might have been better to keep the other method around also.
2017-09-18 17:42:48 -07:00
Antony Polukhin
1bf21ae5b9 Fix issue in test 2017-09-17 10:15:44 +03:00
Antony Polukhin
b67893d92e Updated docs and enabled Loophole by default 2017-09-16 21:19:41 +03:00
Antony Polukhin
14d59f5340 Enable more tests for loophole 2017-09-16 20:46:38 +03:00
Antony Polukhin
28a787a6a8 Removed cloophole friend functions and probably slightly improved compilation speed 2017-09-13 21:53:49 +03:00
Antony Polukhin
3d8b5c33e6 Loophole implementation now works. Added many tests, added BOOST_PFR_USE_LOOPHOLE flag, disabled some unwanted ADLs 2017-09-12 21:18:13 +03:00
Antony Polukhin
0cf44d634e Reduce instantiations count by dropping some of the rvalue overloads of internal methods; reduce detail stuff used for public functions; reduced includes count 2017-09-06 21:57:22 +03:00
Antony Polukhin
79a7a1b25d core14 loophole now closer to working state 2017-09-06 21:52:48 +03:00
Antony Polukhin
a6d655e064 Simplifications and more work for core14 loophole 2017-09-06 21:51:43 +03:00
Antony Polukhin
7b0939289f Refactoring: as_tuple* => tie_as_tuple*; moved some code to separate files 2017-09-06 21:49:38 +03:00
Antony Polukhin
2a28aacc17 Initial version of loophole core14 implementation, copied from Alexandr Poltavsky 2017-09-06 21:47:48 +03:00
Antony Polukhin
982cb04375 Docs were updated, as was proposed in #8 2017-08-19 12:53:40 +03:00
Antony Polukhin
5262e209e4 Split examples.cpp into two files 2017-08-19 12:18:12 +03:00
Antony Polukhin
1bdd543304 Add a check on broken structured bindings and some notes on workarounds (#9) 2017-08-19 12:15:49 +03:00
Antony Polukhin
b0f042d1d8 Fix issue with tuple_element and add examples from Readme to tests 2017-08-19 12:14:05 +03:00
Antony Polukhin
1dfcc666c1 Improved error message and fixes for C++14 2017-08-13 11:48:14 +03:00
Antony Polukhin
78251885b4 Add info on 'precise' and 'flat' into the Overview section #8 2017-08-13 11:12:37 +03:00
Antony Polukhin
efd11f441f Make sure the we are not working with polymorphyc type. More tests added 2017-08-10 20:18:05 +03:00
Antony Polukhin
b7d7abd65d Fix compilation on clang 3.9, more tests for private/protected and improved error detection for #7 2017-08-10 20:16:25 +03:00
Antony Polukhin
62a9e5b758 Tested on a C++17 compatible compiler, fixed a bunch of issues and made all the tests compil and run successfully 2017-05-29 23:24:17 +03:00
Antony Polukhin
33ec908c44 Merge pull request #6 from bryant1410/develop
Fix broken headings in Markdown files
2017-04-17 21:38:15 +03:00
Santiago Castro
f788912a71 Fix broken Markdown headings 2017-04-16 23:41:44 -03:00
Antony Polukhin
34fd387877 Use PNG badges (they look more habitally) 2017-01-20 22:31:23 +03:00
Antony Polukhin
2c24e038d0 Revert the MSVC check 2017-01-15 14:41:58 +03:00
Antony Polukhin
04f2714475 Attempt to reduce msvc requirement 2017-01-15 13:55:19 +03:00
Antony Polukhin
191184a422 Use BOOST_PFR_USE_CPP17 macro instead of copypasted check, fix copyright dates, drop unnecessary dependencies in core17_generated.hpp 2017-01-15 10:49:56 +03:00
Antony Polukhin
bea67d5078 Fix typo 2017-01-07 00:34:24 +03:00
Antony Polukhin
afc6fe1272 Remove vendor specific macro for C++14 detection and aply a fix for appveyor.yml 2017-01-07 00:19:29 +03:00
Antony Polukhin
7992256108 Use ugly vendor specific extension to detect partial C++14 compatibility 2017-01-07 00:06:46 +03:00
Antony Polukhin
fd68ea93ee Deduplicate some code, create a separate config header, assume that MSVC 2017 RC supports C++14 2017-01-06 23:46:41 +03:00
Antony Polukhin
3eda0d10c6 try to test on MSVC 2017 2017-01-06 22:29:12 +03:00
Antony Polukhin
2f3c46dd9d Attempt to test on Windows 2017-01-06 18:17:41 +03:00
Antony Polukhin
7d422edf85 Updated README.md (fixed comments 2017-01-06 17:59:19 +03:00
Antony Polukhin
b4f147722e Updated README.md 2017-01-06 17:55:33 +03:00
Antony Polukhin
afd995e5dd Added info about reinterpret casts into the reference section. Improved formatting and added more examples 2017-01-05 20:54:08 +03:00
Antony Polukhin
6ea565dd6d Fix for Jamfile 2017-01-03 21:51:11 +03:00
Antony Polukhin
7532ba8ba1 Polishing the docs 2017-01-03 21:44:26 +03:00
Antony Polukhin
cfee20e36f Fixed multiple typos in docs and added more short examples 2017-01-01 18:07:16 +03:00
Antony Polukhin
459a25f817 A few more examples 2016-12-31 21:42:44 +03:00
Antony Polukhin
9bca907657 Fixed typos in docs and better structuring of reference section 2016-12-29 21:51:52 +03:00
Antony Polukhin
af0a937126 More tests, some refactoring, flat functions now have their precise version, started improving the documents, fixed issues with const propagations, better separation of functions (now IO functions are not part of the core.hpp) 2016-12-28 22:19:29 +03:00
Antony Polukhin
63a41e0256 Cleanup code and fix hash functor 2016-12-28 22:16:22 +03:00
Antony Polukhin
bc849f583e Operators and functors for precise mode added 2016-12-28 22:15:07 +03:00
Antony Polukhin
32b682261d Functions write and read now use for_each_field in C++14 mode 2016-12-28 22:13:52 +03:00
Antony Polukhin
d6d1082157 Separate tests on common, flat and precise 2016-12-28 22:12:29 +03:00
Antony Polukhin
0147c60f1e More code and tests for for_each_field function 2016-12-28 22:11:38 +03:00
Antony Polukhin
88f7ad3902 Started adding code for for_each_field function 2016-12-28 22:10:43 +03:00
Antony Polukhin
2d289f6b28 Started adopting the precise functions for C++14 2016-12-28 22:09:39 +03:00
Antony Polukhin
fb04223e5e Separate folders for precise and flat functions 2016-12-28 22:08:05 +03:00
Antony Polukhin
1314722a22 Started rewriting the library to support precise and flat operations independently from C++ Standard 2016-12-28 22:07:09 +03:00
Antony Polukhin
cb876b55a8 Runc CI tests only in C++14 mode 2016-12-26 22:09:43 +03:00
Antony Polukhin
e815460aed Updated the autotesting script 2016-12-25 16:59:13 +03:00
Antony Polukhin
26fffe6ff0 Added 'How it works' section into the docs 2016-10-14 08:59:22 +03:00
Antony Polukhin
e353fd63f2 Fixed typo 2016-10-12 22:05:27 +03:00
Antony Polukhin
a277cdac19 Minor cleanups and made fields_count() correctly work with structures that have bitfields 2016-10-08 18:04:27 +03:00
Antony Polukhin
48b86158f0 Added static_assert for fields_count() function. Now noncopy constructable classes are not allowed 2016-10-08 18:02:44 +03:00
Antony Polukhin
8e0f27baee Add more tests and try to relax POD requirement as was proposed by Anton Bikineev 2016-10-08 18:00:47 +03:00
Antony Polukhin
9c88c56cb3 Remove unused classes, drop member reference checks as was proposed by Anton Bikineev 2016-10-08 17:58:51 +03:00
Antony Polukhin
c110bdf0e6 Minor refactoring and one more test 2016-09-30 20:28:15 +03:00
Antony Polukhin
5ae2e2fd5f Optimized compilation times 2016-09-30 20:26:18 +03:00
Antony Polukhin
7c252b4ca5 Updated the motivating example 2016-09-29 22:35:22 +03:00
Antony Polukhin
a144d044df Disable clang, as it is too old in repo 2016-09-29 22:08:03 +03:00
Antony Polukhin
558734e7f8 Fixing clang compile options 2016-09-29 21:45:33 +03:00
Antony Polukhin
940cb1507f Fix testing issue with missing boost/type_index.hpp header and enable clang 2016-09-29 21:42:23 +03:00
Antony Polukhin
378acb1fe9 More tests and significant compilation time improvement 2016-09-29 21:33:24 +03:00
Antony Polukhin
c9bc21ed9c Fix all the known clang related issues 2016-09-29 21:31:42 +03:00
Antony Polukhin
d6687e5d18 Cleanups, clang related workarounds 2016-09-29 21:30:47 +03:00
Antony Polukhin
b0347fb617 Improving compilation times 2016-09-29 21:29:27 +03:00
Antony Polukhin
ac034a6ef7 Removing copypasted code and improving compilation times 2016-09-29 21:28:26 +03:00
Antony Polukhin
138a7aff2e Dropping std::tuple and fixing my own tuple implementation. std::tuple on GCC-6 was exceeding template instantiation depth limit extreamely fast 2016-09-29 21:25:59 +03:00
Antony Polukhin
12940c6ed9 Attempt to fix ineffective std::tuple_cat by implementing it from scratch 2016-09-29 21:24:17 +03:00
Antony Polukhin
282094999e Attempt to use std::tuple to avoid reinventing all the tuple functionality from scratch 2016-09-29 21:23:01 +03:00
Antony Polukhin
72c831cb1a More fixes and debugging for nested structures 2016-09-29 21:21:59 +03:00
Antony Polukhin
3dad4f6271 More tests fixed and enabled, dropped hand-written comparators in favour of std::tuple default ones 2016-09-28 22:45:01 +03:00
Antony Polukhin
46ca2b70b2 More tests enabled and more fixes 2016-09-28 22:43:47 +03:00
Antony Polukhin
558a49daee Use std::tuple in most of the places, instead adding and reinventing new functionality in our own tuple 2016-09-28 22:42:19 +03:00
Antony Polukhin
fd381c5dd4 Continuing work on correct representation of structures with tricky alignments 2016-09-28 22:40:35 +03:00
Antony Polukhin
313d667664 Fixing the compilation; still fails to compile 2016-09-26 20:45:03 +03:00
Antony Polukhin
4c2f7fbce4 Representing nested structures as nested tuples; fails to compile 2016-09-26 20:43:49 +03:00
Antony Polukhin
f4126ca464 Added test case from Lisa Lippincott and started fixing the issue 2016-09-26 20:41:45 +03:00
Antony Polukhin
217b4f9d50 Fixed typo 2016-09-07 01:37:03 +03:00
Antony Polukhin
b5dea7e0c4 Improved docs, removed unused classes 2016-09-05 21:41:53 +03:00
Antony Polukhin
79a79332ae Do not include c++17 headers by default (they are not tested yet) 2016-07-28 23:46:47 +03:00
Antony Polukhin
16e28d3c3c tuned cpp17 generator: the output is even more compact now 2016-07-28 23:45:57 +03:00
Antony Polukhin
452e01ff0b Generator updated, more compact c++17 code produced 2016-07-28 23:24:18 +03:00
Antony Polukhin
9fbb780839 Move more files to better reflect their content and usability (pod_ -> flat_) 2016-07-18 23:54:07 +03:00
Antony Polukhin
494a9cf6ca Rename more internal functions to better match their usability (removed flat prefix and moved to sequence_tuple namespace) 2016-07-18 23:51:22 +03:00
Antony Polukhin
67b1b5c06a Rename internal function to better reflect their usability in C++17 2016-07-18 23:49:21 +03:00
Antony Polukhin
212efb1be0 Added initial and untested version of C++17 functionality 2016-07-18 23:48:14 +03:00
Antony Polukhin
135faf692d Move some files and change header names 2016-07-18 23:46:45 +03:00
Antony Polukhin
9ecedfe6ca Better formatting for generated files 2016-07-18 23:42:07 +03:00
Antony Polukhin
27cd2d78e3 Initial commit of reflections based on 'structured bindings' from C++17 2016-07-14 22:38:34 +03:00
Antony Polukhin
7d9dec3b44 Fair implementation of comparison operators (now actually uses the underlying operators of POD types). More constexpr methods and adde some include guards 2016-07-14 22:35:17 +03:00
Antony Polukhin
2751725148 Changed comparisons _impl to work with sequence_tuple::tuple and made those _impl functions to constexpr 2016-07-14 22:31:16 +03:00
Antony Polukhin
4211404f20 Added tuple_size method, updated the docs and dropped some useless specializations 2016-07-14 22:29:05 +03:00
Antony Polukhin
6ef486f0b7 detail::as_tuple -> detail::as_flat_tuple 2016-07-12 22:20:55 +03:00
Antony Polukhin
2ca4142e93 Made an as_tuple function and improved some of the functions to reinterpret_cast to tuple only once 2016-07-12 21:34:05 +03:00
Antony Polukhin
c9bb66911a rename get to flat_get. Remove some usings 2016-07-12 21:32:38 +03:00
Antony Polukhin
1b0ae91a52 New library name in README 2016-06-18 17:04:35 +03:00
Antony Polukhin
74a1bb1eac More travisCI related fixes (9) 2016-06-18 14:46:54 +03:00
Antony Polukhin
b9987c70ab More travisCI related fixes (8) 2016-06-18 14:37:35 +03:00
Antony Polukhin
54f82e9482 More travisCI related fixes (7) 2016-06-18 13:35:58 +03:00
Antony Polukhin
3ee92b6a14 More travisCI related fixes (6) 2016-06-18 13:27:35 +03:00
Antony Polukhin
a83f1043f3 More travisCI related fixes (5) 2016-06-18 13:16:30 +03:00
Antony Polukhin
1405b1ab64 More travisCI related fixes (4) 2016-06-18 13:06:03 +03:00
Antony Polukhin
2854894a74 More travisCI related fixes (3) 2016-06-18 12:40:38 +03:00
Antony Polukhin
d78d300380 More travisCI related fixes (2) 2016-06-18 12:38:02 +03:00
Antony Polukhin
2284d6f703 More travisCI related fixes 2016-06-18 12:35:40 +03:00
Antony Polukhin
dc585f67fd Another travis related fix no3 2016-06-16 00:18:07 +03:00
Antony Polukhin
ebd3750681 Another travis related fix no2 2016-06-16 00:14:31 +03:00
Antony Polukhin
9fb1071862 Another travis related fix 2016-06-16 00:04:12 +03:00
Antony Polukhin
f058b9b771 Minor fix of README formatting 2016-06-15 23:58:32 +03:00
Antony Polukhin
96b0c9b7d7 Another TravisCI fix 2016-06-15 23:51:48 +03:00
Antony Polukhin
620f9f4f80 Fix travisCI tests 2016-06-15 23:41:30 +03:00
Antony Polukhin
36d22fe4de Updated docs, examples and polished headers 2016-06-15 23:30:56 +03:00
Antony Polukhin
efe421e982 Link to the docs provided 2016-06-09 23:10:35 +03:00
Antony Polukhin
db967a38a8 More experiments with pod_ops, more tests and docs 2016-06-09 23:05:07 +03:00
Antony Polukhin
11aa87e21f More docs, more Boost related modifications, more examples and tests. Work on rel_ops is going on 2016-06-08 21:26:55 +03:00
Antony Polukhin
99e3c623f4 Modifications to make library suitable for Boost 2016-06-07 22:43:44 +03:00
97 changed files with 9900 additions and 1755 deletions

97
.gitattributes vendored Normal file
View File

@@ -0,0 +1,97 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.pp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
doc/autodoc*
doc/html

View File

@@ -2,44 +2,179 @@
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Copyright Antony Polukhin 2014-2016.
# Copyright Antony Polukhin 2014-2020.
#
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
# and how it can be used with Boost libraries.
#
# File revision #6 modified
# File revision #9 (with DIFF)
env:
matrix:
- CXX_STANDARD=c++14 TOOLSET=g++-5
- CXX_STANDARD=c++1z TOOLSET=g++-5
- CXX_STANDARD=c++14 TOOLSET=clang++-3.7
language: cpp
os: linux
dist: bionic
# `--coverage` flags required to generate coverage info for Coveralls
matrix:
include:
# - env: B2_ARGS='cxxstd=14,1y toolset=gcc-6 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD -fno-rtti" linkflags="--coverage -lasan -lubsan"'
# name: "GCC-6, no RTTI"
# addons:
# apt:
# sources: ubuntu-toolchain-r-test
# packages: g++-6
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-10 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
name: "GCC-10"
sudo: required # Required by leak sanitizer
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-10
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
name: "GCC-8"
sudo: required # Required by leak sanitizer
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-8
- env: B2_ARGS='cxxstd=1y toolset=gcc-5 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
name: "GCC-5"
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-5
# - env: B2_ARGS='cxxstd=14,1y toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD -fno-exceptions" linkflags="--coverage -lasan -lubsan"'
# name: "GCC-8, no exceptions"
# sudo: required # Required by leak sanitizer
# addons:
# apt:
# sources: ubuntu-toolchain-r-test
# packages: g++-8
- env: B2_ARGS='cxxstd=14 toolset=clang-6 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -fsanitize=address,leak,undefined"'
name: "Clang-6"
sudo: required # Required by leak sanitizer
addons:
apt:
sources: llvm-toolchain-trusty-6
packages: clang-6.0
- env: B2_ARGS='cxxstd=14,17,20 toolset=clang-10 cxxflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined"'
name: "Clang-10, libc++"
sudo: required # Required by leak sanitizer
addons:
apt:
sources: llvm-toolchain-bionic-10
packages:
- clang-10
- libc++-10-dev
- libc++abi-10-dev
# Sanitizers disabled for this toolset as they started causing link troubles:
# hidden symbol `_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE11__recommendEm' isn't defined
- env: B2_ARGS='cxxstd=14 toolset=clang-libc++ cxxflags="--coverage -DBOOST_TRAVISCI_BUILD" linkflags="--coverage"'
name: "Clang-3.8, libc++"
addons:
apt:
packages: libc++-dev
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
sudo: false
language: cpp
compiler:
- gcc
os:
- linux
# Installing additional tools
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
sources: git-core
packages:
- valgrind
- gcc-5
- g++-5
- clang-3.7
- git
- python-yaml
before_install:
# Autodetect Boost branch by using the following code: - BOOST_BRANCH=$TRAVIS_BRANCH
# or just directly specify it
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
# Files, which coverage results must be ignored (files from other projects).
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
- IGNORE_COVERAGE=''
# Explicitly remove the following library from Boost. This may be useful, if you're for example running Travis
# from `Boost.DLL` repo, while Boost already has `dll`.
#
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
# This will force to use local repo content, instead of the Boost's default.
- BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
# Global options for sanitizers
- UBSAN_OPTIONS=print_stacktrace=1
- LSAN_OPTIONS=verbosity=1:log_threads=1
# Set this to the name of the library
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
# Cloning minimal set of Boost libraries
- BOOST=$HOME/boost-local
- echo "Testing $PROJECT_TO_TEST, to remove $BOOST/libs/$BOOST_REMOVE, testing branch $BOOST_BRANCH"
- git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git $BOOST
- cd $BOOST
- git submodule update --init --depth 10 tools/build tools/boostdep libs/type_index # DIFF: Added libs/type_index
# Replacing Boost module with this project and installing Boost dependencies
- rm -rf $BOOST/libs/$BOOST_REMOVE
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$PROJECT_TO_TEST
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" $(basename $TRAVIS_BUILD_DIR)
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" type_index # DIFF: Added line
- git status
# Adding missing toolsets and preparing Boost headers
- ./bootstrap.sh
- ./b2 headers
- |-
echo "using gcc ;" >> ~/user-config.jam
echo "using clang ;" >> ~/user-config.jam
echo "using clang : 3.8 : clang++-3.8 ;" >> ~/user-config.jam
echo "using clang : 4 : clang++-4.0 ;" >> ~/user-config.jam
echo "using clang : 5 : clang++-5.0 ;" >> ~/user-config.jam
echo "using clang : 6 : clang++-6.0 ;" >> ~/user-config.jam
echo "using clang : 7 : clang++-7.0 ;" >> ~/user-config.jam
echo "using clang : 8 : clang++-8 ;" >> ~/user-config.jam
echo "using clang : 10 : clang++-10 ;" >> ~/user-config.jam
echo "using clang : libc++ : clang++-libc++ ;" >> ~/user-config.jam
- cd $BOOST/libs/$PROJECT_TO_TEST/test/
script:
# `--coverage` flags required to generate coverage info for Coveralls
- $TOOLSET -std=$CXX_STANDARD --coverage main.cpp && valgrind ./a.out
- sh -c "../../../b2 -j2 $B2_ARGS"
after_success:
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.da" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.no" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- wget https://github.com/linux-test-project/lcov/archive/v1.12.zip
- unzip v1.12.zip
- LCOV="`pwd`/lcov-1.12/bin/lcov --gcov-tool gcov-6"
# Preparing Coveralls data by changind data format to a readable one
- echo "$LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info"
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing /test/ /example/ folder data
- cd $BOOST
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing data that is not related to this project directly
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$PROJECT_TO_TEST\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- echo $OTHER_LIBS
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
# Sending data to Coveralls
- cd $TRAVIS_BUILD_DIR
- gem install coveralls-lcov
- coveralls-lcov coverals/coverage.info

201
README.md
View File

@@ -1,170 +1,103 @@
#Magic Get [![Build Status](https://travis-ci.org/apolukhin/magic_get.svg?branch=master)](https://travis-ci.org/apolukhin/magic_get)
# Precise and Flat Reflection (ex Magic Get, ex PODs Flat Reflection)
This C++14 library is meant for accessing structure elements by index and providing other std::tuple like methods for user defined POD types.
This C++14 library is meant for accessing structure elements by index and providing other std::tuple like methods for user defined types without any macro or boilerplate code.
### Motivating example
[Latest documentation](http://apolukhin.github.com/magic_get/index.html)
### Test results
Branches | Build | Tests coverage | More info
----------------|-------------- | -------------- |-----------
Develop: | [![Build Status](https://travis-ci.org/apolukhin/magic_get.svg?branch=develop)](https://travis-ci.org/apolukhin/magic_get) [![Build status](https://ci.appveyor.com/api/projects/status/1edm74h5id8qpr2k/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/magic-get/branch/develop) | [![Coverage Status](https://coveralls.io/repos/github/apolukhin/magic_get/badge.png?branch=develop)](https://coveralls.io/github/apolukhin/magic_get?branch=develop) | <!-- [details...](http://www.boost.org/development/tests/develop/developer/pfr.html)) -->
Master: | [![Build Status](https://travis-ci.org/apolukhin/magic_get.svg?branch=master)](https://travis-ci.org/apolukhin/magic_get) [![Build status](https://ci.appveyor.com/api/projects/status/1edm74h5id8qpr2k/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/magic-get/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/apolukhin/magic_get/badge.png?branch=master)](https://coveralls.io/github/apolukhin/magic_get?branch=master) | <!-- [details...](http://www.boost.org/development/tests/master/developer/pfr.html)) -->
### Motivating Example #0
```c++
// requires: C++14
#include <iostream>
#include "magic_get.hpp"
#include <string>
#include "boost/pfr/precise.hpp"
struct my_struct {
struct some_person {
std::string name;
unsigned birth_year;
};
int main() {
some_person val{"Edgar Allan Poe", 1809};
std::cout << boost::pfr::get<0>(val) // No macro!
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate initializables!
}
```
Outputs:
```
Edgar Allan Poe was born in 1809
```
### Motivating Example #1
```c++
// requires: C++14
#include <iostream>
#include "boost/pfr/precise.hpp"
struct my_struct { // no ostream operator defined!
int i;
char c;
double d;
};
int main() {
my_struct s{100, 'H', 3.141593 };
std::cout << "my_struct has " << flat_tuple_size<my_struct>::value << " fields: "
<< "{ " << flat_get<0>(s) << ", " << flat_get<1>(s)<< ", " << flat_get<2>(s) << " }\n";
using namespace boost::pfr::ops; // out-of-the-box ostream operator for all PODs!
my_struct s{100, 'H', 3.141593};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
}
```
Outputs:
```
my_struct has 3 fields: { 100, H, 3.14159 }
my_struct has 3 fields: {100, H, 3.14159}
```
### Flattening
All the methods with prefix `flat_` represent a template parameter type as flat structure without static members:
### Motivating Example #2
```c++
// Helper structure.
struct my_struct_nested { short a1; int a2; };
// requires: C++14
#include <iostream>
#include "boost/pfr/precise.hpp"
// This structure:
struct my_struct {
int a0;
static const cvalue = 1000;
my_struct_nested nested;
short a3_a4[2];
struct my_struct { // no ostream operator defined!
std::string s;
int i;
};
// will be flattened and represented as:
struct my_struct_flat {
int a0;
short a1;
int a2
short a3;
short a4
};
```
So that
* `flat_get<2>(my_struct{})` will return `my_struct::my_struct_nested::a2` field
* `flat_get<3>(my_struct{})` will return `my_struct::a3_a4[0]` field
int main() {
using namespace boost::pfr::ops; // out-of-the-box ostream operators for aggregate initializables!
my_struct s{{"Das ist fantastisch!"}, 100};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
}
Same story with arrays:
```c++
int i[2][2] = {{10, 11}, {12, 13} };
assert(flat_get<1>(i) == 11);
```
### API
```c++
/// Returns const reference to a field with index `I` in flattened `T`.
/// Example usage: flat_get<0>(my_structure());
template <std::size_t I, class T>
decltype(auto) flat_get(const T& val) noexcept;
/// Returns reference to a field with index `I` in flattened `T`.
/// Requires: `T` must not have const fields.
/// Example usage: flat_get<0>(my_structure());
template <std::size_t I, class T>
decltype(auto) flat_get(T& val, typename std::enable_if< std::is_trivially_assignable<T, T>::value>::type* = 0);
/// `flat_tuple_element` has a `typedef type-of-a-field-with-index-I-in-flattened-T type;`
/// Example usage: std::vector< flat_tuple_element<0, my_structure>::type > v;
template <std::size_t I, class T>
using flat_tuple_element;
/// Type of a field with index `I` in flattened `T`
/// Example usage: std::vector< flat_tuple_element_t<0, my_structure> > v;
template <std::size_t I, class T>
using flat_tuple_element_t = typename flat_tuple_element<I, T>::type;
/// `flat_tuple_size` has a member `value` that constins fields count in a flattened `T`.
/// Example usage: std::array<int, flat_tuple_size<my_structure>::value > a;
template <class T>
using flat_tuple_size;
/// `flat_tuple_size_v` is a template variable that constins fields count in a flattened `T`.
/// Example usage: std::array<int, flat_tuple_size_v<my_structure> > a;
template <class T>
constexpr std::size_t flat_tuple_size_v = flat_tuple_size<T>::value;
/// Creates an `std::tuple` from a flattened T.
/// Example usage:
/// struct my_struct { int i, short s; };
/// my_struct s {10, 11};
/// std::tuple<int, short> t = flat_to_tuple(s);
/// assert(get<0>(t) == 10);
template <class T>
auto flat_make_tuple(const T& val) noexcept;
/// Creates an `std::tuple` with lvalue references to fields of a flattened T.
/// Example usage:
/// struct my_struct { int i, short s; };
/// my_struct s;
/// flat_tie(s) = std::tuple<int, short>{10, 11};
/// assert(s.s == 11);
template <class T>
auto flat_tie(T& val, typename std::enable_if< std::is_trivially_assignable<T, T>::value>::type* = 0 ) noexcept;
/// Writes to `out` POD `value`
/// Example usage:
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// flat_write(std::cout, s); // outputs '{12, 13}'
template <class Char, class Traits, class T>
void flat_write(std::basic_ostream<Char, Traits>& out, const T& value);
/// Reads POD `value` from stream `in`
/// Example usage:
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{12, 13}";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
template <class Char, class Traits, class T>
void flat_read(std::basic_istream<Char, Traits>& in, T& value);
/// Contains comparison operators and stream operators for any POD types that does not have it's own operators.
/// If POD is comparable or streamable using it's own operator or it's conversion operator, then the original operator is be used.
///
/// Example usage:
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// using namespace pod_ops;
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
namespace pod_ops;
Outputs:
```
my_struct has 2 fields: {"Das ist fantastisch!", 100}
```
### Requirements and Limitations
* C++14 compatible compiler (GCC-5.0+, Clang, ...)
* T must be POD and must not contain references nor bitfields
* T must not contain pointers to user defined types
* Enums will be returned as their underlying type
General:
* C++14 compatible compiler (GCC-5.0+, Clang, Visual Studio 2017 with /std:c++latest or /std:c++17, ...)
* Static variables are ignored
* T must be constexpr aggregate initializable and must not contain references nor bitfields
### License

90
doc/Jamfile.v2 Normal file
View File

@@ -0,0 +1,90 @@
# Copyright Antony Polukhin 2016-2019.
# Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
using quickbook ;
using boostbook ;
using doxygen ;
using xsltproc ;
import set ;
import doxygen ;
import xsltproc ;
import notfile ;
import path ;
project pfr/doc ;
#
# Common params for doxygen
#
local doxygen_params =
<doxygen:param>EXTRACT_ALL=NO
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
<doxygen:param>EXTRACT_PRIVATE=NO
<doxygen:param>ENABLE_PREPROCESSING=YES
<doxygen:param>EXPAND_ONLY_PREDEF=YES
<doxygen:param>MACRO_EXPANSION=YES
<doxygen:param>INLINE_SIMPLE_STRUCTS=YES
<doxygen:param>SORT_MEMBER_DOCS=NO
<doxygen:param>"ALIASES= \\
\"flattening{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.tutorial.flattening'>\\1</link>\\endxmlonly\" \\
\"podops=\\b See \\b Also: \\xmlonly<link linkend='boost_precise_and_flat_reflectio.tutorial.three_ways_of_getting_operators'>Three ways of getting operators</link>\\endxmlonly\" \\
\"constexprinit{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.requirements_and_limitations'>\\1</link>\\endxmlonly\" \\
\"rcast=\\b Note: If reflecting structures with enums may `reinterpret_cast` enum to a reference to underlying type.\" \\
\"flatpod{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.requirements_and_limitations'>\\1</link>\\endxmlonly\" \\
"
;
doxygen autodoc_all
:
[ glob ../../../boost/pfr.hpp ]
:
$(doxygen_params)
<xsl:param>"boost.doxygen.reftitle=Include all"
;
doxygen autodoc_flat
:
[ glob ../../../boost/pfr/flat.hpp ]
[ glob ../../../boost/pfr/flat/*.hpp ]
:
$(doxygen_params)
<xsl:param>"boost.doxygen.reftitle=Flat Reflection"
;
doxygen autodoc_precise
:
[ glob ../../../boost/pfr/precise.hpp ]
[ glob ../../../boost/pfr/precise/*.hpp ]
:
$(doxygen_params)
<xsl:param>"boost.doxygen.reftitle=Precise Reflection"
;
boostbook pfr-doc
:
pfr.qbk
:
<dependency>autodoc_all
<dependency>autodoc_precise
<dependency>autodoc_flat
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_63_0
#<xsl:param>boost.root=../../../.
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
;
###############################################################################
alias boostdoc
: pfr-doc/<format>docbook
:
:
: ;
explicit boostdoc ;
alias boostrelease ;
explicit boostrelease ;

419
doc/pfr.qbk Normal file
View File

@@ -0,0 +1,419 @@
[library Boost.PFR
[quickbook 1.6]
[version 1.0]
[copyright 2016-2020 Antony Polukhin]
[category Language Features Emulation]
[license
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])
]
]
[section Motivation]
In C++ we have:
* tuples - types that provide access to members by index. Those are useful for generic programming.
* structures - types with named fields that do not provide access to members by index. Those are just easy to use.
This library provides tuple like methods for aggregate initializable structures, making them usable in contexts where only tuples were useful.
[note All you have to do is to add `#include <boost/pfr.hpp>`.
No macro or other type/member registrations required.]
[import ../example/examples.cpp]
The two different types of reflection are:
* [*Precise] reflection, where each field type is represented as it actually exists, even if the type is itself a user-defined type.
* [*Flat] reflection, where user-defined types are represented by their individual field types, and all other types are represented as they actually exists.
As an example:
[pfr_intro]
Boost.Precise and Flat Reflection (Boost.PFR) adds following out-of-the-box functionality for aggregate initializable structures:
* comparison operators
* heterogeneous comparators
* hash
* stream operators
* access to members by index
* member reflections
* methods for cooperation with `std::tuple`
* methods to visit each field of the structure
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/apolukhin/magic_get from the github] into your project, and the library would work fine.
[warning This is not an official Boost library! It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library to formal review, if community think that it is interesting!]
[caution Recommended C++ Standards are C++17 and above]
[caution Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
[endsect]
[section Short Examples for the Impatient]
Examples in the table use the following definition:
[import ../example/quick_examples.cpp]
[pfr_quick_examples_structures]
[table:quick_examples
[[ Code snippet ] [ `var` content or output ] [ Function description: ]]
[
[ [pfr_quick_examples_get_1] ]
[ `var == {A {1, 2.0}}` ]
[ [funcref boost::pfr::get get] ]
][
[ [pfr_quick_examples_flat_get_1] ]
[ `var == {A, {1, 3.14159}}` ]
[ [funcref boost::pfr::flat_get flat_get] ]
][
[ [pfr_quick_examples_get_2] ]
[ `var == {A, {777, 42.01}}` ]
[ [funcref boost::pfr::get get] ]
][
[ [pfr_quick_examples_flat_get_2] ]
[ `var == {A, {777, 42.01}}` ]
[ [funcref boost::pfr::flat_get flat_get] ]
][
[ [pfr_quick_examples_flat_functors_uset] ]
[ `my_uset` constains `var` ]
[
[classref boost::pfr::flat_hash flat_hash]
[classref boost::pfr::flat_equal_to flat_equal_to]
]
][
[ [pfr_quick_examples_flat_functors_set] ]
[ `my_set` constains `var` ]
[ [classref boost::pfr::flat_less flat_less] ]
][
[ [pfr_quick_examples_flat_ops] ]
[ assert succeeds ]
[ [headerref boost/pfr/flat/ops.hpp using\u00A0namespace\u00A0flat_ops;] ]
][
[ [pfr_quick_examples_ops] ]
[ assert succeeds ]
[ [headerref boost/pfr/precise/ops.hpp using\u00A0namespace\u00A0ops;] ]
][
[ [pfr_quick_examples_flat_for_each] ]
[ `var == {B, {778, 4.14159}}` ]
[ [funcref boost::pfr::flat_for_each_field flat_for_each_field] ]
][
[ [pfr_quick_examples_for_each] ]
[ `var == {B, {787, 103.142}}` ]
[ [funcref boost::pfr::for_each_field for_each_field] ]
][
[ [pfr_quick_examples_flat_for_each_idx] ]
[ ```0: char
1: int
2: double
``` ]
[ [funcref boost::pfr::flat_for_each_field flat_for_each_field] ]
][
[ [pfr_quick_examples_for_each_idx] ]
[ ```0: char
1: quick_examples_ns::foo
``` ]
[ [funcref boost::pfr::for_each_field for_each_field] ]
][
[ [pfr_quick_examples_tuple_size] ]
[ `tuple_size: 2` ]
[ [classref boost::pfr::tuple_size tuple_size] ]
][
[ [pfr_quick_examples_flat_tuple_size] ]
[ `flat_tuple_size: 3` ]
[ [classref boost::pfr::flat_tuple_size flat_tuple_size] ]
][
[ [pfr_quick_examples_structure_to_tuple] ]
[ `var == {A, {777, 3.14159}}` ]
[ [funcref boost::pfr::structure_to_tuple structure_to_tuple] ]
][
[ [pfr_quick_examples_flat_structure_to_tuple] ]
[ `var == {A, {777, 3.14159}}` ]
[ [funcref boost::pfr::flat_structure_to_tuple flat_structure_to_tuple] ]
][
[ [pfr_quick_examples_structure_tie] ]
[ `var == {A, {1, 2.0}}` ]
[ [funcref boost::pfr::structure_tie structure_tie] ]
][
[ [pfr_quick_examples_flat_structure_tie] ]
[ `var == {C, {777, 3.14159}}` ]
[ [funcref boost::pfr::flat_structure_tie flat_structure_tie] ]
]]
[endsect]
[section Tutorial]
[section Accessing structure member by index] [pfr_example_get] [endsect]
[section Flattening] [pfr_example_flattening] [pfr_example_flattening_2] [endsect]
[/ [section Counting fields] [pfr_example_tuple_size] [endsect] ]
[section Flat or Precise functions to choose]
All the functions that have `flat_` prefix and are declared in `boost/pfr/flat/*` headers are the [*flat] functions, other function are [*precise] and are declared in `boost/pfr/precise/*`. In previous example you've seen how the the flattening works.
Use [*flat] functions if you:
* wish types flattened
* or you reflect types with C arrays
For all the other cases prefer [*precise] functions.
[warning MSVC currently supports only [*precise] functions and only in /std:c++latest or /std:c++17 modes.]
[endsect]
[section Three ways of getting operators ]
There are three ways to start using Boost.PFR hashing, comparison and streaming operators for type `T` in your code. Each method has it's own drawbacks and suits own cases.
[table:flat_ops_comp Different approaches for operators
[[ Approach
][ Defines operators in global namespace ][ Defined operators could be found by ADL ][ Works for local types ][ Usable locally, without affecting code from other scopes ][ Ignores implicit conversion operators ][ Respects user defined operators ]]
[[
[headerref boost/pfr/precise/ops.hpp using\u00A0namespace\u00A0boost::pfr::ops;]
[headerref boost/pfr/flat/ops.hpp using\u00A0namespace\u00A0boost::pfr::flat_ops;]
][ no ][ no ][ yes ][ yes ][ no ][ yes ]]
[[
[macroref BOOST_PFR_FLAT_FUNCTIONS_FOR]
[macroref BOOST_PFR_PRECISE_FUNCTIONS_FOR]
][ yes if T is in it ][ yes ][ no ][ no, but could be limited to translation unit ][ yes for T ] [ no (compile time error) ]]
[[
[headerref boost/pfr/flat/global_ops.hpp]
[headerref boost/pfr/precise/global_ops.hpp]
][ yes ][ yes ][ yes ][ no, but could be limited to translation unit ][ yes all ][ yes ]]
]
More detailed description follows:
[*1. [headerref boost/pfr/precise/ops.hpp `using namespace boost::pfr::ops;`] and [headerref boost/pfr/flat/ops.hpp `using namespace boost::pfr::flat_ops;`] approach]
This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there's no operators defined for the type:
```
#include <boost/pfr/precise/ops.hpp>
template <class T>
struct uniform_comparator_less {
bool operator()(const T& lhs, const T& rhs) const noexcept {
using namespace boost::pfr::ops; // Enables Boost.PFR operators usage in this scope.
// If T has operator< or conversion operator then will use it.
// Otherwise will use boost::pfr::flat_less<T>.
return lhs < rhs;
}
};
```
This method's effects are local to the function. It works even for local types, like structures defined in functions.
However *Argument Dependant Lookup* does not work with it:
```
#include <boost/pfr/flat/ops.hpp>
template <class T>
struct uniform_comparator_less {
bool operator()(const T& lhs, const T& rhs) const noexcept {
using namespace flat_ops;
// Compile time error if T has neither operator< nor
// conversion operator to comparable type.
return std::less{}(lhs, rhs);
}
};
```
[*2. [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR] and [macroref BOOST_PFR_PRECISE_FUNCTIONS_FOR] approach]
This method is good if you're writing a structure and wish to define operators for that structure.
```
#include <boost/pfr/flat/functions_for.hpp>
struct pair_like {
int first;
short second;
};
BOOST_PFR_FLAT_FUNCTIONS_FOR(pair_like) // Defines operators
// ...
assert(pair_like{1, 2} < pair_like{1, 3});
```
Argument Dependant Lookup works well, `std::less` will find the operators for `struct pair_like`. [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR BOOST_PFR_FLAT_FUNCTIONS_FOR(T)]
can not be used for local types, it must be called only once in namespace of `T`. It does not respect conversion operators of `T`, so for example the following code
will output different values:
```
#include <boost/pfr/flat/functions_for.hpp>
struct empty {
operator std::string() { return "empty{}"; }
};
// Uncomment to get different output:
// BOOST_PFR_FLAT_FUNCTIONS_FOR(empty)
// ...
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FLAT_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
```
[*3. [headerref boost/pfr/flat/global_ops.hpp] and [headerref boost/pfr/precise/global_ops.hpp] approach]
This approach is for those, who wish to have comparisons/streaming/hashing for all their types.
```
#include <boost/pfr/flat/global_ops.hpp>
struct pair_like {
int first;
short second;
};
// ...
assert(pair_like{1, 2} < pair_like{1, 3});
```
Argument Dependant Lookup works well, `std::less` will find the operators for `struct pair_like`. Operators for local types will be also defined.
*All conversion operators of types are not used during comparisons/streaming/hashing.*
[endsect]
[section Reflection of unions ]
With [*precise] reflection you could do reflection if a type contains union. But be sure that operations for union are manually defined:
```
#include <boost/pfr/precise/ops.hpp>
union test_union {
int i;
float f;
};
inline bool operator==(test_union l, test_union r) noexcept; // Compile time error without this operator
struct foo { int i; test_union u; };
bool some_function(foo f1, foo f2) {
using namespace boost::pfr::ops;
return f1 == f2; // OK
}
```
[*Flat] reflection of types that contain unions is disabled.
[*Flat] and [*precise] reflection of unions is disabled for safety reasons. There's a way to reflect the first member of a union and use it. Unfortunately there's no way to find out [*active] member of a union. Accessing an inactive union member is an Undefined Behavior. Using the first union member for reflection could lead to disaster if it is some character pointer. For example ostreaming `union {char* c; long long ll; } u; u.ll= 1;` will crash your program, as the active member is `ll` that holds `1` but we are trying to output a `char*`. This would cause an invalid pointer2 dereference.
Any attempt to reflect unions leads to a compile time error. In many cases a static assert is triggered that outputs the following message:
```
error: static_assert failed "====================> Boost.PFR: For safety reasons it is forbidden
to reflect unions. See `Reflection of unions` section in the docs for more info."
```
[endsect]
[endsect]
[section Configuration Macro]
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
[table:linkmacro Macros
[[Macro name] [Effect]]
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to use structured bindings and other C++17 features for reflection. Define to `0` otherwize.]]
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` otherwize.]]
[[*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 PFR version of that metafunction. Define to `1` otherwize. ]]
]
Note that disabling [*Loophole] in C++14 significantly limits the reflection abilities of the library. See next section for more info.
[endsect]
[section Limitations]
The reflection has some limitations that depend on a C++ Standard and compiler capabilities:
* Static variables are ignored
* T must be aggregate initializable
* Additional C++14 [*only] limitations (switch to C++17 to remove all of those):
* Non of the member fields should have a template constructor from one parameter.
* Additional limitations if the [*Loophole] as also disabled:
* [*Flat]:
* T must be POD and must not contain references nor bitfields
* Enums will be returned as their underlying type
* [*Precise]:
* T must be constexpr aggregate initializable and all it's fields must be constexpr default constructible
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/precise/core.hpp boost::pfr::tuple_element] require T to be a flat POD type
[endsect]
[section How it works]
Short description:
* Flat functions:
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
# at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
# at run-time: get pointer to each field, knowing the structure address and each field offset
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
* Precise functions:
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
* C++17:
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
* C++14:
# Same approach as with [*flat] functions
* C++14 with disabled [*Loophole]:
# at compile-time: use flat reflection if it could precisely reflect the type. Otherwise:
# at compile-time: let `I` be is an index of current field, it equals 0
# at run-time: `T` is constructed and field `I` is aggregate initialized using a separate instance of structure that is convertible to anything [note Additional care is taken to make sure that all the information about `T` is available to the compiler and that operations on `T` have no side effects, so the compiler can optimize away the unnecessary temporary objects.]
# at compile-time: `I += 1`
# at compile-time: if `I` does not equal fields count goto step [~c.] from inside of the conversion operator of the structure that is convertible to anything
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
# at run-time: get pointer to each field, knowing the structure address and each field offset
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
Long description of some basics: [@https://youtu.be/UlNUNxLtBI0 Antony Polukhin: Better C++14 reflections].
Long description of some basics of C++14 with disabled [*Loophole]: [@https://youtu.be/abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling].
[endsect]
[section Acknowledgements]
Great thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/apolukhin/magic_get/issues/5 Manual type registering/structured bindings might be unnecessary].
Great thanks to Alexandr Poltavsky for initial implementation the [*Loophole] technique and for describing it [@http://alexpolt.github.io/type-loophole.html in his blog].
Great thanks to Chris Beck for implementing the detect-offsets-and-get-field-address functionality that avoids Undefined Behavior of reinterpret_casting layout compatible structures.
[endsect]
[section Reference]
[xinclude autodoc_precise.xml]
[xinclude autodoc_flat.xml]
[xinclude autodoc_all.xml]
[endsect]

129
example/examples.cpp Normal file
View File

@@ -0,0 +1,129 @@
// Copyright 2016-2020 Antony Polukhin
// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
#include <cassert>
//[pfr_intro
#include <boost/pfr.hpp>
struct nested_t { char c; };
struct foo_t { int i; nested_t nested; };
static_assert(std::is_same<
boost::pfr::flat_tuple_element_t<1, foo_t>, // Flat reflection.
char // `char`, not `nested_t`!
>::value, "");
// Requires C++17 or Loophole enabled:
//<-
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE //->
static_assert(std::is_same<
boost::pfr::tuple_element_t<1, foo_t>, // Precise reflection.
nested_t
>::value, ""); //<-
#endif //->
//] [/pfr_intro]
//[pfr_example_get
/*`
The following example shows how to access structure fields by index using [funcref boost::pfr::get].
Let's define some structure:
*/
#include <boost/pfr/precise/core.hpp>
struct foo { // defining structure
int some_integer;
char c;
};
/*`
We can access fields of that structure by index:
*/
foo f {777, '!'};
auto& r1 = boost::pfr::get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer`
auto& r2 = boost::pfr::get<1>(f); // accessing field with index 1, returns reference to `foo::c`
//] [/pfr_example_get]
//[pfr_example_tuple_size
/*`
The following example shows how to count fields using [classref boost::pfr::tuple_size].
*/
#include <boost/pfr/precise/core.hpp>
struct foo2 { // defining structure
int some_integer;
char c;
short some_other_field;
};
static_assert(
boost::pfr::tuple_size<foo2>::value // returns total count of fields in `foo2`
== 3, ""
);
static_assert(
boost::pfr::tuple_size<int[100]>::value // works with arrays too!
== 100, ""
);
//] [/pfr_example_tuple_size]
//[pfr_example_flattening
/*`
[warning All the functions and metafunctions in Boost.PFR that start with `flat_` represent template parameter type as flat structure without static members! ]
Take a look at the `struct my_struct`:
*/
#include <boost/pfr/flat/core.hpp>
struct my_struct_nested { short a1; int a2; };
struct my_struct {
int a0;
static const int cvalue = 1000;
my_struct_nested nested;
short a3_a4[2];
};
/*` It will be flattened and represented as: */
struct my_struct_flat {
int a0;
short a1;
int a2;
short a3;
short a4;
};
//] [/pfr_example_flattening]
void example_get() {
//[pfr_example_flattening_2
/*`
It means, that:
*/
boost::pfr::flat_get<2>(my_struct{}); // ... will return `my_struct::my_struct_nested::a2` field.
boost::pfr::flat_get<3>(my_struct{}); // ... will return `my_struct::a3_a4[0]` field.
/*` Exactly the same story with arrays: */
int i[2][2] = {{10, 11}, {12, 13} };
const int& r = boost::pfr::flat_get<1>(i);
assert(r == 11);
//] [/pfr_example_flattening_2]
(void)r;
}
int main() {
example_get();
}

227
example/quick_examples.cpp Normal file
View File

@@ -0,0 +1,227 @@
// Copyright 2016-2020 Antony Polukhin
// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
#include <cassert>
#include <iostream>
#include <unordered_set>
#include <set>
#include <boost/pfr.hpp>
#include <boost/type_index.hpp>
//[pfr_quick_examples_structures
struct foo {
int integer;
double real;
void operator +=(int v) {
integer += v * 10;
real += v * 100;
}
};
struct bar {
char character;
foo f;
};
bar var{'A', {777, 3.141593}};
//]
inline std::ostream& operator<<(std::ostream& os, const bar& b) {
return os << '{' << b.character << ", {" << b.f.integer << ", " << b.f.real << "}}";
}
void test_examples() {
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_functors_uset
// no `std::hash<bar>` or `bar::operator==(const bar&)` defined
std::unordered_set<
bar, boost::pfr::flat_hash<bar>,
boost::pfr::flat_equal_to<>> my_uset;
my_uset.insert(var);
//]
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_functors_set
// no `bar::operator<(const bar&)` defined
std::set<bar, boost::pfr::flat_less<>> my_set;
my_set.insert(var);
//]
}
{
//[pfr_quick_examples_flat_ops
using namespace boost::pfr::flat_ops; // Defines comparisons
assert((var < bar{'Z', {}} && var.f == foo{777, 3.141593}));
//]
std::cout << "boost::pfr::flat_structure_tie(var) :\n" << var << '\n';
}
#if BOOST_PFR_USE_CPP17
{
//[pfr_quick_examples_ops
struct test { std::string f1; std::string_view f2; };
using namespace boost::pfr::ops; // Defines comparisons
assert((test{"abc", ""} > test{"aaa", "zomg"}));
//]
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_for_each
// incrementing each field on 1:
boost::pfr::flat_for_each_field(var, [](auto& field) {
field += 1;
});
//]
std::cout << "flat_for_each_field outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_for_each
// increments first field on 1, calls foo::operator+= for second field
boost::pfr::for_each_field(var, [](auto& field) {
field += 1;
});
//]
std::cout << "flat_for_each_field outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_for_each_idx
boost::pfr::flat_for_each_field(var, [](auto& field, std::size_t idx) {
std::cout << idx << ": "
<< boost::typeindex::type_id_runtime(field) << '\n';
});
//]
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_for_each_idx
boost::pfr::for_each_field(var, [](auto& field, std::size_t idx) {
std::cout << idx << ": "
<< boost::typeindex::type_id_runtime(field) << '\n';
});
//]
}
{
//[pfr_quick_examples_tuple_size
std::cout << "tuple_size: "
<< boost::pfr::tuple_size<bar>::value << '\n';
//]
}
{
//[pfr_quick_examples_flat_tuple_size
std::cout << "flat_tuple_size: "
<< boost::pfr::flat_tuple_size<bar>::value << '\n';
//]
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_get_1
boost::pfr::get<1>(var) = foo{1, 2}; // C++17 or Loophole is required
//]
std::cout << "boost::pfr::get<1>(var) outputs:\n" << var << '\n';
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_get_1
boost::pfr::flat_get<1>(var) = 1;
//]
std::cout << "boost::pfr::flat_get<1>(var) outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_get_2
boost::pfr::get<1>(var.f) = 42.01;
//]
std::cout << "boost::pfr::get<1>(var.f) outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_get_2
boost::pfr::flat_get<1>(var.f) = 42.01;
//]
std::cout << "boost::pfr::flat_get<1>(var.f) outputs:\n" << var << '\n';
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_structure_to_tuple
// C++17 or Loophole is required
std::tuple<char, foo> t = boost::pfr::structure_to_tuple(var);
std::get<1>(t) = foo{1, 2};
//]
std::cout << "boost::pfr::structure_to_tuple(var) :\n" << var << '\n';
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_structure_to_tuple
std::tuple<char, int, double> t = boost::pfr::flat_structure_to_tuple(var);
std::get<0>(t) = 'C';
//]
std::cout << "boost::pfr::flat_structure_to_tuple(var) :\n" << var << '\n';
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_structure_tie
// C++17 or Loophole is required
std::tuple<char&, foo&> t = boost::pfr::structure_tie(var);
std::get<1>(t) = foo{1, 2};
//]
std::cout << "boost::pfr::structure_tie(var) :\n" << var << '\n';
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_structure_tie
std::tuple<char&, int&, double&> t = boost::pfr::flat_structure_tie(var);
std::get<0>(t) = 'C';
//]
std::cout << "boost::pfr::flat_structure_tie(var) :\n" << var << '\n';
}
} // void test_examples() {
int main() {
test_examples();
}

16
include/boost/pfr.hpp Normal file
View File

@@ -0,0 +1,16 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_HPP
#define BOOST_PFR_HPP
/// \file boost/pfr.hpp
/// Includes all the Boost.PFR headers, except \xmlonly<link linkend='header.boost.pfr.flat.global_ops_hpp'>boost/pfr/flat/global_ops.hpp</link>\endxmlonly and \xmlonly<link linkend='header.boost.pfr.precise.global_ops_hpp'>boost/pfr/precise/global_ops.hpp</link>\endxmlonly
#include <boost/pfr/precise.hpp>
#include <boost/pfr/flat.hpp>
#endif // BOOST_PFR_HPP

View File

@@ -0,0 +1,75 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP
#define BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/rvalue_t.hpp>
namespace boost { namespace pfr { namespace detail {
template <class T, class U>
constexpr void static_assert_layout_compatible() noexcept {
static_assert(
std::alignment_of<T>::value == std::alignment_of<U>::value,
"====================> Boost.PFR: Alignment check failed, probably your structure has user-defined alignment for the whole structure or for some of the fields."
);
static_assert(sizeof(T) == sizeof(U), "====================> Boost.PFR: Size check failed, probably your structure has bitfields or user-defined alignment.");
}
/// @cond
#ifdef __GNUC__
#define MAY_ALIAS __attribute__((__may_alias__))
#else
#define MAY_ALIAS
#endif
/// @endcond
template <class To, class From>
MAY_ALIAS const To& cast_to_layout_compatible(const From& val) noexcept {
MAY_ALIAS const To* const t = reinterpret_cast<const To*>( std::addressof(val) );
detail::static_assert_layout_compatible<To, From>();
return *t;
}
template <class To, class From>
MAY_ALIAS const volatile To& cast_to_layout_compatible(const volatile From& val) noexcept {
MAY_ALIAS const volatile To* const t = reinterpret_cast<const volatile To*>( std::addressof(val) );
detail::static_assert_layout_compatible<To, From>();
return *t;
}
template <class To, class From>
MAY_ALIAS volatile To& cast_to_layout_compatible(volatile From& val) noexcept {
MAY_ALIAS volatile To* const t = reinterpret_cast<volatile To*>( std::addressof(val) );
detail::static_assert_layout_compatible<To, From>();
return *t;
}
template <class To, class From>
MAY_ALIAS To& cast_to_layout_compatible(From& val) noexcept {
MAY_ALIAS To* const t = reinterpret_cast<To*>( std::addressof(val) );
detail::static_assert_layout_compatible<To, From>();
return *t;
}
#ifdef BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING
template <class To, class From>
To&& cast_to_layout_compatible(rvalue_t<From> val) noexcept = delete;
#endif
#undef MAY_ALIAS
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP

View File

@@ -0,0 +1,63 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_CONFIG_HPP
#define BOOST_PFR_DETAIL_CONFIG_HPP
#pragma once
// Reminder:
// * MSVC++ 1?.? _MSC_VER > 1900 (Visual Studio 2017)
// * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
// * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
#if defined(_MSC_VER)
# if _MSC_VER <= 1900
# error Boost.PFR library requires MSVC with c++17 support (Visual Studio 2017 or later).
# endif
#elif __cplusplus < 201402L
# error Boost.PFR library requires at least C++14.
#endif
#ifndef BOOST_PFR_USE_LOOPHOLE
# if !defined(__clang_major__) || __clang_major__ < 8
# define BOOST_PFR_USE_LOOPHOLE 1
# endif
#endif
#ifndef BOOST_PFR_USE_CPP17
# ifdef __cpp_structured_bindings
# define BOOST_PFR_USE_CPP17 1
# elif defined(_MSC_VER)
# warning PFR library supports MSVC compiler only with /std:c++latest or /std:c++17 flag. Assuming that you`ve used it. Define `BOOST_PFR_USE_CPP17` to 1 to suppress this warning.
# define BOOST_PFR_USE_CPP17 1
# else
# define BOOST_PFR_USE_CPP17 0
# endif
#endif
#ifndef BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE
// Assume that libstdc++ since GCC-7.3 does not have linear instantiation depth in std::make_integral_sequence
# if defined( __GLIBCXX__) && __GLIBCXX__ >= 20180101
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
# elif defined(_MSC_VER)
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
//# elif other known working lib
# else
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 0
# endif
#endif
#if defined(__has_cpp_attribute)
# if __has_cpp_attribute(maybe_unused)
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
# endif
#endif
#ifndef BOOST_PFR_MAYBE_UNUSED
# define BOOST_PFR_MAYBE_UNUSED
#endif
#endif // BOOST_PFR_DETAIL_CONFIG_HPP

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_CORE14_HPP
#define BOOST_PFR_DETAIL_CORE14_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#if BOOST_PFR_USE_LOOPHOLE
# include <boost/pfr/detail/core14_loophole.hpp>
#else
# include <boost/pfr/detail/core14_classic.hpp>
#endif
#endif // BOOST_PFR_DETAIL_CORE14_HPP

View File

@@ -0,0 +1,711 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
#define BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/offset_based_getter.hpp>
#include <boost/pfr/detail/fields_count.hpp>
#include <boost/pfr/detail/make_flat_tuple_of_references.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/detail/size_array.hpp>
#include <boost/pfr/detail/size_t_.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wmissing-braces"
# pragma clang diagnostic ignored "-Wundefined-inline"
# pragma clang diagnostic ignored "-Wundefined-internal"
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
#endif
namespace boost { namespace pfr { namespace detail {
///////////////////// General utility stuff
template <class T> struct identity {
typedef T type;
};
template <class T>
constexpr T construct_helper() noexcept { // adding const here allows to deal with copyable only types
return {};
}
template <class T> constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept;
template <class T> constexpr auto flat_array_of_type_ids() noexcept;
///////////////////// All the stuff for representing Type as integer and converting integer back to type
namespace typeid_conversions {
///////////////////// Helper constants and typedefs
#ifdef _MSC_VER
# pragma warning( push )
// '<<': check operator precedence for possible error; use parentheses to clarify precedence
# pragma warning( disable : 4554 )
#endif
constexpr std::size_t native_types_mask = 31;
constexpr std::size_t bits_per_extension = 3;
constexpr std::size_t extension_mask = (
static_cast<std::size_t>((1 << bits_per_extension) - 1)
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
);
constexpr std::size_t native_ptr_type = (
static_cast<std::size_t>(1)
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
);
constexpr std::size_t native_const_ptr_type = (
static_cast<std::size_t>(2)
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
);
constexpr std::size_t native_const_volatile_ptr_type = (
static_cast<std::size_t>(3)
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
);
constexpr std::size_t native_volatile_ptr_type = (
static_cast<std::size_t>(4)
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
);
constexpr std::size_t native_ref_type = (
static_cast<std::size_t>(5)
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
);
template <std::size_t Index, std::size_t Extension>
using if_extension = std::enable_if_t< (Index & extension_mask) == Extension >*;
///////////////////// Helper functions
template <std::size_t Unptr>
constexpr std::size_t type_to_id_extension_apply(std::size_t ext) noexcept {
constexpr std::size_t native_id = (Unptr & native_types_mask);
constexpr std::size_t extensions = (Unptr & ~native_types_mask);
static_assert(
!((extensions >> bits_per_extension) & native_types_mask),
"====================> Boost.PFR: Too many extensions for a single field (something close to `int************************** p;` is in the POD type)."
);
return (extensions >> bits_per_extension) | native_id | ext;
}
template <std::size_t Index>
using remove_1_ext = size_t_<
((Index & ~native_types_mask) << bits_per_extension) | (Index & native_types_mask)
>;
#ifdef _MSC_VER
# pragma warning( pop )
#endif
///////////////////// Forward declarations
template <class Type> constexpr std::size_t type_to_id(identity<Type*>) noexcept;
template <class Type> constexpr std::size_t type_to_id(identity<const Type*>) noexcept;
template <class Type> constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept;
template <class Type> constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept;
template <class Type> constexpr std::size_t type_to_id(identity<Type&>) noexcept;
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>* = 0) noexcept;
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = 0) noexcept;
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>* = 0) noexcept;
template <class Type> constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value && !std::is_union<Type>::value>* = 0) noexcept;
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = 0) noexcept;
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = 0) noexcept;
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = 0) noexcept;
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = 0) noexcept;
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = 0) noexcept;
///////////////////// Definitions of type_to_id and id_to_type for fundamental types
/// @cond
#define BOOST_MAGIC_GET_REGISTER_TYPE(Type, Index) \
constexpr std::size_t type_to_id(identity<Type>) noexcept { \
return Index; \
} \
constexpr Type id_to_type( size_t_<Index > ) noexcept { \
return detail::construct_helper<Type>(); \
} \
/**/
/// @endcond
// Register all base types here
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned char , 1)
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned short , 2)
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned int , 3)
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long , 4)
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long long , 5)
BOOST_MAGIC_GET_REGISTER_TYPE(signed char , 6)
BOOST_MAGIC_GET_REGISTER_TYPE(short , 7)
BOOST_MAGIC_GET_REGISTER_TYPE(int , 8)
BOOST_MAGIC_GET_REGISTER_TYPE(long , 9)
BOOST_MAGIC_GET_REGISTER_TYPE(long long , 10)
BOOST_MAGIC_GET_REGISTER_TYPE(char , 11)
BOOST_MAGIC_GET_REGISTER_TYPE(wchar_t , 12)
BOOST_MAGIC_GET_REGISTER_TYPE(char16_t , 13)
BOOST_MAGIC_GET_REGISTER_TYPE(char32_t , 14)
BOOST_MAGIC_GET_REGISTER_TYPE(float , 15)
BOOST_MAGIC_GET_REGISTER_TYPE(double , 16)
BOOST_MAGIC_GET_REGISTER_TYPE(long double , 17)
BOOST_MAGIC_GET_REGISTER_TYPE(bool , 18)
BOOST_MAGIC_GET_REGISTER_TYPE(void* , 19)
BOOST_MAGIC_GET_REGISTER_TYPE(const void* , 20)
BOOST_MAGIC_GET_REGISTER_TYPE(volatile void* , 21)
BOOST_MAGIC_GET_REGISTER_TYPE(const volatile void* , 22)
BOOST_MAGIC_GET_REGISTER_TYPE(std::nullptr_t , 23)
constexpr std::size_t tuple_begin_tag = 24;
constexpr std::size_t tuple_end_tag = 25;
#undef BOOST_MAGIC_GET_REGISTER_TYPE
///////////////////// Definitions of type_to_id and id_to_type for types with extensions and nested types
template <class Type>
constexpr std::size_t type_to_id(identity<Type*>) noexcept {
constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
static_assert(
std::is_same<const std::size_t, decltype(unptr)>::value,
"====================> Boost.PFR: Pointers to user defined types are not supported."
);
return typeid_conversions::type_to_id_extension_apply<unptr>(native_ptr_type);
}
template <class Type>
constexpr std::size_t type_to_id(identity<const Type*>) noexcept {
constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
static_assert(
std::is_same<const std::size_t, decltype(unptr)>::value,
"====================> Boost.PFR: Const pointers to user defined types are not supported."
);
return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_ptr_type);
}
template <class Type>
constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept {
constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
static_assert(
std::is_same<const std::size_t, decltype(unptr)>::value,
"====================> Boost.PFR: Const volatile pointers to user defined types are not supported."
);
return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_volatile_ptr_type);
}
template <class Type>
constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept {
constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
static_assert(
std::is_same<const std::size_t, decltype(unptr)>::value,
"====================> Boost.PFR: Volatile pointers to user defined types are not supported."
);
return typeid_conversions::type_to_id_extension_apply<unptr>(native_volatile_ptr_type);
}
template <class Type>
constexpr std::size_t type_to_id(identity<Type&>) noexcept {
constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
static_assert(
std::is_same<const std::size_t, decltype(unptr)>::value,
"====================> Boost.PFR: References to user defined types are not supported."
);
return typeid_conversions::type_to_id_extension_apply<unptr>(native_ref_type);
}
template <class Type>
constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>*) noexcept {
return typeid_conversions::type_to_id(identity<typename std::underlying_type<Type>::type >{});
}
template <class Type>
constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>*) noexcept {
static_assert(!std::is_empty<Type>::value, "====================> Boost.PFR: Empty classes/structures as members are not supported.");
return 0;
}
template <class Type>
constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>*) noexcept {
static_assert(
!std::is_union<Type>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
return 0;
}
template <class Type>
constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value && !std::is_union<Type>::value>*) noexcept {
constexpr auto t = detail::flat_array_of_type_ids<Type>();
size_array<sizeof(Type) * 3> result {{tuple_begin_tag}};
constexpr bool requires_tuplening = (
(t.count_nonzeros() != 1) || (t.count_nonzeros() == t.count_from_opening_till_matching_parenthis_seq(0, tuple_begin_tag, tuple_end_tag))
);
if (requires_tuplening) {
for (std::size_t i = 0; i < t.size(); ++i)
result.data[i + 1] = t.data[i];
result.data[result.size() - 1] = tuple_end_tag;
} else {
for (std::size_t i = 0; i < t.size(); ++i)
result.data[i] = t.data[i];
}
return result;
}
template <std::size_t Index>
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type>) noexcept {
typedef decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
return detail::construct_helper<res_t>();
}
template <std::size_t Index>
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type>) noexcept {
typedef const decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
return detail::construct_helper<res_t>();
}
template <std::size_t Index>
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type>) noexcept {
typedef const volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
return detail::construct_helper<res_t>();
}
template <std::size_t Index>
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type>) noexcept {
typedef volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
return detail::construct_helper<res_t>();
}
template <std::size_t Index>
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type>) noexcept {
static_assert(!Index, "====================> Boost.PFR: References are not supported");
return nullptr;
}
} // namespace typeid_conversions
///////////////////// Structure that remembers types as integers on a `constexpr operator Type()` call
struct ubiq_val {
std::size_t* ref_;
template <class T>
constexpr void assign(const T& typeids) const noexcept {
for (std::size_t i = 0; i < T::size(); ++i)
ref_[i] = typeids.data[i];
}
constexpr void assign(std::size_t val) const noexcept {
ref_[0] = val;
}
template <class Type>
constexpr operator Type() const noexcept {
constexpr auto typeids = typeid_conversions::type_to_id(identity<Type>{});
assign(typeids);
return detail::construct_helper<Type>();
}
};
///////////////////// Structure that remembers size of the type on a `constexpr operator Type()` call
struct ubiq_sizes {
std::size_t& ref_;
template <class Type>
constexpr operator Type() const noexcept {
ref_ = sizeof(Type);
return detail::construct_helper<Type>();
}
};
///////////////////// Returns array of (offsets without accounting alignments). Required for keeping places for nested type ids
template <class T, std::size_t N, std::size_t... I>
constexpr size_array<N> get_type_offsets() noexcept {
typedef size_array<N> array_t;
array_t sizes{};
T tmp{ ubiq_sizes{sizes.data[I]}... };
(void)tmp;
array_t offsets{{0}};
for (std::size_t i = 1; i < N; ++i)
offsets.data[i] = offsets.data[i - 1] + sizes.data[i - 1];
return offsets;
}
///////////////////// Returns array of typeids and zeros if construtor 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
{
static_assert(
N <= sizeof(T),
"====================> Boost.PFR: Bit fields are not supported."
);
constexpr auto offsets = detail::get_type_offsets<T, N, I...>();
T tmp{ ubiq_val{types + get<I>(offsets) * 3}... };
(void)types;
(void)tmp;
(void)offsets; // If type is empty offsets are not used
return nullptr;
}
///////////////////// Returns array of typeids and zeros
template <class T>
constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept {
size_array<sizeof(T) * 3> types{};
constexpr std::size_t N = detail::fields_count<T>();
detail::flat_type_to_array_of_type_ids<T, N>(types.data, detail::make_index_sequence<N>());
return types;
}
///////////////////// Returns array of typeids without zeros
template <class T>
constexpr auto flat_array_of_type_ids() noexcept {
constexpr auto types = detail::fields_count_and_type_ids_with_zeros<T>();
constexpr std::size_t count = types.count_nonzeros();
size_array<count> res{};
std::size_t j = 0;
for (std::size_t i = 0; i < decltype(types)::size(); ++i) {
if (types.data[i]) {
res.data[j] = types.data[i];
++ j;
}
}
return res;
}
///////////////////// Convert array of typeids into sequence_tuple::tuple
template <class T, std::size_t First, std::size_t... I>
constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept;
template <class T>
constexpr sequence_tuple::tuple<> as_flat_tuple_impl(std::index_sequence<>) noexcept {
return sequence_tuple::tuple<>{};
}
template <std::size_t Increment, std::size_t... I>
constexpr auto increment_index_sequence(std::index_sequence<I...>) noexcept {
return std::index_sequence<I + Increment...>{};
}
template <class T, std::size_t V, std::size_t I, std::size_t SubtupleLength>
constexpr auto prepare_subtuples(size_t_<V>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
static_assert(SubtupleLength == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
return typeid_conversions::id_to_type(size_t_<V>{});
}
template <class T, std::size_t I, std::size_t SubtupleLength>
constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_end_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
static_assert(sizeof(T) == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
return int{};
}
template <class T, std::size_t I, std::size_t SubtupleLength>
constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_begin_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
static_assert(SubtupleLength > 2, "====================> Boost.PFR: Internal error while representing nested field as tuple");
constexpr auto seq = detail::make_index_sequence<SubtupleLength - 2>{};
return detail::as_flat_tuple_impl<T>( detail::increment_index_sequence<I + 1>(seq) );
}
template <class Array>
constexpr Array remove_subtuples(Array indexes_plus_1, const Array& subtuple_lengths) noexcept {
for (std::size_t i = 0; i < subtuple_lengths.size(); ++i) {
if (subtuple_lengths.data[i]) {
const std::size_t skips_count = subtuple_lengths.data[i];
for (std::size_t j = i + 1; j < skips_count + i; ++j) {
indexes_plus_1.data[j] = 0;
}
i += skips_count - 1;
}
}
return indexes_plus_1;
}
template <std::size_t N, class Array>
constexpr size_array<N> resize_dropping_zeros_and_decrementing(size_t_<N>, const Array& a) noexcept {
size_array<N> result{};
std::size_t result_indx = 0;
for (std::size_t i = 0; i < a.size(); ++i) {
if (a.data[i]) {
result.data[result_indx] = static_cast<std::size_t>(a.data[i] - 1);
++ result_indx;
}
}
return result;
}
template <class T, std::size_t First, std::size_t... I, std::size_t... INew>
constexpr auto as_flat_tuple_impl_drop_helpers(std::index_sequence<First, I...>, std::index_sequence<INew...>) noexcept {
constexpr auto a = detail::flat_array_of_type_ids<T>();
constexpr size_array<sizeof...(I) + 1> subtuples_length {{
a.count_from_opening_till_matching_parenthis_seq(First, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag),
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
}};
constexpr size_array<sizeof...(I) + 1> type_indexes_with_subtuple_internals {{ 1, 1 + I - First...}};
constexpr auto type_indexes_plus_1_and_zeros_as_skips = detail::remove_subtuples(type_indexes_with_subtuple_internals, subtuples_length);
constexpr auto new_size = size_t_<type_indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
constexpr auto type_indexes = detail::resize_dropping_zeros_and_decrementing(new_size, type_indexes_plus_1_and_zeros_as_skips);
typedef sequence_tuple::tuple<
decltype(detail::prepare_subtuples<T>(
size_t_< a.data[ First + type_indexes.data[INew] ] >{}, // id of type
size_t_< First + type_indexes.data[INew] >{}, // index of current id in `a`
size_t_< subtuples_length.data[ type_indexes.data[INew] ] >{} // if id of type is tuple, then length of that tuple
))...
> subtuples_uncleanuped_t;
return subtuples_uncleanuped_t{};
}
template <class Array>
constexpr std::size_t count_skips_in_array(std::size_t begin_index, std::size_t end_index, const Array& a) noexcept {
std::size_t skips = 0;
for (std::size_t i = begin_index; i < end_index; ++i) {
if (a.data[i] == typeid_conversions::tuple_begin_tag) {
const std::size_t this_tuple_size = a.count_from_opening_till_matching_parenthis_seq(i, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag) - 1;
skips += this_tuple_size;
i += this_tuple_size - 1;
}
}
return skips;
}
template <class T, std::size_t First, std::size_t... I>
constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept {
constexpr auto a = detail::flat_array_of_type_ids<T>();
constexpr std::size_t count_of_I = sizeof...(I);
return detail::as_flat_tuple_impl_drop_helpers<T>(
std::index_sequence<First, I...>{},
detail::make_index_sequence< 1 + count_of_I - count_skips_in_array(First, First + count_of_I, a) >{}
);
}
template <class T>
constexpr auto internal_tuple_with_same_alignment() noexcept {
typedef typename std::remove_cv<T>::type type;
static_assert(
std::is_trivial<type>::value && std::is_standard_layout<type>::value,
"====================> Boost.PFR: Type can not be used is flat_ functions, because it's not POD"
);
static_assert(!std::is_reference<type>::value, "====================> Boost.PFR: Not applyable");
constexpr auto res = detail::as_flat_tuple_impl<type>(
detail::make_index_sequence< decltype(detail::flat_array_of_type_ids<type>())::size() >()
);
return res;
}
template <class T>
using internal_tuple_with_same_alignment_t = decltype( detail::internal_tuple_with_same_alignment<T>() );
///////////////////// Flattening
struct ubiq_is_flat_refelectable {
bool& is_flat_refelectable;
template <class Type>
constexpr operator Type() const noexcept {
is_flat_refelectable = std::is_fundamental<Type>::value;
return {};
}
};
template <class T, std::size_t... I>
constexpr bool is_flat_refelectable(std::index_sequence<I...>) noexcept {
constexpr std::size_t fields = sizeof...(I);
bool result[fields] = {static_cast<bool>(I)...};
const T v{ ubiq_is_flat_refelectable{result[I]}... };
(void)v;
for (std::size_t i = 0; i < fields; ++i) {
if (!result[i]) {
return false;
}
}
return true;
}
template <class T>
auto tie_as_flat_tuple(T& lvalue) 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."
);
using type = std::remove_cv_t<T>;
using tuple_type = internal_tuple_with_same_alignment_t<type>;
offset_based_getter<type, tuple_type> getter;
return boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<tuple_type::size_v>{});
}
#if !BOOST_PFR_USE_CPP17
template <class T>
auto tie_as_tuple(T& val) noexcept {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
static_assert(
boost::pfr::detail::is_flat_refelectable<T>( detail::make_index_sequence<boost::pfr::detail::fields_count<T>()>{} ),
"====================> Boost.PFR: Not possible in C++14 to represent that type without loosing information. Use boost::pfr::flat_ version, or change type definition, or enable C++17"
);
return boost::pfr::detail::tie_as_flat_tuple(val);
}
#endif // #if !BOOST_PFR_USE_CPP17
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////// Structure that can be converted to copy of anything
struct ubiq_constructor_constexpr_copy {
std::size_t ignore;
template <class Type>
constexpr operator Type() const noexcept {
static_assert(
std::is_trivially_destructible<Type>::value,
"====================> Boost.PFR: One of the fields in the type passed to `for_each_field` has non trivial destructor."
);
return {};
}
};
/////////////////////
#if !BOOST_PFR_USE_CPP17
template <class T, std::size_t... I>
struct is_constexpr_aggregate_initializable { // TODO: try to fix it
template <T = T{ ubiq_constructor_constexpr_copy{I}... } >
static std::true_type test(long) noexcept;
static std::false_type test(...) noexcept;
static constexpr decltype( test(0) ) value{};
};
template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...);
template <class T, class F, class... Fields>
void for_each_field_in_depth(T& t, F&& f, std::index_sequence<>, identity<Fields>...);
template <class T, class F, class IndexSeq, class... Fields>
struct next_step {
T& t;
F& f;
template <class Field>
operator Field() const {
boost::pfr::detail::for_each_field_in_depth(
t,
std::forward<F>(f),
IndexSeq{},
identity<Fields>{}...,
identity<Field>{}
);
return {};
}
};
template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...) {
(void)std::add_const_t<std::remove_reference_t<T>>{
Fields{}...,
next_step<T, F, std::index_sequence<I...>, Fields...>{t, f},
ubiq_constructor_constexpr_copy{I}...
};
}
template <class T, class F, class... Fields>
void for_each_field_in_depth(T& lvalue, F&& f, std::index_sequence<>, identity<Fields>...) {
using tuple_type = sequence_tuple::tuple<Fields...>;
offset_based_getter<std::remove_cv_t<std::remove_reference_t<T>>, tuple_type> getter;
std::forward<F>(f)(
boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<sizeof...(Fields)>{})
);
}
template <class T, class F, std::size_t... I>
void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::true_type /*is_flat_refelectable*/) {
std::forward<F>(f)(
boost::pfr::detail::tie_as_flat_tuple(t)
);
}
template <class T, class F, std::size_t... I>
void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::false_type /*is_flat_refelectable*/) {
boost::pfr::detail::for_each_field_in_depth(
t,
std::forward<F>(f),
std::index_sequence<I...>{}
);
}
template <class T, class F, std::size_t... I>
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."
);
/// Compile time error at this point means that you have called `for_each_field` or some other non-flat function or operator for a
/// type that is not constexpr aggregate initializable.
///
/// Make sure that all the fields of your type have constexpr default construtors and trivial destructors.
/// Or compile in C++17 mode.
constexpr T tmp{ ubiq_constructor_constexpr_copy{I}... };
(void)tmp;
//static_assert(is_constexpr_aggregate_initializable<T, I...>::value, "====================> Boost.PFR: T must be a constexpr initializable type");
constexpr bool is_flat_refelectable_val = detail::is_flat_refelectable<T>( std::index_sequence<I...>{} );
detail::for_each_field_dispatcher_1(
t,
std::forward<F>(f),
std::index_sequence<I...>{},
std::integral_constant<bool, is_flat_refelectable_val>{}
);
}
#endif // #if !BOOST_PFR_USE_CPP17
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef __clang__
# pragma clang diagnostic pop
#endif
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP

View File

@@ -0,0 +1,277 @@
// Copyright (c) 2017-2018 Alexandr Poltavsky, Antony Polukhin.
// Copyright (c) 2019-2020 Antony Polukhin.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// The Great Type Loophole (C++14)
// Initial implementation by Alexandr Poltavsky, http://alexpolt.github.io
//
// 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
// this blog post http://alexpolt.github.io/type-loophole.html .
//
// This technique exploits the http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118
// CWG 2118. Stateful metaprogramming via friend injection
// Note: CWG agreed that such techniques should be ill-formed, although the mechanism for prohibiting them is as yet undetermined.
#ifndef BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP
#define BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility>
#include <boost/pfr/detail/cast_to_layout_compatible.hpp> // still needed for enums
#include <boost/pfr/detail/offset_based_getter.hpp>
#include <boost/pfr/detail/fields_count.hpp>
#include <boost/pfr/detail/make_flat_tuple_of_references.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
#include <boost/pfr/detail/unsafe_declval.hpp>
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wmissing-braces"
# pragma clang diagnostic ignored "-Wundefined-inline"
# pragma clang diagnostic ignored "-Wundefined-internal"
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
namespace boost { namespace pfr { namespace detail {
// tag<T,N> generates friend declarations and helps with overload resolution.
// There are two types: one with the auto return type, which is the way we read types later.
// The second one is used in the detection of instantiations without which we'd get multiple
// definitions.
template <class T, std::size_t N>
struct tag {
friend auto loophole(tag<T,N>);
};
// The definitions of friend functions.
template <class T, class U, std::size_t N, bool B>
struct fn_def_lref {
friend auto loophole(tag<T,N>) {
// Standard Library containers do not SFINAE on invalid copy constructor. Because of that std::vector<std::unique_ptr<int>> reports that it is copyable,
// which leads to an instantiation error at this place.
//
// To workaround the issue, we check that the type U is movable, and move it in that case.
using no_extents_t = std::remove_all_extents_t<U>;
return static_cast< std::conditional_t<std::is_move_constructible<no_extents_t>::value, no_extents_t&&, no_extents_t&> >(
boost::pfr::detail::unsafe_declval<no_extents_t&>()
);
}
};
template <class T, class U, std::size_t N, bool B>
struct fn_def_rref {
friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval< std::remove_all_extents_t<U>& >()); }
};
// Those specializations are to avoid multiple definition errors.
template <class T, class U, std::size_t N>
struct fn_def_lref<T, U, N, true> {};
template <class T, class U, std::size_t N>
struct fn_def_rref<T, U, N, true> {};
// This has a templated conversion operator which in turn triggers instantiations.
// Important point, using sizeof seems to be more reliable. Also default template
// arguments are "cached" (I think). To fix that I provide a U template parameter to
// the ins functions which do the detection using constexpr friend functions and SFINAE.
template <class T, std::size_t N>
struct loophole_ubiq_lref {
template<class U, std::size_t M> static std::size_t ins(...);
template<class U, std::size_t M, std::size_t = sizeof(loophole(tag<T,M>{})) > static char ins(int);
template<class U, std::size_t = sizeof(fn_def_lref<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)>
constexpr operator U&() const noexcept; // `const` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior.
};
template <class T, std::size_t N>
struct loophole_ubiq_rref {
template<class U, std::size_t M> static std::size_t ins(...);
template<class U, std::size_t M, std::size_t = sizeof(loophole(tag<T,M>{})) > static char ins(int);
template<class U, std::size_t = sizeof(fn_def_rref<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)>
constexpr operator U&&() const noexcept; // `const` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior.
};
// This is a helper to turn a data structure into a tuple.
template <class T, class U>
struct loophole_type_list_lref;
template <typename T, std::size_t... I>
struct loophole_type_list_lref< T, std::index_sequence<I...> >
// Instantiating loopholes:
: sequence_tuple::tuple< decltype(T{ loophole_ubiq_lref<T, I>{}... }, 0) >
{
using type = sequence_tuple::tuple< decltype(loophole(tag<T, I>{}))... >;
};
template <class T, class U>
struct loophole_type_list_rref;
template <typename T, std::size_t... I>
struct loophole_type_list_rref< T, std::index_sequence<I...> >
// Instantiating loopholes:
: sequence_tuple::tuple< decltype(T{ loophole_ubiq_rref<T, I>{}... }, 0) >
{
using type = sequence_tuple::tuple< decltype(loophole(tag<T, I>{}))... >;
};
// Lazily returns loophole_type_list_{lr}ref.
template <bool IsCopyConstructible /*= true*/, class T, class U>
struct loophole_type_list_selector {
using type = loophole_type_list_lref<T, U>;
};
template <class T, class U>
struct loophole_type_list_selector<false /*IsCopyConstructible*/, T, U> {
using type = loophole_type_list_rref<T, U>;
};
template <class T>
auto tie_as_tuple_loophole_impl(T& lvalue) noexcept {
using type = std::remove_cv_t<std::remove_reference_t<T>>;
using indexes = detail::make_index_sequence<fields_count<type>()>;
using loophole_type_list = typename detail::loophole_type_list_selector<
std::is_copy_constructible<std::remove_all_extents_t<type>>::value, type, indexes
>::type;
using tuple_type = typename loophole_type_list::type;
return boost::pfr::detail::make_flat_tuple_of_references(
lvalue,
offset_based_getter<type, tuple_type>{},
size_t_<0>{},
size_t_<tuple_type::size_v>{}
);
}
// Forward declarations:
template <class T> auto tie_as_tuple_recursively(rvalue_t<T> val) noexcept;
template <class T>
auto tie_or_value(T& val, std::enable_if_t<std::is_class< std::remove_reference_t<T> >::value>* = 0) noexcept {
return boost::pfr::detail::tie_as_tuple_recursively(
boost::pfr::detail::tie_as_tuple_loophole_impl(val)
);
}
template <class T>
decltype(auto) tie_or_value(T& val, std::enable_if_t<std::is_enum<std::remove_reference_t<T>>::value>* = 0) noexcept {
// This is compatible with the pre-loophole implementation, and tests, but IIUC it violates strict aliasing unfortunately
return detail::cast_to_layout_compatible<
std::underlying_type_t<std::remove_reference_t<T> >
>(val);
#if 0
// This "works", in that it's usable and it doesn't violate strict aliasing.
// But it means we break compatibility and don't convert enum to underlying type.
return val;
#endif
}
template <class T>
auto tie_or_value(T& /*val*/, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
static_assert(
sizeof(T) && false,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
return 0;
}
template <class T>
decltype(auto) tie_or_value(T& val, std::enable_if_t<!std::is_class< std::remove_reference_t<T> >::value && !std::is_enum< std::remove_reference_t<T> >::value && !std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
return val;
}
template <class T, std::size_t... I>
auto tie_as_tuple_recursively_impl(T& tup, std::index_sequence<I...> ) noexcept
-> sequence_tuple::tuple<
decltype(boost::pfr::detail::tie_or_value(
sequence_tuple::get<I>(tup)
))...
>
{
return {
boost::pfr::detail::tie_or_value(
sequence_tuple::get<I>(tup)
)...
};
}
template <class T>
auto tie_as_tuple_recursively(rvalue_t<T> tup) noexcept {
using indexes = detail::make_index_sequence<T::size_v>;
return boost::pfr::detail::tie_as_tuple_recursively_impl(tup, indexes{});
}
template <class T>
auto tie_as_flat_tuple(T& t) {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
auto rec_tuples = boost::pfr::detail::tie_as_tuple_recursively(
boost::pfr::detail::tie_as_tuple_loophole_impl(t)
);
return boost::pfr::detail::make_flat_tuple_of_references(
rec_tuples, sequence_tuple_getter{}, size_t_<0>{}, size_t_<decltype(rec_tuples)::size_v>{}
);
}
#if !BOOST_PFR_USE_CPP17
template <class T>
auto tie_as_tuple(T& val) noexcept {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
return boost::pfr::detail::tie_as_tuple_loophole_impl(
val
);
}
template <class T, class F, std::size_t... I>
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
std::forward<F>(f)(
boost::pfr::detail::tie_as_tuple_loophole_impl(t)
);
}
#endif // #if !BOOST_PFR_USE_CPP17
}}} // namespace boost::pfr::detail
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
#endif // BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_CORE17_HPP
#define BOOST_PFR_DETAIL_CORE17_HPP
#include <boost/pfr/detail/core17_generated.hpp>
#include <boost/pfr/detail/fields_count.hpp>
#include <boost/pfr/detail/for_each_field_impl.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
namespace boost { namespace pfr { namespace detail {
#ifndef _MSC_VER // MSVC fails to compile the following code, but compiles the structured bindings in core17_generated.hpp
struct do_not_define_std_tuple_size_for_me {
bool test1 = true;
};
template <class T>
constexpr bool do_structured_bindings_work() noexcept { // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
T val{};
const auto& [a] = val; // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
/****************************************************************************
*
* It looks like your compiler or Standard Library can not handle C++17
* structured bindings.
*
* Workaround: Define BOOST_PFR_USE_CPP17 to 0
* It will disable the C++17 features for Boost.PFR library.
*
* Sorry for the inconvenience caused.
*
****************************************************************************/
return a;
}
static_assert(
do_structured_bindings_work<do_not_define_std_tuple_size_for_me>(),
"====================> Boost.PFR: Your compiler can not handle C++17 structured bindings. Read the above comments for workarounds."
);
#endif // #ifndef _MSC_VER
template <class T>
constexpr auto tie_as_tuple(T& val) noexcept {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
typedef size_t_<boost::pfr::detail::fields_count<T>()> fields_count_tag;
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
}
template <class T, class F, std::size_t... I>
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
std::forward<F>(f)(
detail::tie_as_tuple(t)
);
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_CORE17_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_DETECTORS_HPP
#define BOOST_PFR_DETAIL_DETECTORS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
namespace boost { namespace pfr { namespace detail {
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
struct success{};
template <template <class, class> class Detector, class Tleft, class Tright>
struct not_appliable {
static constexpr bool value = std::is_same<
Detector<Tleft, Tright>,
success
>::value;
};
///////////////////// Detectors for different operators
template <class S, class T> auto comp_eq_detector_msvc_helper(long) -> decltype(std::declval<S>() == std::declval<T>());
template <class S, class T> success comp_eq_detector_msvc_helper(int);
template <class T1, class T2> using comp_eq_detector = decltype(comp_eq_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_ne_detector_msvc_helper(long) -> decltype(std::declval<S>() != std::declval<T>());
template <class S, class T> success comp_ne_detector_msvc_helper(int);
template <class T1, class T2> using comp_ne_detector = decltype(comp_ne_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_lt_detector_msvc_helper(long) -> decltype(std::declval<S>() < std::declval<T>());
template <class S, class T> success comp_lt_detector_msvc_helper(int);
template <class T1, class T2> using comp_lt_detector = decltype(comp_lt_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_le_detector_msvc_helper(long) -> decltype(std::declval<S>() <= std::declval<T>());
template <class S, class T> success comp_le_detector_msvc_helper(int);
template <class T1, class T2> using comp_le_detector = decltype(comp_le_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_gt_detector_msvc_helper(long) -> decltype(std::declval<S>() > std::declval<T>());
template <class S, class T> success comp_gt_detector_msvc_helper(int);
template <class T1, class T2> using comp_gt_detector = decltype(comp_gt_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_ge_detector_msvc_helper(long) -> decltype(std::declval<S>() >= std::declval<T>());
template <class S, class T> success comp_ge_detector_msvc_helper(int);
template <class T1, class T2> using comp_ge_detector = decltype(comp_ge_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto ostreamable_detector_msvc_helper(long) -> decltype(std::declval<S>() << std::declval<T>());
template <class S, class T> success ostreamable_detector_msvc_helper(int);
template <class S, class T> using ostreamable_detector = decltype(ostreamable_detector_msvc_helper<S,T>(1L));
template <class S, class T> auto istreamable_detector_msvc_helper(long) -> decltype(std::declval<S>() >> std::declval<T>());
template <class S, class T> success istreamable_detector_msvc_helper(int);
template <class S, class T> using istreamable_detector = decltype(istreamable_detector_msvc_helper<S,T>(1L));
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_DETECTORS_HPP

View File

@@ -0,0 +1,262 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_FIELDS_COUNT_HPP
#define BOOST_PFR_DETAIL_FIELDS_COUNT_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/detail/size_t_.hpp>
#include <boost/pfr/detail/unsafe_declval.hpp>
#include <climits> // CHAR_BIT
#include <type_traits>
#include <utility> // metaprogramming stuff
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wmissing-braces"
# pragma clang diagnostic ignored "-Wundefined-inline"
# pragma clang diagnostic ignored "-Wundefined-internal"
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
#endif
namespace boost { namespace pfr { namespace detail {
///////////////////// Structure that can be converted to reference to anything
struct ubiq_lref_constructor {
std::size_t ignore;
template <class Type> constexpr operator Type&() const noexcept { // Allows initialization of reference fields (T& and const T&)
return detail::unsafe_declval<Type&>();
};
};
///////////////////// Structure that can be converted to rvalue reference to anything
struct ubiq_rref_constructor {
std::size_t ignore;
template <class Type> /*constexpr*/ operator Type&&() const noexcept { // Allows initialization of rvalue reference fields and move-only types
return detail::unsafe_declval<Type&&>();
};
};
#ifndef __cpp_lib_is_aggregate
///////////////////// Hand-made is_aggregate_initializable_n<T> trait
// Structure that can be converted to reference to anything except reference to T
template <class T, bool IsCopyConstructible>
struct ubiq_constructor_except {
std::size_t ignore;
template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&> () const noexcept; // Undefined
};
template <class T>
struct ubiq_constructor_except<T, false> {
std::size_t ignore;
template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&&> () const noexcept; // Undefined
};
// `std::is_constructible<T, ubiq_constructor_except<T>>` consumes a lot of time, so we made a separate lazy trait for it.
template <std::size_t N, class T> struct is_single_field_and_aggregate_initializable: std::false_type {};
template <class T> struct is_single_field_and_aggregate_initializable<1, T>: std::integral_constant<
bool, !std::is_constructible<T, ubiq_constructor_except<T, std::is_copy_constructible<T>::value>>::value
> {};
// Hand-made is_aggregate<T> trait:
// Before C++20 aggregates could be constructed from `decltype(ubiq_?ref_constructor{I})...` but type traits report that
// there's no constructor from `decltype(ubiq_?ref_constructor{I})...`
// Special case for N == 1: `std::is_constructible<T, ubiq_?ref_constructor>` returns true if N == 1 and T is copy/move constructible.
template <class T, std::size_t N>
struct is_aggregate_initializable_n {
template <std::size_t ...I>
static constexpr bool is_not_constructible_n(std::index_sequence<I...>) noexcept {
return (!std::is_constructible<T, decltype(ubiq_lref_constructor{I})...>::value && !std::is_constructible<T, decltype(ubiq_rref_constructor{I})...>::value)
|| is_single_field_and_aggregate_initializable<N, T>::value
;
}
static constexpr bool value =
std::is_empty<T>::value
|| std::is_array<T>::value
|| std::is_fundamental<T>::value
|| is_not_constructible_n(detail::make_index_sequence<N>{})
;
};
#endif // #ifndef __cpp_lib_is_aggregate
///////////////////// Helper for SFINAE on fields count
template <class T, std::size_t... I, class /*Enable*/ = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
-> typename std::add_pointer<decltype(T{ ubiq_lref_constructor{I}... })>::type;
template <class T, std::size_t... I, class /*Enable*/ = typename std::enable_if<!std::is_copy_constructible<T>::value>::type>
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
-> typename std::add_pointer<decltype(T{ ubiq_rref_constructor{I}... })>::type;
template <class T, std::size_t N, class /*Enable*/ = decltype( enable_if_constructible_helper<T>(detail::make_index_sequence<N>()) ) >
using enable_if_constructible_helper_t = std::size_t;
///////////////////// Helpers for range size detection
template <std::size_t Begin, std::size_t Last>
using is_one_element_range = std::integral_constant<bool, Begin == Last>;
using multi_element_range = std::false_type;
using one_element_range = std::true_type;
///////////////////// Non greedy fields count search. Templates instantiation depth is log(sizeof(T)), templates instantiation count is log(sizeof(T)).
template <class T, std::size_t Begin, std::size_t Middle>
constexpr std::size_t detect_fields_count(detail::one_element_range, long) noexcept {
static_assert(
Begin == Middle,
"====================> Boost.PFR: Internal logic error."
);
return Begin;
}
template <class T, std::size_t Begin, std::size_t Middle>
constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept;
template <class T, std::size_t Begin, std::size_t Middle>
constexpr auto detect_fields_count(detail::multi_element_range, long) noexcept
-> detail::enable_if_constructible_helper_t<T, Middle>
{
constexpr std::size_t next_v = Middle + (Middle - Begin + 1) / 2;
return detail::detect_fields_count<T, Middle, next_v>(detail::is_one_element_range<Middle, next_v>{}, 1L);
}
template <class T, std::size_t Begin, std::size_t Middle>
constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept {
constexpr std::size_t next_v = Begin + (Middle - Begin) / 2;
return detail::detect_fields_count<T, Begin, next_v>(detail::is_one_element_range<Begin, next_v>{}, 1L);
}
///////////////////// Greedy search. Templates instantiation depth is log(sizeof(T)), templates instantiation count is log(sizeof(T))*T in worst case.
template <class T, std::size_t N>
constexpr auto detect_fields_count_greedy_remember(long) noexcept
-> detail::enable_if_constructible_helper_t<T, N>
{
return N;
}
template <class T, std::size_t N>
constexpr std::size_t detect_fields_count_greedy_remember(int) noexcept {
return 0;
}
template <class T, std::size_t Begin, std::size_t Last>
constexpr std::size_t detect_fields_count_greedy(detail::one_element_range) noexcept {
static_assert(
Begin == Last,
"====================> Boost.PFR: Internal logic error."
);
return detail::detect_fields_count_greedy_remember<T, Begin>(1L);
}
template <class T, std::size_t Begin, std::size_t Last>
constexpr std::size_t detect_fields_count_greedy(detail::multi_element_range) noexcept {
constexpr std::size_t middle = Begin + (Last - Begin) / 2;
constexpr std::size_t fields_count_big_range = detail::detect_fields_count_greedy<T, middle + 1, Last>(
detail::is_one_element_range<middle + 1, Last>{}
);
constexpr std::size_t small_range_begin = (fields_count_big_range ? 0 : Begin);
constexpr std::size_t small_range_last = (fields_count_big_range ? 0 : middle);
constexpr std::size_t fields_count_small_range = detail::detect_fields_count_greedy<T, small_range_begin, small_range_last>(
detail::is_one_element_range<small_range_begin, small_range_last>{}
);
return fields_count_big_range ? fields_count_big_range : fields_count_small_range;
}
///////////////////// Choosing between array size, greedy and non greedy search.
template <class T, std::size_t N>
constexpr auto detect_fields_count_dispatch(size_t_<N>, long, long) noexcept
-> typename std::enable_if<std::is_array<T>::value, std::size_t>::type
{
return sizeof(T) / sizeof(typename std::remove_all_extents<T>::type);
}
template <class T, std::size_t N>
constexpr auto detect_fields_count_dispatch(size_t_<N>, long, int) noexcept
-> decltype(sizeof(T{}))
{
constexpr std::size_t middle = N / 2 + 1;
return detail::detect_fields_count<T, 0, middle>(detail::multi_element_range{}, 1L);
}
template <class T, std::size_t N>
constexpr std::size_t detect_fields_count_dispatch(size_t_<N>, int, int) noexcept {
// T is not default aggregate initialzable. It means that at least one of the members is not default constructible,
// so we have to check all the aggregate initializations for T up to N parameters and return the bigest succeeded
// (we can not use binary search for detecting fields count).
return detail::detect_fields_count_greedy<T, 0, N>(detail::multi_element_range{});
}
///////////////////// Returns non-flattened fields count
template <class T>
constexpr std::size_t fields_count() noexcept {
using type = std::remove_cv_t<T>;
static_assert(
!std::is_reference<type>::value,
"====================> Boost.PFR: Attempt to get fields count on a reference. This is not allowed because that could hide an issue and different library users expect different behavior in that case."
);
static_assert(
std::is_copy_constructible<std::remove_all_extents_t<type>>::value || (
std::is_move_constructible<std::remove_all_extents_t<type>>::value
&& std::is_move_assignable<std::remove_all_extents_t<type>>::value
),
"====================> Boost.PFR: Type and each field in the type must be copy constructible (or move constructible and move assignable)."
);
static_assert(
!std::is_polymorphic<type>::value,
"====================> Boost.PFR: Type must have no virtual function, because otherwise it is not aggregate initializable."
);
#ifdef __cpp_lib_is_aggregate
static_assert(
std::is_aggregate<type>::value // Does not return `true` for build in types.
|| std::is_scalar<type>::value,
"====================> Boost.PFR: Type must be aggregate initializable."
);
#endif
// Can't use the following. See the non_std_layout.cpp test.
//#if !BOOST_PFR_USE_CPP17
// static_assert(
// std::is_standard_layout<type>::value, // Does not return `true` for structs that have non standard layout members.
// "Type must be aggregate initializable."
// );
//#endif
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT); // We multiply by CHAR_BIT because the type may have bitfields in T
constexpr std::size_t result = detail::detect_fields_count_dispatch<type>(size_t_<max_fields_count>{}, 1L, 1L);
#ifndef __cpp_lib_is_aggregate
static_assert(
is_aggregate_initializable_n<type, result>::value,
"====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported."
);
#endif
static_assert(
result != 0 || std::is_empty<type>::value || std::is_fundamental<type>::value || std::is_reference<type>::value,
"====================> Boost.PFR: If there's no other failed static asserts then something went wrong. Please report this issue to the github along with the structure you're reflecting."
);
return result;
}
}}} // namespace boost::pfr::detail
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif // BOOST_PFR_DETAIL_FIELDS_COUNT_HPP

View File

@@ -0,0 +1,41 @@
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_FLAT_TIE_FROM_STRUCTURE_TUPLE_HPP
#define BOOST_PFR_DETAIL_FLAT_TIE_FROM_STRUCTURE_TUPLE_HPP
#pragma once
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
namespace boost { namespace pfr { namespace detail {
/// \brief A `std::tuple` capable of de-structuring assignment used to support
/// a tie of multiple lvalue references to \flattening{flattened} fields of an
/// aggregate T.
///
/// \sa boost::pfr::flat_tie_from_structure
///
template <typename... Elements>
struct flat_tie_from_structure_tuple : std::tuple<Elements&...> {
using base = std::tuple<Elements&...>;
using base::base;
template <typename T>
constexpr flat_tie_from_structure_tuple& operator= (T const& t) {
base::operator=(
detail::make_stdtiedtuple_from_tietuple(
detail::tie_as_flat_tuple(t),
detail::make_index_sequence<flat_tuple_size_v<T>>()));
return *this;
}
};
}}} // boost::pfr::detail
#endif // BOOST_PFR_DETAIL_FLAT_TIE_FROM_STRUCTURE_TUPLE_HPP

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP
#define BOOST_PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
namespace boost { namespace pfr { namespace detail {
template <std::size_t Index>
using size_t_ = std::integral_constant<std::size_t, Index >;
template <class T, class F, class I, class = decltype(std::declval<F>()(std::declval<T>(), I{}))>
void for_each_field_impl_apply(T&& v, F&& f, I i, long) {
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) {
std::forward<F>(f)(std::forward<T>(v));
}
template <class T, class F, std::size_t... I>
void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type /*move_values*/) {
const int v[] = {(
detail::for_each_field_impl_apply(sequence_tuple::get<I>(t), std::forward<F>(f), size_t_<I>{}, 1L),
0
)...};
(void)v;
}
template <class T, class F, std::size_t... I>
void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type /*move_values*/) {
const int v[] = {(
detail::for_each_field_impl_apply(sequence_tuple::get<I>(std::move(t)), std::forward<F>(f), size_t_<I>{}, 1L),
0
)...};
(void)v;
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP

View File

@@ -0,0 +1,150 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_FUNCTIONAL_HPP
#define BOOST_PFR_DETAIL_FUNCTIONAL_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <functional>
#include <boost/pfr/detail/sequence_tuple.hpp>
namespace boost { namespace pfr { namespace detail {
template <std::size_t I, std::size_t N>
struct equal_impl {
template <class T, class U>
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
return ::boost::pfr::detail::sequence_tuple::get<I>(v1) == ::boost::pfr::detail::sequence_tuple::get<I>(v2)
&& equal_impl<I + 1, N>::cmp(v1, v2);
}
};
template <std::size_t N>
struct equal_impl<N, N> {
template <class T, class U>
constexpr static bool cmp(const T&, const U&) noexcept {
return T::size_v == U::size_v;
}
};
template <std::size_t I, std::size_t N>
struct not_equal_impl {
template <class T, class U>
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
return ::boost::pfr::detail::sequence_tuple::get<I>(v1) != ::boost::pfr::detail::sequence_tuple::get<I>(v2)
|| not_equal_impl<I + 1, N>::cmp(v1, v2);
}
};
template <std::size_t N>
struct not_equal_impl<N, N> {
template <class T, class U>
constexpr static bool cmp(const T&, const U&) noexcept {
return T::size_v != U::size_v;
}
};
template <std::size_t I, std::size_t N>
struct less_impl {
template <class T, class U>
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
return sequence_tuple::get<I>(v1) < sequence_tuple::get<I>(v2)
|| (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && less_impl<I + 1, N>::cmp(v1, v2));
}
};
template <std::size_t N>
struct less_impl<N, N> {
template <class T, class U>
constexpr static bool cmp(const T&, const U&) noexcept {
return T::size_v < U::size_v;
}
};
template <std::size_t I, std::size_t N>
struct less_equal_impl {
template <class T, class U>
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
return sequence_tuple::get<I>(v1) < sequence_tuple::get<I>(v2)
|| (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && less_equal_impl<I + 1, N>::cmp(v1, v2));
}
};
template <std::size_t N>
struct less_equal_impl<N, N> {
template <class T, class U>
constexpr static bool cmp(const T&, const U&) noexcept {
return T::size_v <= U::size_v;
}
};
template <std::size_t I, std::size_t N>
struct greater_impl {
template <class T, class U>
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
return sequence_tuple::get<I>(v1) > sequence_tuple::get<I>(v2)
|| (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && greater_impl<I + 1, N>::cmp(v1, v2));
}
};
template <std::size_t N>
struct greater_impl<N, N> {
template <class T, class U>
constexpr static bool cmp(const T&, const U&) noexcept {
return T::size_v > U::size_v;
}
};
template <std::size_t I, std::size_t N>
struct greater_equal_impl {
template <class T, class U>
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
return sequence_tuple::get<I>(v1) > sequence_tuple::get<I>(v2)
|| (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && greater_equal_impl<I + 1, N>::cmp(v1, v2));
}
};
template <std::size_t N>
struct greater_equal_impl<N, N> {
template <class T, class U>
constexpr static bool cmp(const T&, const U&) noexcept {
return T::size_v >= U::size_v;
}
};
template <typename SizeT>
constexpr void hash_combine(SizeT& seed, SizeT value) noexcept {
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
template <std::size_t I, std::size_t N>
struct hash_impl {
template <class T>
constexpr static std::size_t compute(const T& val) noexcept {
typedef std::decay_t<typename detail::sequence_tuple::tuple_element<I, T>::type> elem_t;
std::size_t h = std::hash<elem_t>()( ::boost::pfr::detail::sequence_tuple::get<I>(val) );
detail::hash_combine(h, hash_impl<I + 1, N>::compute(val) );
return h;
}
};
template <std::size_t N>
struct hash_impl<N, N> {
template <class T>
constexpr static std::size_t compute(const T&) noexcept {
return 0;
}
};
///////////////////// Define min_element and to avoid inclusion of <algorithm>
constexpr std::size_t min_size(std::size_t x, std::size_t y) noexcept {
return x < y ? x : y;
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_FUNCTIONAL_HPP

View File

@@ -0,0 +1,85 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_IO_HPP
#define BOOST_PFR_DETAIL_IO_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <iosfwd> // stream operators
#include <iomanip>
#if defined(__has_include)
# if __has_include(<string_view>) && BOOST_PFR_USE_CPP17
# include <string_view>
# endif
#endif
namespace boost { namespace pfr { namespace detail {
inline auto quoted_helper(const std::string& s) noexcept {
return std::quoted(s);
}
#if defined(__has_include)
# if __has_include(<string_view>) && BOOST_PFR_USE_CPP17
template <class CharT, class Traits>
inline auto quoted_helper(std::basic_string_view<CharT, Traits> s) noexcept {
return std::quoted(s);
}
# endif
#endif
inline auto quoted_helper(std::string& s) noexcept {
return std::quoted(s);
}
template <class T>
inline decltype(auto) quoted_helper(T&& v) noexcept {
return std::forward<T>(v);
}
template <std::size_t I, std::size_t N>
struct print_impl {
template <class Stream, class T>
static void print (Stream& out, const T& value) {
if (!!I) out << ", ";
out << detail::quoted_helper(boost::pfr::detail::sequence_tuple::get<I>(value));
print_impl<I + 1, N>::print(out, value);
}
};
template <std::size_t I>
struct print_impl<I, I> {
template <class Stream, class T> static void print (Stream&, const T&) noexcept {}
};
template <std::size_t I, std::size_t N>
struct read_impl {
template <class Stream, class T>
static void read (Stream& in, const T& value) {
char ignore = {};
if (!!I) {
in >> ignore;
if (ignore != ',') in.setstate(Stream::failbit);
in >> ignore;
if (ignore != ' ') in.setstate(Stream::failbit);
}
in >> detail::quoted_helper( boost::pfr::detail::sequence_tuple::get<I>(value) );
read_impl<I + 1, N>::read(in, value);
}
};
template <std::size_t I>
struct read_impl<I, I> {
template <class Stream, class T> static void read (Stream&, const T&) {}
};
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_IO_HPP

View File

@@ -0,0 +1,96 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_MAKE_FLAT_TUPLE_OF_REFERENCES_HPP
#define BOOST_PFR_DETAIL_MAKE_FLAT_TUPLE_OF_REFERENCES_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
namespace boost { namespace pfr { namespace detail {
template <std::size_t Index>
using size_t_ = std::integral_constant<std::size_t, Index >;
// Helper: Make a "getter" object corresponding to built-in tuple::get
// For user-defined structures, the getter should be "offset_based_getter"
struct sequence_tuple_getter {
template <std::size_t idx, typename TupleOfReferences>
decltype(auto) get(TupleOfReferences&& t, size_t_<idx>) const noexcept {
return sequence_tuple::get<idx>(std::forward<TupleOfReferences>(t));
}
};
template <class TupleOrUserType, class Getter, std::size_t Begin, std::size_t Size>
constexpr auto make_flat_tuple_of_references(TupleOrUserType&, const Getter&, size_t_<Begin>, size_t_<Size>) noexcept;
template <class TupleOrUserType, class Getter, std::size_t Begin>
constexpr sequence_tuple::tuple<> make_flat_tuple_of_references(TupleOrUserType&, const Getter&, size_t_<Begin>, size_t_<0>) noexcept;
template <class TupleOrUserType, class Getter, std::size_t Begin>
constexpr auto make_flat_tuple_of_references(TupleOrUserType&, const Getter&, size_t_<Begin>, size_t_<1>) noexcept;
template <class... T>
constexpr auto tie_as_tuple_with_references(T&... args) noexcept {
return sequence_tuple::tuple<T&...>{ args... };
}
template <class... T>
constexpr decltype(auto) tie_as_tuple_with_references(detail::sequence_tuple::tuple<T...>& t) noexcept {
return detail::make_flat_tuple_of_references(t, sequence_tuple_getter{}, size_t_<0>{}, size_t_<sequence_tuple::tuple<T...>::size_v>{});
}
template <class... T>
constexpr decltype(auto) tie_as_tuple_with_references(const detail::sequence_tuple::tuple<T...>& t) noexcept {
return detail::make_flat_tuple_of_references(t, sequence_tuple_getter{}, size_t_<0>{}, size_t_<sequence_tuple::tuple<T...>::size_v>{});
}
template <class Tuple1, std::size_t... I1, class Tuple2, std::size_t... I2>
constexpr auto my_tuple_cat_impl(const Tuple1& t1, std::index_sequence<I1...>, const Tuple2& t2, std::index_sequence<I2...>) noexcept {
return detail::tie_as_tuple_with_references(
sequence_tuple::get<I1>(t1)...,
sequence_tuple::get<I2>(t2)...
);
}
template <class Tuple1, class Tuple2>
constexpr auto my_tuple_cat(const Tuple1& t1, const Tuple2& t2) noexcept {
return detail::my_tuple_cat_impl(
t1, detail::make_index_sequence< Tuple1::size_v >{},
t2, detail::make_index_sequence< Tuple2::size_v >{}
);
}
template <class TupleOrUserType, class Getter, std::size_t Begin, std::size_t Size>
constexpr auto make_flat_tuple_of_references(TupleOrUserType& t, const Getter& g, size_t_<Begin>, size_t_<Size>) noexcept {
constexpr std::size_t next_size = Size / 2;
return detail::my_tuple_cat(
detail::make_flat_tuple_of_references(t, g, size_t_<Begin>{}, size_t_<next_size>{}),
detail::make_flat_tuple_of_references(t, g, size_t_<Begin + Size / 2>{}, size_t_<Size - next_size>{})
);
}
template <class TupleOrUserType, class Getter, std::size_t Begin>
constexpr sequence_tuple::tuple<> make_flat_tuple_of_references(TupleOrUserType&, const Getter&, size_t_<Begin>, size_t_<0>) noexcept {
return {};
}
template <class TupleOrUserType, class Getter, std::size_t Begin>
constexpr auto make_flat_tuple_of_references(TupleOrUserType& t, const Getter& g, size_t_<Begin>, size_t_<1>) noexcept {
return detail::tie_as_tuple_with_references(
g.get(t, size_t_<Begin>{})
);
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_MAKE_FLAT_TUPLE_OF_REFERENCES_HPP

View File

@@ -0,0 +1,90 @@
// Copyright (c) 2018 Sergei Fedorov
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_MAKE_INTEGER_SEQUENCE_HPP
#define BOOST_PFR_DETAIL_MAKE_INTEGER_SEQUENCE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility>
#include <cstddef>
namespace boost { namespace pfr { namespace detail {
#if BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == 0
#ifdef __has_builtin
# if __has_builtin(__make_integer_seq)
# define BOOST_PFR_USE_MAKE_INTEGER_SEQ_BUILTIN
# endif
#endif
#ifdef BOOST_PFR_USE_MAKE_INTEGER_SEQ_BUILTIN
using std::integer_sequence;
// Clang unable to use namespace qualified std::integer_sequence in __make_integer_seq.
template <typename T, T N>
using make_integer_sequence = __make_integer_seq<integer_sequence, T, N>;
#undef BOOST_PFR_USE_MAKE_INTEGER_SEQ_BUILTIN
#else
template <typename T, typename U>
struct join_sequences;
template <typename T, T... A, T... B>
struct join_sequences<std::integer_sequence<T, A...>, std::integer_sequence<T, B...>> {
using type = std::integer_sequence<T, A..., B...>;
};
template <typename T, T Min, T Max>
struct build_sequence_impl {
static_assert(Min < Max, "Start of range must be less than it's end");
static constexpr T size = Max - Min;
using type = typename join_sequences<
typename build_sequence_impl<T, Min, Min + size / 2>::type,
typename build_sequence_impl<T, Min + size / 2 + 1, Max>::type
>::type;
};
template <typename T, T V>
struct build_sequence_impl<T, V, V> {
using type = std::integer_sequence<T, V>;
};
template <typename T, std::size_t N>
struct make_integer_sequence_impl : build_sequence_impl<T, 0, N - 1> {};
template <typename T>
struct make_integer_sequence_impl<T, 0> {
using type = std::integer_sequence<T>;
};
template <typename T, T N>
using make_integer_sequence = typename make_integer_sequence_impl<T, N>::type;
#endif // !defined BOOST_PFR_USE_MAKE_INTEGER_SEQ_BUILTIN
#else // BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == 1
template <typename T, T N>
using make_integer_sequence = std::make_integer_sequence<T, N>;
#endif // BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == 1
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <typename... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
}}} // namespace boost::pfr::detail
#endif

View File

@@ -0,0 +1,142 @@
// Copyright (c) 2017-2018 Chris Beck
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_OFFSET_BASED_GETTER_HPP
#define BOOST_PFR_DETAIL_OFFSET_BASED_GETTER_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
namespace boost { namespace pfr { namespace detail {
template <std::size_t Index>
using size_t_ = std::integral_constant<std::size_t, Index >;
// Our own implementation of std::aligned_storage. On godbolt with MSVC, I have compilation errors
// using the standard version, it seems the compiler cannot generate default ctor.
template<std::size_t s, std::size_t a>
struct internal_aligned_storage {
alignas(a) char storage_[s];
};
// Metafunction that replaces tuple<T1, T2, T3, ...> with
// tuple<std::aligned_storage_t<sizeof(T1), alignof(T1)>, std::aligned_storage<sizeof(T2), alignof(T2)>, ...>
//
// The point is, the new tuple is "layout compatible" in the sense that members have the same offsets,
// but this tuple is constexpr constructible.
template <typename T>
struct tuple_of_aligned_storage;
template <typename... Ts>
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.
(alignof(Ts) > 4 ? 4 : alignof(Ts))
#else
alignof(Ts)
#endif
>...>;
};
// Note: If pfr has a typelist also, could also have an overload for that here
template <typename T>
using tuple_of_aligned_storage_t = typename tuple_of_aligned_storage<T>::type;
/***
* Given a structure type and its sequence of members, we want to build a function
* object "getter" that implements a version of `std::get` using offset arithmetic
* and reinterpret_cast.
*
* typename U should be a user-defined struct
* typename S should be a sequence_tuple which is layout compatible with U
*/
template <typename U, typename S>
class offset_based_getter {
using this_t = offset_based_getter<U, S>;
static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");
static_assert(alignof(U) == alignof(S), "====================> Boost.PFR: Member sequence does not indicate correct alignment for struct type!");
static_assert(!std::is_const<U>::value, "====================> Boost.PFR: const should be stripped from user-defined type when using offset_based_getter or overload resolution will be ambiguous later, this indicates an error within pfr");
static_assert(!std::is_reference<U>::value, "====================> Boost.PFR: reference should be stripped from user-defined type when using offset_based_getter or overload resolution will be ambiguous later, this indicates an error within pfr");
static_assert(!std::is_volatile<U>::value, "====================> Boost.PFR: volatile should be stripped from user-defined type when using offset_based_getter or overload resolution will be ambiguous later. this indicates an error within pfr");
// Get type of idx'th member
template <std::size_t idx>
using index_t = typename sequence_tuple::tuple_element<idx, S>::type;
// Get offset of idx'th member
// Idea: Layout object has the same offsets as instance of S, so if S and U are layout compatible, then these offset
// calculations are correct.
template <std::size_t idx>
static constexpr std::ptrdiff_t offset() noexcept {
constexpr tuple_of_aligned_storage_t<S> layout{};
return &sequence_tuple::get<idx>(layout).storage_[0] - &sequence_tuple::get<0>(layout).storage_[0];
}
// Encapsulates offset arithmetic and reinterpret_cast
template <std::size_t idx>
static index_t<idx> * get_pointer(U * u) noexcept {
return reinterpret_cast<index_t<idx> *>(reinterpret_cast<char *>(u) + this_t::offset<idx>());
}
template <std::size_t idx>
static const index_t<idx> * get_pointer(const U * u) noexcept {
return reinterpret_cast<const index_t<idx> *>(reinterpret_cast<const char *>(u) + this_t::offset<idx>());
}
template <std::size_t idx>
static volatile index_t<idx> * get_pointer(volatile U * u) noexcept {
return reinterpret_cast<volatile index_t<idx> *>(reinterpret_cast<volatile char *>(u) + this_t::offset<idx>());
}
template <std::size_t idx>
static const volatile index_t<idx> * get_pointer(const volatile U * u) noexcept {
return reinterpret_cast<const volatile index_t<idx> *>(reinterpret_cast<const volatile char *>(u) + this_t::offset<idx>());
}
public:
template <std::size_t idx>
index_t<idx> & get(U & u, size_t_<idx>) const noexcept {
return *this_t::get_pointer<idx>(std::addressof(u));
}
template <std::size_t idx>
index_t<idx> const & get(U const & u, size_t_<idx>) const noexcept {
return *this_t::get_pointer<idx>(std::addressof(u));
}
template <std::size_t idx>
index_t<idx> volatile & get(U volatile & u, size_t_<idx>) const noexcept {
return *this_t::get_pointer<idx>(std::addressof(u));
}
template <std::size_t idx>
index_t<idx> const volatile & get(U const volatile & u, size_t_<idx>) const noexcept {
return *this_t::get_pointer<idx>(std::addressof(u));
}
// rvalues must not be used here, to avoid template instantiation bloats.
template <std::size_t idx>
index_t<idx> && get(rvalue_t<U> u, size_t_<idx>) const = delete;
};
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_OFFSET_LIST_HPP

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_RVALUE_T_HPP
#define BOOST_PFR_DETAIL_RVALUE_T_HPP
#pragma once
#include <type_traits>
#include <utility> // std::enable_if_t
// This header provides aliases rvalue_t and lvalue_t.
//
// Usage: template <class T> void foo(rvalue<T> rvalue);
//
// Those are useful for
// * better type safety - you can validate at compile time that only rvalue reference is passed into the function
// * documentation and readability - rvalue_t<T> is much better than T&&+SFINAE
namespace boost { namespace pfr { namespace detail {
/// Binds to rvalues only, no copying allowed.
template <class T
#ifdef BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING
, class = std::enable_if_t<std::is_rvalue_reference<T&&>::value>
#endif
>
using rvalue_t = T&&;
/// Binds to mutable lvalues only
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_RVALUE_T_HPP

View File

@@ -0,0 +1,127 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_SEQUENCE_TUPLE_HPP
#define BOOST_PFR_DETAIL_SEQUENCE_TUPLE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <utility> // metaprogramming stuff
#include <cstddef> // std::size_t
///////////////////// Tuple that holds it's values in the supplied order
namespace boost { namespace pfr { namespace detail { namespace sequence_tuple {
template <std::size_t N, class T>
struct base_from_member {
T value;
};
template <class I, class ...Tail>
struct tuple_base;
template <std::size_t... I, class ...Tail>
struct tuple_base< std::index_sequence<I...>, Tail... >
: base_from_member<I , Tail>...
{
static constexpr std::size_t size_v = sizeof...(I);
// We do not use `noexcept` in the following functions, because if user forget to put one then clang will issue an error:
// "error: exception specification of explicitly defaulted default constructor does not match the calculated one".
constexpr tuple_base() = default;
constexpr tuple_base(tuple_base&&) = default;
constexpr tuple_base(const tuple_base&) = default;
constexpr tuple_base(Tail... v) noexcept
: base_from_member<I, Tail>{ v }...
{}
};
template <>
struct tuple_base<std::index_sequence<> > {
static constexpr std::size_t size_v = 0;
};
template <std::size_t N, class T>
constexpr T& get_impl(base_from_member<N, T>& t) noexcept {
return t.value;
}
template <std::size_t N, class T>
constexpr const T& get_impl(const base_from_member<N, T>& t) noexcept {
return t.value;
}
template <std::size_t N, class T>
constexpr volatile T& get_impl(volatile base_from_member<N, T>& t) noexcept {
return t.value;
}
template <std::size_t N, class T>
constexpr const volatile T& get_impl(const volatile base_from_member<N, T>& t) noexcept {
return t.value;
}
template <std::size_t N, class T>
constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
return std::forward<T>(t.value);
}
template <class ...Values>
struct tuple: tuple_base<
detail::index_sequence_for<Values...>,
Values...>
{
using tuple_base<
detail::index_sequence_for<Values...>,
Values...
>::tuple_base;
};
template <std::size_t N, class ...T>
constexpr decltype(auto) get(tuple<T...>& t) noexcept {
static_assert(N < tuple<T...>::size_v, "====================> Boost.PFR: Tuple index out of bounds");
return sequence_tuple::get_impl<N>(t);
}
template <std::size_t N, class ...T>
constexpr decltype(auto) get(const tuple<T...>& t) noexcept {
static_assert(N < tuple<T...>::size_v, "====================> Boost.PFR: Tuple index out of bounds");
return sequence_tuple::get_impl<N>(t);
}
template <std::size_t N, class ...T>
constexpr decltype(auto) get(const volatile tuple<T...>& t) noexcept {
static_assert(N < tuple<T...>::size_v, "====================> Boost.PFR: Tuple index out of bounds");
return sequence_tuple::get_impl<N>(t);
}
template <std::size_t N, class ...T>
constexpr decltype(auto) get(volatile tuple<T...>& t) noexcept {
static_assert(N < tuple<T...>::size_v, "====================> Boost.PFR: Tuple index out of bounds");
return sequence_tuple::get_impl<N>(t);
}
template <std::size_t N, class ...T>
constexpr decltype(auto) get(tuple<T...>&& t) noexcept {
static_assert(N < tuple<T...>::size_v, "====================> Boost.PFR: Tuple index out of bounds");
return sequence_tuple::get_impl<N>(std::move(t));
}
template <std::size_t I, class T>
using tuple_element = std::remove_reference< decltype(
::boost::pfr::detail::sequence_tuple::get<I>( std::declval<T>() )
) >;
}}}} // namespace boost::pfr::detail::sequence_tuple
#endif // BOOST_PFR_CORE_HPP

View File

@@ -0,0 +1,79 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_SIZE_ARRAY_HPP
#define BOOST_PFR_DETAIL_SIZE_ARRAY_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <cstddef> // metaprogramming stuff
namespace boost { namespace pfr { namespace detail {
///////////////////// Array that has the constexpr
template <std::size_t N>
struct size_array { // libc++ misses constexpr on operator[]
typedef std::size_t type;
std::size_t data[N];
static constexpr std::size_t size() noexcept { return N; }
constexpr std::size_t count_nonzeros() const noexcept {
std::size_t count = 0;
for (std::size_t i = 0; i < size(); ++i) {
if (data[i]) {
++ count;
}
}
return count;
}
constexpr std::size_t count_from_opening_till_matching_parenthis_seq(std::size_t from, std::size_t opening_parenthis, std::size_t closing_parenthis) const noexcept {
if (data[from] != opening_parenthis) {
return 0;
}
std::size_t unclosed_parnthesis = 0;
std::size_t count = 0;
for (; ; ++from) {
if (data[from] == opening_parenthis) {
++ unclosed_parnthesis;
} else if (data[from] == closing_parenthis) {
-- unclosed_parnthesis;
}
++ count;
if (unclosed_parnthesis == 0) {
return count;
}
}
return count;
}
};
template <>
struct size_array<0> { // libc++ misses constexpr on operator[]
typedef std::size_t type;
std::size_t data[1];
static constexpr std::size_t size() noexcept { return 0; }
constexpr std::size_t count_nonzeros() const noexcept {
return 0;
}
};
template <std::size_t I, std::size_t N>
constexpr std::size_t get(const size_array<N>& a) noexcept {
static_assert(I < N, "====================> Boost.PFR: Array index out of bounds");
return a.data[I];
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_SIZE_ARRAY_HPP

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_SIZE_T_HPP
#define BOOST_PFR_DETAIL_SIZE_T_HPP
#pragma once
namespace boost { namespace pfr { namespace detail {
///////////////////// General utility stuff
template <std::size_t Index>
using size_t_ = std::integral_constant<std::size_t, Index >;
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_SIZE_T_HPP

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_STDTUPLE_HPP
#define BOOST_PFR_DETAIL_STDTUPLE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <utility> // metaprogramming stuff
#include <tuple>
#include <boost/pfr/detail/sequence_tuple.hpp>
namespace boost { namespace pfr { namespace detail {
template <class T, std::size_t... I>
constexpr auto make_stdtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
return std::make_tuple(
boost::pfr::detail::sequence_tuple::get<I>(t)...
);
}
template <class T, std::size_t... I>
constexpr auto make_stdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
return std::tie(
boost::pfr::detail::sequence_tuple::get<I>(t)...
);
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_STDTUPLE_HPP

View File

@@ -0,0 +1,45 @@
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP
#define BOOST_PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP
#pragma once
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
#include <tuple>
namespace boost { namespace pfr { namespace detail {
/// \brief A `std::tuple` capable of de-structuring assignment used to support
/// a tie of multiple lvalue references to fields of an aggregate T.
///
/// \sa boost::pfr::tie_from_structure
template <typename... Elements>
struct tie_from_structure_tuple : std::tuple<Elements&...> {
using base = std::tuple<Elements&...>;
using base::base;
template <typename T>
constexpr tie_from_structure_tuple& operator= (T const& t) {
base::operator=(
detail::make_stdtiedtuple_from_tietuple(
detail::tie_as_tuple(t),
detail::make_index_sequence<tuple_size_v<T>>()));
return *this;
}
};
}}} // boost::pfr::detail
#endif // BOOST_PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2019-2020 Antony Polukhin.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
#define BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
namespace boost { namespace pfr { namespace detail {
// This function serves as a link-time assert. If linker requires it, then
// `unsafe_declval()` is used at runtime.
void report_if_you_see_link_error_with_this_function() noexcept;
// For returning non default constructible types. Do NOT use at runtime!
//
// GCC's std::declval may not be used in potentionally evaluated contexts,
// so we reinvent it.
template <class T>
constexpr T unsafe_declval() noexcept {
report_if_you_see_link_error_with_this_function();
typename std::remove_reference<T>::type* ptr = 0;
ptr += 42; // suppresses 'null pointer dereference' warnings
return static_cast<T>(*ptr);
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_HPP
#define BOOST_PFR_FLAT_HPP
/// \file boost/pfr/flat.hpp
/// Includes all the Boost.PFR headers that define `flat_*` functions, except \xmlonly<link linkend='header.boost.pfr.flat.global_ops_hpp'>boost/pfr/flat/global_ops.hpp</link>\endxmlonly
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/ops.hpp>
#include <boost/pfr/flat/io.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/flat/functions_for.hpp>
#endif // BOOST_PFR_FLAT_HPP

View File

@@ -0,0 +1,161 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_CORE_HPP
#define BOOST_PFR_FLAT_CORE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/detail/for_each_field_impl.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/detail/flat_tie_from_structure_tuple.hpp>
namespace boost { namespace pfr {
/// \brief Returns reference or const reference to a field with index `I` in \flattening{flattened} T.
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s {10, 11};
/// assert(boost::pfr::flat_get<0>(s) == 10);
/// boost::pfr::flat_get<1>(s) = 0;
/// \endcode
template <std::size_t I, class T>
decltype(auto) flat_get(const T& val) noexcept {
return boost::pfr::detail::sequence_tuple::get<I>( boost::pfr::detail::tie_as_flat_tuple(val) );
}
/// \overload flat_get
template <std::size_t I, class T>
decltype(auto) flat_get(T& val /* @cond */, std::enable_if_t< std::is_trivially_assignable<T, T>::value>* = 0/* @endcond */ ) noexcept {
return boost::pfr::detail::sequence_tuple::get<I>( boost::pfr::detail::tie_as_flat_tuple(val) );
}
/// \brief `flat_tuple_element` has a `typedef type-of-the-field-with-index-I-in-\flattening{flattened}-T type;`
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::flat_tuple_element<0, my_structure>::type > v;
/// \endcode
template <std::size_t I, class T>
using flat_tuple_element = std::remove_reference<
typename boost::pfr::detail::sequence_tuple::tuple_element<I, decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>())) >::type
>;
/// \brief Type of a field with index `I` in \flattening{flattened} `T`
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::flat_tuple_element_t<0, my_structure> > v;
/// \endcode
template <std::size_t I, class T>
using flat_tuple_element_t = typename flat_tuple_element<I, T>::type;
/// \brief Creates an `std::tuple` from a \flattening{flattened} T.
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s {10, 11};
/// std::tuple<int, short> t = flat_make_tuple(s);
/// assert(flat_get<0>(t) == 10);
/// \endcode
template <class T>
auto flat_structure_to_tuple(const T& val) noexcept {
return detail::make_stdtuple_from_tietuple(
detail::tie_as_flat_tuple(val),
detail::make_index_sequence< flat_tuple_size_v<T> >()
);
}
/// \brief Creates an `std::tuple` with lvalue references to fields of a \flattening{flattened} T.
///
/// \rcast
///
/// \b Requires: `T` must not have const fields.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// flat_structure_tie(s) = std::tuple<int, short>{10, 11};
/// assert(s.s == 11);
/// \endcode
template <class T>
auto flat_structure_tie(T& val /* @cond */, std::enable_if_t< std::is_trivially_assignable<T, T>::value>* = 0 /* @endcond */) noexcept {
return detail::make_stdtiedtuple_from_tietuple(
detail::tie_as_flat_tuple(val),
detail::make_index_sequence< flat_tuple_size_v<T> >()
);
}
/// Calls `func` for each field of a \flattening{flattened} POD `value`.
///
/// \rcast
///
/// \param func must have one of the following signatures:
/// * any_return_type func(U&& field) // field of value is perfect forwarded to function
/// * any_return_type func(U&& field, std::size_t i)
/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \param value After \flattening{flattening} to each field of this variable will be the `func` applied.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// int sum = 0;
/// for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
/// assert(sum == 42);
/// \endcode
template <class T, class F>
void flat_for_each_field(T&& value, F&& func) {
auto tup = detail::tie_as_flat_tuple(value);
::boost::pfr::detail::for_each_field_impl(
tup,
std::forward<F>(func),
detail::make_index_sequence< flat_tuple_size_v<T> >{},
std::is_rvalue_reference<T&&>{}
);
}
/// \brief Create a tuple of lvalue references capable of de-structuring
/// assignment from \flattening{flattened} fields of an aggregate T.
///
/// \b Example:
/// \code
/// auto f() {
/// struct { struct { int x, y } p; short s; } res { { 4, 5 }, 6 };
/// return res;
/// }
/// auto [x, y, s] = flat_structure_tie(f());
/// flat_tie_from_structure(x, y, s) = f();
/// \endcode
template <typename... Elements>
constexpr detail::flat_tie_from_structure_tuple<Elements...> flat_tie_from_structure(Elements&... args) noexcept {
return detail::flat_tie_from_structure_tuple<Elements...>(args...);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_CORE_HPP

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP
#define BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/io.hpp>
/// \def BOOST_PFR_FLAT_FUNCTIONS_FOR(T)
/// Defines comparison operators and stream operators for T.
/// If POD is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/flat/functions_for.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// BOOST_PFR_FLAT_FUNCTIONS_FOR(comparable_struct)
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \rcast
///
/// \podops for other ways to define operators and more details.
///
/// \b Defines \b following \b for \b T:
/// \code
/// bool operator==(const T& lhs, const T& rhs) noexcept;
/// bool operator!=(const T& lhs, const T& rhs) noexcept;
/// bool operator< (const T& lhs, const T& rhs) noexcept;
/// bool operator> (const T& lhs, const T& rhs) noexcept;
/// bool operator<=(const T& lhs, const T& rhs) noexcept;
/// bool operator>=(const T& lhs, const T& rhs) noexcept;
///
/// template <class Char, class Traits>
/// std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
///
/// template <class Char, class Traits>
/// std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
///
/// // helper function for Boost unordered containers and boost::hash<>.
/// std::size_t hash_value(const T& value) noexcept;
/// \endcode
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::flat_write(out, value); \
return out; \
} \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::flat_read(in, value); \
return in; \
} \
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) noexcept { \
return ::boost::pfr::flat_hash<T>{}(v); \
} \
/**/
#endif // BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP

View File

@@ -0,0 +1,233 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_FUNCTORS_HPP
#define BOOST_PFR_FLAT_FUNCTORS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/functional.hpp>
#include <boost/pfr/flat/core.hpp>
/// \file boost/pfr/functors.hpp
/// Contains functors that can work with PODs and are close to the Standard Library ones.
/// Each functor \flattening{flattens} the POD type and iterates over its fields.
///
/// \rcast
namespace boost { namespace pfr {
///////////////////// Comparisons
/// \brief std::equal_to like flattening comparator
template <class T = void> struct flat_equal_to {
/// \return \b true if each field of \b x equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_equal_to<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::equal_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
};
/// @endcond
/// \brief std::not_equal like flattening comparator
template <class T = void> struct flat_not_equal {
/// \return \b true if at least one field \b x not equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_not_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater like flattening comparator
template <class T = void> struct flat_greater {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::greater_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_greater<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::greater_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less like flattening comparator
template <class T = void> struct flat_less {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::less_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_less<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::less_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater_equal like flattening comparator
template <class T = void> struct flat_greater_equal {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::greater_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_greater_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::greater_equal_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less_equal like flattening comparator
template <class T = void> struct flat_less_equal {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::less_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_less_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::less_equal_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::hash like flattening functor
template <class T> struct flat_hash {
/// \return hash value of \b x.
///
/// \rcast
std::size_t operator()(const T& x) const noexcept {
return detail::hash_impl<0, flat_tuple_size_v<T> >::compute(detail::tie_as_flat_tuple(x));
}
};
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_FUNCTORS_HPP

View File

@@ -0,0 +1,125 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_GLOBAL_OPS_HPP
#define BOOST_PFR_FLAT_GLOBAL_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/flat/io.hpp>
/// \file boost/pfr/flat/global_ops.hpp
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.
/// If POD is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/flat/global_ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \rcast
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b defines:
/// @cond
namespace boost { namespace pfr { namespace detail {
template <class T, class U>
using enable_flat_comparisons = std::enable_if_t<
std::is_same<T, U>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
bool
>;
}}} // namespace boost::pfr::detail
/// @endcond
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost unordered containers and boost::hash<>.
template <class T> std::size_t hash_value(const T& value) noexcept;
#else
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator==(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator!=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator<(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_less<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator>(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_greater<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator<=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator>=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_ostream<Char, Traits>&
> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
::boost::pfr::flat_write(out, value);
return out;
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_istream<Char, Traits>&
> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
::boost::pfr::flat_read(in, value);
return in;
}
template <class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::size_t
> hash_value(const T& value) noexcept {
return ::boost::pfr::flat_hash<T>{}(value);
}
#endif
#endif // BOOST_PFR_FLAT_GLOBAL_OPS_HPP

View File

@@ -0,0 +1,75 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_IO_HPP
#define BOOST_PFR_FLAT_IO_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
namespace boost { namespace pfr {
/// \brief Writes \flattening{flattened} POD `value` to `out`
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// flat_write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void flat_write(std::basic_ostream<Char, Traits>& out, const T& value) {
out << '{';
detail::print_impl<0, flat_tuple_size_v<T> >::print(out, detail::tie_as_flat_tuple(value));
out << '}';
}
/// Reads \flattening{flattened} POD `value` from stream `in`
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
template <class Char, class Traits, class T>
void flat_read(std::basic_istream<Char, Traits>& in, T& value) {
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
auto tuple = detail::tie_as_flat_tuple(value);
detail::read_impl<0, flat_tuple_size_v<T> >::read(in, tuple);
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_IO_HPP

View File

@@ -0,0 +1,151 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_OPS_HPP
#define BOOST_PFR_FLAT_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/io.hpp>
/// \file boost/pfr/flat/ops.hpp
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.
/// If POD is comparable or streamable using it's own operator or it's conversion operator, then the original operator is used.
///
/// Just write \b using \b namespace \b flat_ops; and operators will be available in scope.
///
/// \b Example:
/// \code
/// #include <boost/pfr/flat/ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// using namespace flat_ops;
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \rcast
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b contains:
namespace boost { namespace pfr {
namespace detail {
///////////////////// Helper typedef that it used by all the enable_flat_not_*_comp_t
template <template <class, class> class Detector, class T>
using enable_flat_not_comp_base_t = typename std::enable_if<
not_appliable<Detector, T const&, T const&>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
bool
>::type;
///////////////////// std::enable_if_t like functions that enable only if types do not support operation and are PODs
template <class T> using enable_flat_not_eq_comp_t = enable_flat_not_comp_base_t<comp_eq_detector, T>;
template <class T> using enable_flat_not_ne_comp_t = enable_flat_not_comp_base_t<comp_ne_detector, T>;
template <class T> using enable_flat_not_lt_comp_t = enable_flat_not_comp_base_t<comp_lt_detector, T>;
template <class T> using enable_flat_not_le_comp_t = enable_flat_not_comp_base_t<comp_le_detector, T>;
template <class T> using enable_flat_not_gt_comp_t = enable_flat_not_comp_base_t<comp_gt_detector, T>;
template <class T> using enable_flat_not_ge_comp_t = enable_flat_not_comp_base_t<comp_ge_detector, T>;
template <class Stream, class Type>
using enable_flat_not_ostreamable_t = typename std::enable_if<
not_appliable<ostreamable_detector, Stream&, Type const&>::value && std::is_trivial<Type>::value
&& std::is_standard_layout<Type>::value,
Stream&
>::type;
template <class Stream, class Type>
using enable_flat_not_istreamable_t = typename std::enable_if<
not_appliable<istreamable_detector, Stream&, Type&>::value && std::is_trivial<Type>::value
&& std::is_standard_layout<Type>::value,
Stream&
>::type;
} // namespace detail
namespace flat_ops {
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost
template <class T> std::size_t hash_value(const T& value) noexcept;
#else
template <class T>
static detail::enable_flat_not_eq_comp_t<T> operator==(const T& lhs, const T& rhs) noexcept {
return flat_equal_to<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_ne_comp_t<T> operator!=(const T& lhs, const T& rhs) noexcept {
return flat_not_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_lt_comp_t<T> operator<(const T& lhs, const T& rhs) noexcept {
return flat_less<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_gt_comp_t<T> operator>(const T& lhs, const T& rhs) noexcept {
return flat_greater<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_le_comp_t<T> operator<=(const T& lhs, const T& rhs) noexcept {
return flat_less_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_ge_comp_t<T> operator>=(const T& lhs, const T& rhs) noexcept {
return flat_greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static detail::enable_flat_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
boost::pfr::flat_write(out, value);
return out;
}
template <class Char, class Traits, class T>
static detail::enable_flat_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
boost::pfr::flat_read(in, value);
return in;
}
template <class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::size_t
> hash_value(const T& value) noexcept {
return flat_hash<T>{}(value);
}
#endif
} // namespace flat_ops
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_OPS_HPP

View File

@@ -0,0 +1,40 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_TUPLE_SIZE_HPP
#define BOOST_PFR_FLAT_TUPLE_SIZE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/core14.hpp>
namespace boost { namespace pfr {
/// Has a static const member variable `value` that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size<my_structure>::value > a;
/// \endcode
template <class T>
using flat_tuple_size = boost::pfr::detail::size_t_<decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>()))::size_v>;
/// `flat_tuple_size_v` is a template variable that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size_v<my_structure> > a;
/// \endcode
template <class T>
constexpr std::size_t flat_tuple_size_v = flat_tuple_size<T>::value;
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_TUPLE_SIZE_HPP

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_HPP
#define BOOST_PFR_PRECISE_HPP
/// \file boost/pfr/precise.hpp
/// Includes all the Boost.PFR headers that do not define `flat_*` functions, except \xmlonly<link linkend='header.boost.pfr.precise.global_ops_hpp'>boost/pfr/precise/global_ops.hpp</link>\endxmlonly
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/ops.hpp>
#include <boost/pfr/precise/io.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/precise/functions_for.hpp>
#endif // BOOST_PFR_PRECISE_HPP

View File

@@ -0,0 +1,177 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_CORE_HPP
#define BOOST_PFR_PRECISE_CORE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/detail/for_each_field_impl.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
#include <boost/pfr/detail/tie_from_structure_tuple.hpp>
namespace boost { namespace pfr {
/// \brief Returns reference or const reference to a field with index `I` in aggregate T.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
///
/// \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;
/// \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) noexcept {
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
}
/// \brief `tuple_element` has a `typedef type-of-a-field-with-index-I-in-aggregate-T type;`
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::tuple_element<0, my_structure>::type > v;
/// \endcode
template <std::size_t I, class T>
using tuple_element = detail::sequence_tuple::tuple_element<I, decltype( ::boost::pfr::detail::tie_as_tuple(std::declval<T&>()) ) >;
/// \brief Type of a field with index `I` in aggregate `T`.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::tuple_element_t<0, my_structure> > v;
/// \endcode
template <std::size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;
/// \brief Creates an `std::tuple` from an aggregate T.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s {10, 11};
/// std::tuple<int, short> t = make_tuple(s);
/// assert(get<0>(t) == 10);
/// \endcode
template <class T>
constexpr auto structure_to_tuple(const T& val) noexcept {
return detail::make_stdtuple_from_tietuple(
detail::tie_as_tuple(val),
detail::make_index_sequence< tuple_size_v<T> >()
);
}
/// \brief Creates an `std::tuple` with lvalue references to fields of an aggregate T.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// structure_tie(s) = std::tuple<int, short>{10, 11};
/// assert(s.s == 11);
/// \endcode
template <class T>
constexpr auto structure_tie(T& val) noexcept {
return detail::make_stdtiedtuple_from_tietuple(
detail::tie_as_tuple(val),
detail::make_index_sequence< tuple_size_v<T> >()
);
}
/// Calls `func` for each field of a `value`.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \param func must have one of the following signatures:
/// * any_return_type func(U&& field) // field of value is perfect forwarded to function
/// * any_return_type func(U&& field, std::size_t i)
/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \param value To each field of this variable will be the `func` applied.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// int sum = 0;
/// for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
/// assert(sum == 42);
/// \endcode
template <class T, class F>
void for_each_field(T&& value, F&& func) {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
::boost::pfr::detail::for_each_field_dispatcher(
value,
[f = std::forward<F>(func)](auto&& t) mutable {
// MSVC related workaround. It's lambdas do not capture constexprs.
constexpr std::size_t fields_count_val_in_lambda
= boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
::boost::pfr::detail::for_each_field_impl(
t,
std::forward<F>(f),
detail::make_index_sequence<fields_count_val_in_lambda>{},
std::is_rvalue_reference<T&&>{}
);
},
detail::make_index_sequence<fields_count_val>{}
);
}
/// \brief Create a tuple of lvalue references capable of de-structuring
/// assignment from fields of an aggregate T.
///
/// \b Example:
/// \code
/// auto f() {
/// struct { struct { int x, y } p; short s; } res { { 4, 5 }, 6 };
/// return res;
/// }
/// auto [p, s] = f();
/// tie_from_structure(p, s) = f();
/// \endcode
template <typename... Elements>
constexpr detail::tie_from_structure_tuple<Elements...> tie_from_structure(Elements&... args) noexcept {
return detail::tie_from_structure_tuple<Elements...>(args...);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_CORE_HPP

View File

@@ -0,0 +1,79 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/io.hpp>
/// \def BOOST_PFR_PRECISE_FUNCTIONS_FOR(T)
/// Defines comparison operators and stream operators for T.
/// If type T is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/functions_for.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// BOOST_PFR_PRECISE_FUNCTIONS_FOR(comparable_struct)
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b Defines \b following \b for \b T:
/// \code
/// bool operator==(const T& lhs, const T& rhs);
/// bool operator!=(const T& lhs, const T& rhs);
/// bool operator< (const T& lhs, const T& rhs);
/// bool operator> (const T& lhs, const T& rhs);
/// bool operator<=(const T& lhs, const T& rhs);
/// bool operator>=(const T& lhs, const T& rhs);
///
/// template <class Char, class Traits>
/// std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
///
/// template <class Char, class Traits>
/// std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
///
/// // helper function for Boost unordered containers and boost::hash<>.
/// std::size_t hash_value(const T& value);
/// \endcode
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::write(out, value); \
return out; \
} \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::read(in, value); \
return in; \
} \
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) { \
return ::boost::pfr::hash<T>{}(v); \
} \
/**/
#endif // BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP

View File

@@ -0,0 +1,259 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_FUNCTORS_HPP
#define BOOST_PFR_PRECISE_FUNCTORS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/functional.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
/// \file boost/pfr/functors.hpp
/// Contains functors that are close to the Standard Library ones.
/// Each functor iterates over fields of the type.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
namespace boost { namespace pfr {
namespace detail {
template <template <std::size_t, std::size_t> class Visitor, class T, class U>
bool binary_visit(const T& x, const U& y) {
constexpr std::size_t fields_count_lhs = detail::fields_count<std::remove_reference_t<T>>();
constexpr std::size_t fields_count_rhs = detail::fields_count<std::remove_reference_t<U>>();
constexpr std::size_t fields_count_min = detail::min_size(fields_count_lhs, fields_count_rhs);
typedef Visitor<0, fields_count_min> visitor_t;
#if BOOST_PFR_USE_CPP17
return visitor_t::cmp(detail::tie_as_tuple(x), detail::tie_as_tuple(y));
#else
bool result = true;
::boost::pfr::detail::for_each_field_dispatcher(
x,
[&result, &y](const auto& lhs) {
::boost::pfr::detail::for_each_field_dispatcher(
y,
[&result, &lhs](const auto& rhs) {
result = visitor_t::cmp(lhs, rhs);
},
detail::make_index_sequence<fields_count_rhs>{}
);
},
detail::make_index_sequence<fields_count_lhs>{}
);
return result;
#endif
}
} // namespace detail
///////////////////// Comparisons
/// \brief std::equal_to like comparator
template <class T = void> struct equal_to {
/// \return \b true if each field of \b x equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::equal_impl>(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const;
#endif
};
/// @cond
template <> struct equal_to<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::equal_impl>(x, y);
}
};
/// @endcond
/// \brief std::not_equal like comparator
template <class T = void> struct not_equal {
/// \return \b true if at least one field \b x not equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::not_equal_impl>(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const;
#endif
};
/// @cond
template <> struct not_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::not_equal_impl>(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater like comparator
template <class T = void> struct greater {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::greater_impl>(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const;
#endif
};
/// @cond
template <> struct greater<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::greater_impl>(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less like comparator
template <class T = void> struct less {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::less_impl>(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const;
#endif
};
/// @cond
template <> struct less<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::less_impl>(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater_equal like comparator
template <class T = void> struct greater_equal {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::greater_equal_impl>(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const;
#endif
};
/// @cond
template <> struct greater_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::greater_equal_impl>(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less_equal like comparator
template <class T = void> struct less_equal {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::less_equal_impl>(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const;
#endif
};
/// @cond
template <> struct less_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::less_equal_impl>(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::hash like functor
template <class T> struct hash {
/// \return hash value of \b x.
std::size_t operator()(const T& x) const {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
#if BOOST_PFR_USE_CPP17
return detail::hash_impl<0, fields_count_val>::compute(detail::tie_as_tuple(x));
#else
std::size_t result = 0;
::boost::pfr::detail::for_each_field_dispatcher(
x,
[&result](const auto& lhs) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
result = detail::hash_impl<0, fields_count_val_lambda>::compute(lhs);
},
detail::make_index_sequence<fields_count_val>{}
);
return result;
#endif
}
};
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_FUNCTORS_HPP

View File

@@ -0,0 +1,120 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_GLOBAL_OPS_HPP
#define BOOST_PFR_PRECISE_GLOBAL_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/io.hpp>
/// \file boost/pfr/precise/global_ops.hpp
/// Contains comparison operators and stream operators for any types that do not have their own operators.
/// If type is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/global_ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b defines:
/// @cond
namespace boost { namespace pfr { namespace detail {
template <class T, class U>
using enable_comparisons = std::enable_if_t<
std::is_same<T, U>::value,
bool
>;
}}} // namespace boost::pfr::detail
/// @endcond
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs);
template <class T> bool operator!=(const T& lhs, const T& rhs);
template <class T> bool operator< (const T& lhs, const T& rhs);
template <class T> bool operator> (const T& lhs, const T& rhs);
template <class T> bool operator<=(const T& lhs, const T& rhs);
template <class T> bool operator>=(const T& lhs, const T& rhs);
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost unordered containers and boost::hash<>.
template <class T> std::size_t hash_value(const T& value);
#else
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator==(const T& lhs, const U& rhs) {
return ::boost::pfr::equal_to<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator!=(const T& lhs, const U& rhs) {
return ::boost::pfr::not_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<(const T& lhs, const U& rhs) {
return ::boost::pfr::less<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>(const T& lhs, const U& rhs) {
return ::boost::pfr::greater<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<=(const T& lhs, const U& rhs) {
return ::boost::pfr::less_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>=(const T& lhs, const U& rhs) {
return ::boost::pfr::greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_ostream<Char, Traits>&
> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
::boost::pfr::write(out, value);
return out;
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_istream<Char, Traits>&
> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
::boost::pfr::read(in, value);
return in;
}
template <class T>
static std::size_t hash_value(const T& value) {
return ::boost::pfr::hash<T>{}(value);
}
#endif
#endif // BOOST_PFR_PRECISE_GLOBAL_OPS_HPP

View File

@@ -0,0 +1,110 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_IO_HPP
#define BOOST_PFR_PRECISE_IO_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
namespace boost { namespace pfr {
/// \brief Writes aggregate `value` to `out`
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
out << '{';
#if BOOST_PFR_USE_CPP17
detail::print_impl<0, fields_count_val>::print(out, detail::tie_as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&out](const auto& val) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
detail::print_impl<0, fields_count_val_lambda>::print(out, val);
},
detail::make_index_sequence<fields_count_val>{}
);
#endif
out << '}';
}
/// Reads aggregate `value` from stream `in`
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
template <class Char, class Traits, class T>
void read(std::basic_istream<Char, Traits>& in, T& value) {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
#if BOOST_PFR_USE_CPP17
detail::read_impl<0, fields_count_val>::read(in, detail::tie_as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&in](const auto& val) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
detail::read_impl<0, fields_count_val_lambda>::read(in, val);
},
detail::make_index_sequence<fields_count_val>{}
);
#endif
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_IO_HPP

View File

@@ -0,0 +1,147 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_OPS_HPP
#define BOOST_PFR_PRECISE_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/io.hpp>
/// \file boost/pfr/precise/ops.hpp
/// Contains comparison operators and stream operators for types that do not have their own operators.
/// If type is comparable or streamable using it's own operator or it's conversion operator, then the original operator is used.
///
/// Just write \b using \b namespace \b ops; and operators will be available in scope.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// using namespace ops;
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b contains:
namespace boost { namespace pfr {
namespace detail {
///////////////////// Helper typedef that it used by all the enable_not_*_comp_t
template <template <class, class> class Detector, class T>
using enable_not_comp_base_t = typename std::enable_if<
not_appliable<Detector, T const&, T const&>::value,
bool
>::type;
///////////////////// std::enable_if_t like functions that enable only if types do not support operation and are PODs
template <class T> using enable_not_eq_comp_t = enable_not_comp_base_t<comp_eq_detector, T>;
template <class T> using enable_not_ne_comp_t = enable_not_comp_base_t<comp_ne_detector, T>;
template <class T> using enable_not_lt_comp_t = enable_not_comp_base_t<comp_lt_detector, T>;
template <class T> using enable_not_le_comp_t = enable_not_comp_base_t<comp_le_detector, T>;
template <class T> using enable_not_gt_comp_t = enable_not_comp_base_t<comp_gt_detector, T>;
template <class T> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T>;
template <class Stream, class Type>
using enable_not_ostreamable_t = typename std::enable_if<
not_appliable<ostreamable_detector, Stream&, Type const&>::value,
Stream&
>::type;
template <class Stream, class Type>
using enable_not_istreamable_t = typename std::enable_if<
not_appliable<istreamable_detector, Stream&, Type&>::value,
Stream&
>::type;
} // namespace detail
namespace ops {
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost
template <class T> std::size_t hash_value(const T& value) noexcept;
#else
template <class T>
static detail::enable_not_eq_comp_t<T> operator==(const T& lhs, const T& rhs) noexcept {
return equal_to<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_ne_comp_t<T> operator!=(const T& lhs, const T& rhs) noexcept {
return not_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_lt_comp_t<T> operator<(const T& lhs, const T& rhs) noexcept {
return less<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_gt_comp_t<T> operator>(const T& lhs, const T& rhs) noexcept {
return greater<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_le_comp_t<T> operator<=(const T& lhs, const T& rhs) noexcept {
return less_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_ge_comp_t<T> operator>=(const T& lhs, const T& rhs) noexcept {
return greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static detail::enable_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
boost::pfr::write(out, value);
return out;
}
template <class Char, class Traits, class T>
static detail::enable_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
boost::pfr::read(in, value);
return in;
}
template <class T>
static std::enable_if_t<std::is_trivial<T>::value, std::size_t> hash_value(const T& value) noexcept {
return hash<T>{}(value);
}
#endif
} // namespace ops
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_OPS_HPP

View File

@@ -0,0 +1,50 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_TUPLE_SIZE_HPP
#define BOOST_PFR_PRECISE_TUPLE_SIZE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/fields_count.hpp>
namespace boost { namespace pfr {
/// Has a static const member variable `value` that contains fields count in a T.
/// Works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::tuple_size<my_structure>::value > a;
/// \endcode
template <class T>
using tuple_size = detail::size_t_< boost::pfr::detail::fields_count<T>() >;
/// `tuple_size_v` is a template variable that contains fields count in a T and
/// works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::tuple_size_v<my_structure> > a;
/// \endcode
template <class T>
constexpr std::size_t tuple_size_v = tuple_size<T>::value;
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_TUPLE_SIZE_HPP

File diff suppressed because it is too large Load Diff

471
main.cpp
View File

@@ -1,471 +0,0 @@
// Copyright (c) 2016 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 "magic_get.hpp"
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <vector>
#include <cassert>
#include <algorithm>
#include <unordered_set>
template <std::size_t I, class T>
void print(T& f) {
std::cout << flat_get<I>(f) << "\t\t"
<< typeid(flat_tuple_element_t<I, T>).name()
<< std::endl;
}
struct make_my_life_harder { int a0; short a1; };
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
struct foo {
unsigned char v0;
unsigned int v1;
unsigned short v2;
unsigned long long v3;
unsigned char v4and5[2];
int v6;
std::size_t v7;
int* v8;
const void* v9;
int const**const volatile**volatile** v10;
const double v11;
make_my_life_harder v12and13;
make_my_life_even_more_harder v14and15andv16and17;
};
void test_print() {
foo f {
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
, {18, 19}
, {20, 21, {22, 23}}
};
print<0>(f); print<1>(f); print<2>(f);
print<3>(f); print<4>(f); print<5>(f);
print<6>(f); print<7>(f); print<8>(f);
print<9>(f); print<10>(f); print<11>(f);
print<12>(f); print<13>(f); print<14>(f);
print<15>(f); print<16>(f); print<17>(f);
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
int a[] = {0, 1, 2, 3};
std::cout << '\n' << flat_get<1>(a) << std::endl;
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
std::cout << flat_get<4>(b) << std::endl;
int i = 777;
std::cout << flat_get<0>(i) << std::endl;
}
void test_runtime(const foo& f) {
assert( flat_get<0>(f) == f.v0);
assert( flat_get<1>(f) == f.v1);
assert( flat_get<2>(f) == f.v2);
assert( flat_get<3>(f) == f.v3);
assert( flat_get<4>(f) == f.v4and5[0]);
assert( flat_get<5>(f) == f.v4and5[1]);
assert( flat_get<6>(f) == f.v6);
assert( flat_get<7>(f) == f.v7);
assert( flat_get<8>(f) == f.v8);
assert( flat_get<9>(f) == f.v9);
assert( flat_get<10>(f) == f.v10);
assert( flat_get<11>(f) < f.v11 + 0.001); assert( flat_get<11>(f) > f.v11 - 0.001);
assert( flat_get<12>(f) == f.v12and13.a0);
assert( flat_get<13>(f) == f.v12and13.a1);
assert( flat_get<14>(f) == f.v14and15andv16and17.b0);
assert( flat_get<15>(f) == f.v14and15andv16and17.b1);
assert( flat_get<16>(f) == f.v14and15andv16and17.cr.a0);
assert( flat_get<17>(f) == f.v14and15andv16and17.cr.a1);
}
template <class T>
void test_compiletime() {
constexpr T f{};
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
}
template <class T>
constexpr void test_compiletime_array() {
{
constexpr T f[20] = {0};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
{
constexpr T f[2][10] = {0};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
{
constexpr T f[2][5][2] = {0};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
}
//#define TEST_REF
#ifdef TEST_REF
struct with_ref {
int i;
int& ref;
};
void test() {
int ref_me = 1234567890;
with_ref f { 987654321, ref_me };
print<0>(f); print<1>(f);
}
#endif
void test_with_enums() {
enum class my_enum: unsigned {
VALUE1 = 17, VALUE2, VALUE3
};
struct my_struct { my_enum e; int i; short s; };
my_struct s {my_enum::VALUE1, 10, 11};
std::tuple<unsigned, int, short> t = flat_make_tuple(s);
assert(std::get<0>(t) == 17);
assert(std::get<1>(t) == 10);
assert(std::get<2>(t) == 11);
flat_get<1>(s) = 101;
assert(flat_get<1>(s) == 101);
flat_get<2>(s) = 111;
assert(flat_get<2>(s) == 111);
assert(flat_tie(s) == flat_tie(s));
assert(flat_tie(s) == flat_make_tuple(s));
assert(flat_tie(s) != t);
flat_tie(s) = t;
assert(flat_get<0>(s) == 17);
assert(flat_get<1>(s) == 10);
assert(flat_get<2>(s) == 11);
static_assert(std::is_same<
int, flat_tuple_element_t<1, my_struct>
>::value, "");
static_assert(std::is_same<
short, flat_tuple_element_t<2, my_struct>
>::value, "");
static_assert(std::is_same<
const int, flat_tuple_element_t<1, const my_struct>
>::value, "");
static_assert(std::is_same<
volatile short, flat_tuple_element_t<2, volatile my_struct>
>::value, "");
static_assert(std::is_same<
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
>::value, "");
static_assert(
3 == flat_tuple_size_v<const volatile my_struct>,
""
);
}
void test_comparable_struct() {
struct comparable_struct {
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
};
using namespace pod_ops;
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
comparable_struct s2 = s1;
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
assert(s1 == s2);
assert(s1 <= s2);
assert(s1 >= s2);
assert(!(s1 != s2));
assert(!(s1 == s3));
assert(s1 != s3);
assert(s1 < s3);
assert(s3 > s2);
assert(s1 <= s3);
assert(s3 >= s2);
std::cout << s1 << std::endl;
comparable_struct s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
assert(s1 == s4);
int i = 1, j = 2;
assert(i != j);
}
void test_empty_struct() {
struct empty {};
using namespace pod_ops;
std::cout << empty{} << std::endl;
assert(empty{} == empty{});
}
void test_pods_with_int_operators() {
using namespace pod_ops;
std::stringstream ss;
ss << std::is_pod<int>{};
int i = 0;
ss >> i;
assert(i == 1);
std::cout << i << std::endl;
}
void test_struct_with_single_field() {
struct f1 { int i; };
using namespace pod_ops;
std::stringstream ss;
ss << f1{ 777 };
f1 var{};
ss >> var;
assert(var.i == 777);
assert(var == f1{ 777 });
assert(var != f1{ 778 });
assert(var <= f1{ 777 });
assert(var <= f1{ 778 });
assert(var < f1{ 778 });
assert(var >= f1{ 777 });
assert(var >= f1{ 776 });
assert(var > f1{ 776 });
}
template <class Comparator>
void test_with_contatiners() {
struct testing { bool b1, b2; int i; };
struct testing2 { bool b1, b2; int i; };
std::set<testing, Comparator > t{
{true, true, 100},
{false, true, 100},
{true, false, 100},
{true, true, 101}
};
assert(t.find({true, true, 100}) != t.end());
assert(t.count({true, true, 100}) == 1);
assert(t.find(testing2{true, true, 100}) != t.end());
std::set<testing2, Comparator > t2{
{true, true, 101},
{true, true, 100},
{true, false, 100},
{false, true, 100}
};
assert(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
assert(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
std::vector<testing> res;
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
std::back_inserter(res), Comparator{});
assert(res.size() == 4);
}
void test_with_user_defined_constructor() {
struct pr {
int i;
short s;
pr() = default;
pr(const pr&) = default;
pr(pr&&) = default;
pr(int ii, short is) noexcept
: i(ii), s(is)
{}
};
pr p{1, 2};
//assert(flat_get<1>(p) == 2); // Compilation error
}
template <class T1, std::size_t CountInT, std::size_t CountHelpers>
void test_counts_on_multiple_chars_impl_1() {
struct t1_c { T1 v1; char c[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_c> == CountInT + CountHelpers, "");
struct t1_s { T1 v1; short s[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_s> == CountInT + CountHelpers, "");
struct t1_i { T1 v1; int i[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_i> == CountInT + CountHelpers, "");
struct t1_p { T1 v1; void* p[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_p> == CountInT + CountHelpers, "");
struct t1_ll { T1 v1; long long ll[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_ll> == CountInT + CountHelpers, "");
struct rt1_c { char c[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_c> == CountInT + CountHelpers, "");
struct rt1_s { short s[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_s> == CountInT + CountHelpers, "");
struct rt1_i { int i[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_i> == CountInT + CountHelpers, "");
struct rt1_p { void* p[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_p> == CountInT + CountHelpers, "");
struct rt1_ll { long long ll[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_ll> == CountInT + CountHelpers, "");
}
template <class T1, std::size_t CountInT>
void test_counts_on_multiple_chars_impl() {
struct t1_0 { T1 v1; };
static_assert(flat_tuple_size_v<t1_0> == CountInT, "");
static_assert(flat_tuple_size_v<T1> == CountInT, "");
static_assert(flat_tuple_size_v<std::conditional_t<std::is_fundamental<T1>::value, T1*, void*> > == 1, "");
static_assert(flat_tuple_size_v<T1[5]> == CountInT*5, "");
test_counts_on_multiple_chars_impl_1<T1, CountInT, 1>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 2>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 3>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 4>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 5>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 6>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 7>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 8>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 9>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 10>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 11>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 12>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 13>();/*
test_counts_on_multiple_chars_impl_1<T1, CountInT, 14>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 15>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 16>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 17>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 18>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 19>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 20>();*/
}
template <class T>
void test_counts_on_multiple_chars() {
test_counts_on_multiple_chars_impl<T, 1>();
struct t2 { T v1; T v2; };
test_counts_on_multiple_chars_impl<t2, 2>();
test_counts_on_multiple_chars_impl<T[2], 2>();
test_counts_on_multiple_chars_impl<T[3], 3>();
test_counts_on_multiple_chars_impl<T[4], 4>();
struct t8 { T v1; T v2; T v3; T v4; T v5; T v6; T v7; T v8; };
test_counts_on_multiple_chars_impl<t8, 8>();
}
void test_hash() {
struct almost_pair { int i; short s; };
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
s.insert({0, 1});
s.insert({1, 0});
s.insert({1, 1});
assert(s.size() == 3);
flat_hash<almost_pair> hs;
assert(hs({0, 1}) != hs({1, 0}));
assert(hs({0, 1}) == hs({0, 1}));
assert(hs({1, 1}) == hs({1, 1}));
assert(hs({0, 0}) != hs({1, 1}));
struct single_field { int i; };
assert(flat_hash<single_field>()({1}) != std::hash<int>()(1));
assert(flat_hash<single_field>()({199}) != std::hash<int>()(199));
}
int main() {
test_compiletime<foo>();
test_compiletime_array<int>();
test_compiletime_array<void*>();
test_compiletime_array<const void*>();
test_compiletime_array<char>();
test_compiletime_array<char const volatile*>();
{
foo f {
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
, {18, 19}
, {20, 21, {22, 23}}
};
test_runtime(f);
}
{
foo f {
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
, {-18, -19}
, {656565, 65535, {-22, -23}}
};
test_runtime(f);
}
test_with_enums();
test_comparable_struct();
test_empty_struct();
test_pods_with_int_operators();
test_struct_with_single_field();
test_with_contatiners<flat_less<>>();
test_with_contatiners<flat_greater<>>();
test_print();
test_with_user_defined_constructor();
test_counts_on_multiple_chars<char>();
test_counts_on_multiple_chars<short>();
test_counts_on_multiple_chars<int>();
test_counts_on_multiple_chars<void*>();
test_counts_on_multiple_chars<long long>();
test_hash();
}

111
misc/generate_cpp17.py Normal file
View File

@@ -0,0 +1,111 @@
#!/usr/bin/python
# Copyright (c) 2016-2020 Antony Polukhin
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
############################################################################################################################
import sys
import string
# Skipping some letters that may produce keywords or are hard to read, or shadow template parameters
ascii_letters = string.ascii_letters.replace("o", "").replace("O", "").replace("i", "").replace("I", "").replace("T", "")
PROLOGUE = """// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////// THIS HEADER IS AUTO GENERATED BY misc/generate_cpp17.py ////////////////
//////////////// MODIFY AND RUN THE misc/generate_cpp17.py INSTEAD OF DIRECTLY MODIFYING THE GENERATED FILE ////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
#define BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#if !BOOST_PFR_USE_CPP17
# error C++17 is required for this header.
#endif
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/size_t_.hpp>
namespace boost { namespace pfr { namespace detail {
template <class... Args>
constexpr auto make_tuple_of_references(Args&&... args) noexcept {
return sequence_tuple::tuple<Args&...>{ args... };
}
template <class T>
constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
return sequence_tuple::tuple<>{};
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = 0) noexcept {
auto& [a] = val;
return ::boost::pfr::detail::make_tuple_of_references(a);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class< std::remove_cv_t<T> >::value>* = 0) noexcept {
return ::boost::pfr::detail::make_tuple_of_references( val );
}
"""
############################################################################################################################
EPILOGUE = """
template <class T, std::size_t I>
constexpr void tie_as_tuple(T& val, size_t_<I>) noexcept {
static_assert(sizeof(T) && false,
"====================> Boost.PFR: Too many fields in a structure T. Regenerate include/boost/pfr/detail/core17_generated.hpp file for appropriate count of fields. For example: `python ./misc/generate_cpp17.py 300 > include/boost/pfr/detail/core17_generated.hpp`");
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
"""
############################################################################################################################
indexes = " a"
print PROLOGUE
funcs_count = 100 if len(sys.argv) == 1 else int(sys.argv[1])
max_args_on_a_line = len(ascii_letters)
for i in xrange(1, funcs_count):
if i % max_args_on_a_line == 0:
indexes += ",\n "
else:
indexes += ","
if i >= max_args_on_a_line:
indexes += ascii_letters[i / max_args_on_a_line - 1]
indexes += ascii_letters[i % max_args_on_a_line]
print "template <class T>"
print "constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {"
if i < max_args_on_a_line:
print " auto& [" + indexes.strip() + "] = val;"
print " return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");"
else:
print " auto& ["
print indexes
print " ] = val;"
print ""
print " return ::boost::pfr::detail::make_tuple_of_references("
print indexes
print " );"
print "}\n"
print EPILOGUE

195
test/Jamfile.v2 Normal file
View File

@@ -0,0 +1,195 @@
# Copyright (C) 2016-2020, Antony Polukhin.
#
# Use, modification and distribution is subject to the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
import testing ;
import ../../config/checks/config : requires ;
project
: source-location .
: requirements
<toolset>msvc:<cxxflags>"/std:c++latest"
<toolset>msvc:<define>BOOST_PFR_USE_CPP17=1
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
[ requires cxx14_constexpr ]
;
local DISABLE_ON_MSVC = <toolset>msvc:<build>no ;
local DISABLE_ON_CLANG8_PLUS = <toolset>clang-8:<build>no <toolset>clang-9:<build>no <toolset>clang-10:<build>no ;
local LOOPHOLE_FLAT_DEF = <define>BOOST_PFR_TEST_FLAT <define>BOOST_PFR_USE_LOOPHOLE=1 $(DISABLE_ON_MSVC) $(DISABLE_ON_CLANG8_PLUS) ;
local CLASSIC_FLAT_DEF = <define>BOOST_PFR_TEST_FLAT <define>BOOST_PFR_USE_LOOPHOLE=0 $(DISABLE_ON_MSVC) ;
local LOOPHOLE_PREC_DEF = <define>BOOST_PFR_TEST_PRECISE <define>BOOST_PFR_USE_LOOPHOLE=1 $(DISABLE_ON_MSVC) $(DISABLE_ON_CLANG8_PLUS) ;
local CLASSIC_PREC_DEF = <define>BOOST_PFR_TEST_PRECISE <define>BOOST_PFR_USE_LOOPHOLE=0 ;
test-suite pfr
:
##### Common tests
[ run common/offset_based_getter.cpp ]
[ run common/ops.cpp : : : $(CLASSIC_FLAT_DEF) : flat_ops ]
[ run common/ops.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_ops ]
[ run common/ops.cpp : : : $(CLASSIC_PREC_DEF) : precise_ops ]
[ run common/ops.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_ops ]
[ run common/global_ops.cpp : : : $(CLASSIC_FLAT_DEF) : flat_global_ops ]
[ run common/global_ops.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_global_ops ]
[ run common/global_ops.cpp : : : $(CLASSIC_PREC_DEF) : precise_global_ops ]
[ run common/global_ops.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_global_ops ]
[ run common/functions_for.cpp : : : $(CLASSIC_FLAT_DEF) : flat_function_for ]
[ run common/functions_for.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_function_for ]
[ run common/functions_for.cpp : : : $(CLASSIC_PREC_DEF) : precise_function_for ]
[ run common/functions_for.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_function_for ]
[ run common/read_write.cpp : : : $(CLASSIC_FLAT_DEF) : flat_read_write ]
[ run common/read_write.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_read_write ]
[ run common/read_write.cpp : : : $(CLASSIC_PREC_DEF) : precise_read_write ]
[ run common/read_write.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_read_write ]
[ run common/std_interactions.cpp : : : $(CLASSIC_FLAT_DEF) : flat_std_interactions ]
[ run common/std_interactions.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_std_interactions ]
[ run common/std_interactions.cpp : : : $(CLASSIC_PREC_DEF) : precise_std_interactions ]
[ run common/std_interactions.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_std_interactions ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(CLASSIC_FLAT_DEF) : flat_movable_and_lvalue_references ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_movable_and_lvalue_references ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(CLASSIC_PREC_DEF) : precise_movable_and_lvalue_references ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_movable_and_lvalue_references ]
[ compile-fail common/private_fields.cpp : $(CLASSIC_FLAT_DEF) : flat_private_fields ]
[ compile-fail common/private_fields.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_private_fields ]
[ compile-fail common/private_fields.cpp : $(CLASSIC_PREC_DEF) : precise_private_fields ]
[ compile-fail common/private_fields.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_private_fields ]
[ compile-fail common/protected_fields.cpp : $(CLASSIC_FLAT_DEF) : flat_protected_fields ]
[ compile-fail common/protected_fields.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_protected_fields ]
[ compile-fail common/protected_fields.cpp : $(CLASSIC_PREC_DEF) : precise_protected_fields ]
[ compile-fail common/protected_fields.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_protected_fields ]
[ compile-fail common/virtual_functions.cpp : $(CLASSIC_FLAT_DEF) : flat_virtual_functions ]
[ compile-fail common/virtual_functions.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_virtual_functions ]
[ compile-fail common/virtual_functions.cpp : $(CLASSIC_PREC_DEF) : precise_virtual_functions ]
[ compile-fail common/virtual_functions.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_virtual_functions ]
[ compile-fail common/ops_on_union.cpp : $(CLASSIC_FLAT_DEF) : flat_on_union ]
[ compile-fail common/ops_on_union.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_on_union ]
[ compile-fail common/ops_on_union.cpp : $(CLASSIC_PREC_DEF) : precise_on_union ]
[ compile-fail common/ops_on_union.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_on_union ]
[ compile-fail common/ops_unions.cpp : $(CLASSIC_FLAT_DEF) : flat_unions ]
[ compile-fail common/ops_unions.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_unions ]
[ compile-fail common/ops_unions.cpp : $(CLASSIC_PREC_DEF) : precise_unions ]
[ compile-fail common/ops_unions.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(CLASSIC_FLAT_DEF) : flat_unrestricted_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_unrestricted_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(CLASSIC_PREC_DEF) : precise_unrestricted_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_unrestricted_unions ]
[ compile-fail common/non_std_layout.cpp : $(CLASSIC_FLAT_DEF) : flat_non_standard_layout ]
[ compile-fail common/non_std_layout.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_standard_layout ]
[ run common/non_std_layout.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_standard_layout ]
[ run common/non_std_layout.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_standard_layout ]
[ compile-fail common/non_default_constructible.cpp : $(CLASSIC_FLAT_DEF) : flat_non_default_constructible ]
[ compile-fail common/non_default_constructible.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_sdefault_constructible ]
[ run common/non_default_constructible.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_default_constructible ]
[ run common/non_default_constructible.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_default_constructible ]
#[ compile-fail common/non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_copyable_but_movable ]
#[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_copyable_but_movable ]
[ run common/non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_copyable_but_movable ]
[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_copyable_but_movable ]
#[ compile-fail common/non_default_constructible_non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_dc_non_cop_but_mov ]
#[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_dc_non_cop_but_mov ]
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_dc_non_cop_but_mov ]
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_dc_non_cop_but_mov ]
[ compile-fail common/fields_count_on_reference.cpp ]
[ run common/fields_count_on_const.cpp ]
##### Flat tuple sizes
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=void* : test_tuple_sizes_on_voidptrs ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON="std::size_t" : test_tuple_sizes_on_size_ts ]
#[ run common/test_tuple_sizes_on.cpp $(DISABLE_ON_MSVC)<define>BOOST_PFR_RUN_TEST_ON=char <define>BOOST_PFR_RUN_HUGE_TESTS : test_tuple_sizes_on_chars_huge ]
##### Flat specific tests
[ run flat/core.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/flat_tuple_size.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/flat_motivating_example.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/flat_for_each_field.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/destructuring_tie.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ compile-fail flat/flat_tuple_size_on_non_aggregate.cpp : $(CLASSIC_FLAT_DEF) ]
[ compile-fail flat/flat_tuple_size_on_bitfields.cpp : $(CLASSIC_FLAT_DEF) ]
##### Precise specific tests
[ run precise/tuple_size.cpp : : : $(CLASSIC_PREC_DEF) : precise_tuple_size ]
[ run precise/bitfields.cpp : : : $(CLASSIC_PREC_DEF) : precise_tuple_size_on_bitfields ]
[ run precise/for_each_field.cpp : : : $(CLASSIC_PREC_DEF) : precise_for_each_field ]
[ run precise/motivating_example0.cpp : : : $(CLASSIC_PREC_DEF) : precise_motivating_example0 ]
[ run precise/motivating_example.cpp : : : $(CLASSIC_PREC_DEF) : precise_motivating_example ]
[ run precise/motivating_example2.cpp : : : $(CLASSIC_PREC_DEF) : precise_motivating_example2 ]
[ run precise/optional_like.cpp : : : $(CLASSIC_PREC_DEF) : precise_optional_like ]
[ run precise/get_non_default_constructible.cpp : : : $(CLASSIC_PREC_DEF) : precise_get_non_default_constructible ]
[ run precise/destructuring_tie.cpp : : : $(CLASSIC_PREC_DEF) : precise_destructuring_tie ]
[ run precise/error_pfr_c1202.cpp : : : $(CLASSIC_PREC_DEF) : precise_c1202_issue21 ]
[ compile-fail precise/non_aggregate.cpp : $(CLASSIC_PREC_DEF) : precise_non_aggregate ]
[ run precise/tie_anonymous.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_tie_anonymous ]
# See "Requirements and Limitations" section of the docs for info on following tests:
#[ compile-fail precise/template_constructor.cpp : $(CLASSIC_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_template_constructor14 ]
#[ compile-fail precise/template_unconstrained.cpp : $(CLASSIC_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_template_unconstrained14 ]
[ run precise/template_constructor.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_template_constructor ]
# TODO:
#[ run precise/template_unconstrained.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_template_unconstrained ]
# The following tests may compile of fail depending on C++ Standard version.
#[ compile-fail precise/issue30.cpp : $(CLASSIC_PREC_DEF) : precise_issue30 ]
#[ compile-fail precise/issue33.cpp : $(CLASSIC_PREC_DEF) : precise_issue33 ]
##### Loophole tests running precise and flat specific tests
[ run flat/core.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_core ]
[ run flat/flat_tuple_size.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_tuple_size ]
[ run flat/flat_motivating_example.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_motivating_example ]
[ run flat/flat_for_each_field.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_for_each_field ]
[ compile-fail flat/flat_tuple_size_on_non_aggregate.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_tuple_size_on_non_aggregate ]
[ compile-fail flat/flat_tuple_size_on_bitfields.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_tuple_size_on_bitfields ]
[ run precise/tuple_size.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_tuple_size ]
[ run precise/bitfields.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_tuple_size_on_bitfields ]
[ run precise/for_each_field.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_for_each_field ]
[ run precise/motivating_example0.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_motivating_example0 ]
[ run precise/motivating_example.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_motivating_example ]
[ run precise/motivating_example2.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_motivating_example2 ]
[ run precise/optional_like.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_optional_like ]
[ run precise/get_non_default_constructible.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_get_non_default_constructible ]
[ run precise/error_pfr_c1202.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_c1202_issue21 ]
[ run precise/issue30.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue30 ]
[ run precise/issue33.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue33 ]
[ compile-fail precise/non_aggregate.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_non_aggregate ]
[ run precise/tie_anonymous.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_tie_anonymous ]
# See "Requirements and Limitations" section of the docs for info on following tests:
#[ compile-fail precise/template_constructor.cpp : $(LOOPHOLE_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_lh_template_constructor14 ]
#[ compile-fail precise/template_unconstrained.cpp : $(LOOPHOLE_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_lh_template_unconstrained14 ]
[ run precise/template_constructor.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_template_constructor ]
# TODO:
#[ run precise/template_unconstrained.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_template_unconstrained ]
# Examples from docs
[ run ../example/examples.cpp : : : $(DISABLE_ON_MSVC) ]
[ run ../example/quick_examples.cpp : : : $(DISABLE_ON_MSVC) ]
;

92
test/appveyor.yml Normal file
View File

@@ -0,0 +1,92 @@
# Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Copyright Antony Polukhin 2016-2019.
#
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
# and how it can be used with Boost libraries.
#
# File revision #6 (with DIFF)
init:
- set BOOST_REMOVE=%APPVEYOR_PROJECT_NAME% # Remove this folder from lib from full clone of Boost.
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
version: 1.64.{build}-{branch}
# branches to build
branches:
except:
- gh-pages
skip_tags: true
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
ADDRMD: 32,64
CXXSTD: 17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
ADDRMD: 32,64
CXXSTD: 17,latest
CXXFLAGS: /permissive-
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin\bin;
TOOLSET: gcc
CXXSTD: 14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin64\bin;
TOOLSET: gcc
CXXSTD: 14,1z
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# ADDPATH: C:\mingw\bin;
# TOOLSET: gcc
# CXXSTD: 14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;
TOOLSET: gcc
CXXSTD: 14,1z
before_build:
- set BOOST_BRANCH=develop
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
- echo "Testing %APPVEYOR_PROJECT_NAME%"
# Cloning Boost libraries (fast nondeep cloning)
- set BOOST=C:/boost-local
- git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git %BOOST%
- cd %BOOST%
- git submodule update --init --depth 10 tools/build tools/boostdep libs/type_index # DIFF: Added libs/type_index
- rm -rf %BOOST%/libs/%BOOST_REMOVE%
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%APPVEYOR_PROJECT_NAME%
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" %APPVEYOR_PROJECT_NAME%
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" type_index # DIFF: Added
build_script:
- cmd /c bootstrap
- b2.exe headers
- cd %BOOST%/libs/%APPVEYOR_PROJECT_NAME%/test
after_build:
before_test:
test_script:
- PATH=%ADDPATH%%PATH%
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- echo "Running command ..\..\..\b2 -j3 toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release"
- ..\..\..\b2.exe -j3 toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release cxxflags="-DBOOST_TRAVISCI_BUILD %CXXFLAGS%"
after_test:
on_success:
on_failure:
on_finish:

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2018 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/detail/fields_count.hpp>
struct some_struct {
int i;
int j;
};
int main() {
static_assert(boost::pfr::detail::fields_count<const some_struct>() == 2, "");
}

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2018 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/detail/fields_count.hpp>
struct some_struct {
int i;
int j;
};
int main() {
return boost::pfr::detail::fields_count<some_struct&>();
}

View File

@@ -0,0 +1,168 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
# include <boost/pfr/flat/functions_for.hpp>
# define BOOST_PFR_TEST_FUNCTIONS_FOR BOOST_PFR_FLAT_FUNCTIONS_FOR
#elif defined(BOOST_PFR_TEST_PRECISE)
# include <boost/pfr/precise/functions_for.hpp>
# define BOOST_PFR_TEST_FUNCTIONS_FOR BOOST_PFR_PRECISE_FUNCTIONS_FOR
#else
# error Misused test
#endif
#include <boost/core/lightweight_test.hpp>
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <string>
#include <boost/functional/hash.hpp>
#include <unordered_set>
struct adl_hash {
template <class T>
std::size_t operator()(const T& val) const {
using namespace boost;
return hash_value(val);
}
};
struct comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(comparable_struct)
template <typename Struct>
void test_some_comparable_struct() {
Struct s1 {0, 1, false, 6,7,8,9,10,11};
Struct s2 = s1;
Struct s3 {0, 1, false, 6,7,8,9,10,11111};
BOOST_TEST_EQ(s1, s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
BOOST_TEST(!(s1 != s2));
BOOST_TEST(!(s1 == s3));
BOOST_TEST(s1 != s3);
BOOST_TEST(s1 < s3);
BOOST_TEST(s3 > s2);
BOOST_TEST(s1 <= s3);
BOOST_TEST(s3 >= s2);
std::cout << s1 << std::endl;
Struct s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
BOOST_TEST_EQ(s1, s4);
int i = 1, j = 2;
BOOST_TEST_NE(i, j);
}
void test_comparable_struct() {
test_some_comparable_struct<comparable_struct>();
}
struct empty { operator std::string() { return "empty{}"; } };
BOOST_PFR_TEST_FUNCTIONS_FOR(empty)
void test_empty_struct() {
BOOST_TEST_EQ(empty{}, empty{});
}
namespace foo {
struct testing { bool b1, b2; int i; };
BOOST_PFR_TEST_FUNCTIONS_FOR(testing);
}
template <class Comparator>
void test_with_contatiners() {
std::set<foo::testing, Comparator > t{
{true, true, 100},
{false, true, 100},
{true, false, 100},
{true, true, 101}
};
BOOST_TEST(t.find({true, true, 100}) != t.end());
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
std::unordered_set<foo::testing, adl_hash> us(t.begin(), t.end());
BOOST_TEST_EQ(us.size(), t.size());
}
void test_implicit_conversions() {
std::stringstream ss;
ss << std::true_type{};
BOOST_TEST_EQ(ss.str(), "1"); // Does not breaks implicit conversion
ss.str("");
ss << empty{};
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_TEST_FUNCTIONS_FOR
}
namespace {
struct anonymous_comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(anonymous_comparable_struct)
struct other_anonymous_struct {
anonymous_comparable_struct a,b;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(other_anonymous_struct)
}
namespace std {
template <>
struct hash<anonymous_comparable_struct> {
std::size_t operator()(const anonymous_comparable_struct& val) const noexcept {
return hash_value(val);
}
};
}
namespace {
void test_anonymous_comparable_struct() {
test_some_comparable_struct<anonymous_comparable_struct>();
}
void test_nested_anonymous_comparable_struct() {
other_anonymous_struct s1{
{0, 1, false, 6,7,8,9,10,11},
{0, 1, false, 6,7,8,9,10,11},
};
auto s2 = s1;
BOOST_TEST_EQ(s1, s2);
}
}
int main() {
test_comparable_struct();
test_empty_struct();
test_with_contatiners<std::less<>>();
test_with_contatiners<std::greater<>>();
test_implicit_conversions();
test_anonymous_comparable_struct();
test_nested_anonymous_comparable_struct();
return boost::report_errors();
}

126
test/common/global_ops.cpp Normal file
View File

@@ -0,0 +1,126 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
# include <boost/pfr/flat/global_ops.hpp>
#elif defined(BOOST_PFR_TEST_PRECISE)
# include <boost/pfr/precise/global_ops.hpp>
#else
# error Misused test
#endif
#include <boost/core/lightweight_test.hpp>
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <string>
#include <unordered_set>
#define BOOST_HASH_NO_EXTENSIONS
#include <boost/container_hash/hash.hpp>
template <class T>
void test_comparable_struct() {
T s1 {0, 1, false, 6,7,8,9,10,11};
T s2 = s1;
T s3 {0, 1, false, 6,7,8,9,10,11111};
BOOST_TEST(s1 == s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
BOOST_TEST(!(s1 != s2));
BOOST_TEST(!(s1 == s3));
BOOST_TEST(s1 != s3);
BOOST_TEST(s1 < s3);
BOOST_TEST(s3 > s2);
BOOST_TEST(s1 <= s3);
BOOST_TEST(s3 >= s2);
std::cout << s1 << std::endl;
T s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
BOOST_TEST(s1 == s4);
int i = 1, j = 2;
BOOST_TEST_NE(i, j);
}
void test_empty_struct() {
struct empty {};
std::cout << empty{};
BOOST_TEST(empty{} == empty{});
}
struct adl_hash {
template <class T>
std::size_t operator()(const T& val) const {
using namespace boost;
return hash_value(val);
}
};
template <class Comparator>
void test_with_contatiners() {
struct testing { bool b1, b2; int i; };
std::set<testing, Comparator > t{
{true, true, 100},
{false, true, 100},
{true, false, 100},
{true, true, 101}
};
BOOST_TEST(t.find({true, true, 100}) != t.end());
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
std::unordered_set<testing, adl_hash> us(t.begin(), t.end());
BOOST_TEST_EQ(us.size(), t.size());
}
namespace foo {
struct comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
}
void test_implicit_conversions() {
std::stringstream ss;
ss << std::true_type{};
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion :(
}
int main() {
test_comparable_struct<foo::comparable_struct>();
struct local_comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
test_comparable_struct<local_comparable_struct>();
test_empty_struct();
#ifndef BOOST_CLANG
// TODO: Fails for unknown reason on Clang
test_with_contatiners<std::less<>>();
test_with_contatiners<std::greater<>>();
#endif
test_implicit_conversions();
return boost::report_errors();
}

View File

@@ -0,0 +1,30 @@
// Copyright (c) 2018 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/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
struct X {
X() = default;
X(X&&) = default;
X(const X&) = delete;
X& operator=(X&&) = default;
X& operator=(const X&) = delete;
};
struct test_lvalue_ref_and_movable {
X x;
char& c;
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_lvalue_ref_and_movable>::value;
#else
return boost::pfr::tuple_size<test_lvalue_ref_and_movable>::value;
#endif
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2018 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)
#ifdef BOOST_PFR_TEST_PRECISE
# include <boost/pfr/precise/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_FLAT)
# include <boost/pfr/flat/tuple_size.hpp>
#else
# error Misused test
#endif
#include <boost/core/lightweight_test.hpp>
struct X {
X() = default;
X(X&&) = default;
X(const X&) = delete;
X& operator=(X&&) = default;
X& operator=(const X&) = delete;
};
struct S { X x0; X x1; int x2; X x3; };
int main() {
#ifdef BOOST_PFR_TEST_PRECISE
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
struct S5_0 { int x0; int x1; int x2; int x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_0> == 5, "");
struct S5_1 { X x0; int x1; int x2; int x3; int x4; };
static_assert(boost::pfr::tuple_size_v<S5_1> == 5, "");
struct S5_2 { int x0; int x1; X x2; int x3; int x4; };
static_assert(boost::pfr::tuple_size_v<S5_2> == 5, "");
struct S5_3 { int x0; int x1; X x2; int x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_3> == 5, "");
struct S5_4 { X x0; X x1; X x2; X x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_4> == 5, "");
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
#elif defined(BOOST_PFR_TEST_FLAT)
// Test disabled in Jamfile!
// Does not compile since GCC-10. Result is quite strange on compilers where the code compiles:
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,44 @@
// Copyright (c) 2018 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)
#ifdef BOOST_PFR_TEST_PRECISE
# include <boost/pfr/precise/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_FLAT)
# include <boost/pfr/flat/tuple_size.hpp>
#else
# error Misused test
#endif
struct X {
X(int) {}
};
struct S { X x0; X x1; int x2; X x3; };
int main() {
#ifdef BOOST_PFR_TEST_PRECISE
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
struct S5_0 { int x0; int x1; int x2; int x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_0> == 5, "");
struct S5_1 { X x0; int x1; int x2; int x3; int x4; };
static_assert(boost::pfr::tuple_size_v<S5_1> == 5, "");
struct S5_2 { int x0; int x1; X x2; int x3; int x4; };
static_assert(boost::pfr::tuple_size_v<S5_2> == 5, "");
struct S5_3 { int x0; int x1; X x2; int x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_3> == 5, "");
struct S5_4 { X x0; X x1; X x2; X x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_4> == 5, "");
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
#elif defined(BOOST_PFR_TEST_FLAT)
return boost::pfr::flat_tuple_size_v<S>;
#endif
}

View File

@@ -0,0 +1,59 @@
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_PRECISE
# include <boost/pfr/precise/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_FLAT)
# include <boost/pfr/flat/tuple_size.hpp>
#else
# error Misused test
#endif
#include <type_traits>
#include <boost/core/lightweight_test.hpp>
struct X {
X(X&&) = default;
X(const X&) = delete;
X& operator=(X&&) = default;
X& operator=(const X&) = delete;
};
struct S { X x0; X x1; int x2; X x3; };
static_assert(!std::is_default_constructible<X>::value, "");
static_assert(!std::is_default_constructible<S>::value, "");
int main() {
#ifdef BOOST_PFR_TEST_PRECISE
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
struct S5_0 { int x0; int x1; int x2; int x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_0> == 5, "");
struct S5_1 { X x0; int x1; int x2; int x3; int x4; };
static_assert(boost::pfr::tuple_size_v<S5_1> == 5, "");
struct S5_2 { int x0; int x1; X x2; int x3; int x4; };
static_assert(boost::pfr::tuple_size_v<S5_2> == 5, "");
struct S5_3 { int x0; int x1; X x2; int x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_3> == 5, "");
struct S5_4 { X x0; X x1; X x2; X x3; X x4; };
static_assert(boost::pfr::tuple_size_v<S5_4> == 5, "");
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
#elif defined(BOOST_PFR_TEST_FLAT)
// Test disabled in Jamfile!
// Does not compile since GCC-10. Result is quite strange on compilers where the code compiles:
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
# include <boost/pfr/flat/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_PRECISE)
# include <boost/pfr/precise/tuple_size.hpp>
#else
# error Misused test
#endif
struct non_standard_layout_member {
private:
int i = 0;
public:
int j = 1;
};
struct test_with_non_st_layout {
non_standard_layout_member m;
double d;
float f;
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_non_st_layout>::value;
#else
static_assert(boost::pfr::tuple_size<test_with_non_st_layout>::value == 3, "");
#endif
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) 2019 Ilya Kiselev
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/detail/offset_based_getter.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/core/lightweight_test.hpp>
struct user_type {
char c;
double d;
};
int main() {
using pfr_tuple = boost::pfr::detail::sequence_tuple::tuple<char, double>;
using getter = boost::pfr::detail::offset_based_getter<user_type, pfr_tuple>;
using boost::pfr::detail::size_t_;
using boost::pfr::detail::sequence_tuple::get;
user_type value{};
auto begin = reinterpret_cast<char*>(&value);
auto native_offset = reinterpret_cast<char*>(&value.d) - begin;
auto getter_offset = reinterpret_cast<char*>(&getter{}.get(value, size_t_<1>{})) - begin;
BOOST_TEST_EQ(native_offset, getter_offset);
pfr_tuple pfr_value{};
auto pfr_tuple_offset = (
reinterpret_cast<char*>(&get<1>(pfr_value)) - reinterpret_cast<char*>(&get<0>(pfr_value))
);
BOOST_TEST_EQ(native_offset, pfr_tuple_offset);
return boost::report_errors();
}

118
test/common/ops.cpp Normal file
View File

@@ -0,0 +1,118 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
#define BOOST_PFR_TEST_NAMESPECE boost::pfr::flat_ops
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
#define BOOST_PFR_TEST_NAMESPECE boost::pfr::ops
#endif
unsigned test_union_counter = 0;
union test_union {
int i;
float f;
};
inline bool operator< (test_union l, test_union r) noexcept { ++test_union_counter; return l.i < r.i; }
inline bool operator<=(test_union l, test_union r) noexcept { ++test_union_counter; return l.i <= r.i; }
inline bool operator> (test_union l, test_union r) noexcept { ++test_union_counter; return l.i > r.i; }
inline bool operator>=(test_union l, test_union r) noexcept { ++test_union_counter; return l.i >= r.i; }
inline bool operator==(test_union l, test_union r) noexcept { ++test_union_counter; return l.i == r.i; }
inline bool operator!=(test_union l, test_union r) noexcept { ++test_union_counter; return l.i != r.i; }
inline std::ostream& operator<<(std::ostream& os, test_union src) { ++test_union_counter; return os << src.i; }
inline std::istream& operator>>(std::istream& is, test_union& src) { ++test_union_counter; return is >> src.i; }
template <class T>
void test_comparable_struct() {
using namespace BOOST_PFR_TEST_NAMESPECE;
T s1 {0, 1, false, 6,7,8,9,10,11};
T s2 = s1;
T s3 {0, 1, false, 6,7,8,9,10,11111};
BOOST_TEST(s1 == s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
BOOST_TEST(!(s1 != s2));
BOOST_TEST(!(s1 == s3));
BOOST_TEST(s1 != s3);
BOOST_TEST(s1 < s3);
BOOST_TEST(s3 > s2);
BOOST_TEST(s1 <= s3);
BOOST_TEST(s3 >= s2);
std::cout << s1 << std::endl;
T s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
BOOST_TEST(s1 == s4);
int i = 1, j = 2;
BOOST_TEST_NE(i, j);
}
void test_empty_struct() {
struct empty {};
using namespace BOOST_PFR_TEST_NAMESPECE;
std::cout << empty{};
BOOST_TEST(empty{} == empty{});
}
void test_implicit_conversions() {
using namespace BOOST_PFR_TEST_NAMESPECE;
std::stringstream ss;
ss << std::true_type{};
BOOST_TEST_EQ(ss.str(), "1"); // Does not break implicit conversion
}
namespace foo {
struct comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
}
int main() {
test_comparable_struct<foo::comparable_struct>();
struct local_comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
test_comparable_struct<local_comparable_struct>();
#if defined(BOOST_PFR_TEST_PRECISE)
struct local_comparable_struct_with_union {
int i; short s; bool bl; int a,b,c,d,e; test_union u;
};
test_comparable_struct<local_comparable_struct_with_union>();
// Making sure that test_union overloaded operations were called.
BOOST_TEST_EQ(test_union_counter, 17);
#endif
test_empty_struct();
test_implicit_conversions();
return boost::report_errors();
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) 2018 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 <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
using namespace boost::pfr::flat_ops;
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
using namespace boost::pfr::ops;
#endif
union test_union {
const char* c;
int i;
};
int main() {
test_union v{""};
return v == v;
}

View File

@@ -0,0 +1,30 @@
// Copyright (c) 2018 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 <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
using namespace boost::pfr::flat_ops;
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
using namespace boost::pfr::ops;
#endif
union test_union {
const char* c;
int i;
};
int main() {
struct two_unions {
test_union u1, u2;
};
two_unions v{{""}, {""}};
return v == v;
}

View File

@@ -0,0 +1,32 @@
// Copyright (c) 2018 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 <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
using namespace boost::pfr::flat_ops;
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
using namespace boost::pfr::ops;
#endif
union test_unrestricted_union {
int i;
std::string s;
};
int main() {
struct two_unions {
test_unrestricted_union u1, u2;
};
// Not calling the destructor intentionally!
auto v = new two_unions{{1}, {1}};
return *v == *v;
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2018 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/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
class test_with_private {
private:
int i;
char c;
public:
double d;
float f;
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_private>::value;
#else
#ifndef __cpp_lib_is_aggregate
# error No known way to detect private fields.
#endif
return boost::pfr::tuple_size<test_with_private>::value;
#endif
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2018 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/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
class test_with_protected {
protected:
int i;
char c;
public:
double d;
float f;
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_protected>::value;
#else
#ifndef __cpp_lib_is_aggregate
# error No known way to detect protected fields.
#endif
return boost::pfr::tuple_size<test_with_protected>::value;
#endif
}

150
test/common/read_write.cpp Normal file
View File

@@ -0,0 +1,150 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <sstream>
#include <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/io.hpp>
namespace boost { namespace test {
template <class Char, class Traits, class T>
void read(std::basic_istream<Char, Traits>& in, T& value) {
::boost::pfr::flat_read(in, value);
}
template <class Char, class Traits, class T>
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
::boost::pfr::flat_write(out, value);
}
}}
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/io.hpp>
namespace boost { namespace test {
using boost::pfr::read;
using boost::pfr::write;
}}
#endif
template <class T>
void test_write_read(const T& value) {
T result;
std::stringstream ss;
boost::test::write(ss, value);
boost::test::read(ss, result);
BOOST_TEST_EQ(value.f0, result.f0);
BOOST_TEST_EQ(value.f1, result.f1);
BOOST_TEST_EQ(value.f2, result.f2);
BOOST_TEST_EQ(value.f3, result.f3);
BOOST_TEST_EQ(value.f4, result.f4);
}
template <class T>
void to_string_test(const T& value, const char* ethalon) {
std::stringstream ss;
boost::test::write(ss, value);
BOOST_TEST_EQ(ss.str(), ethalon);
}
template <class T>
void test_type(const T& value, const char* ethalon) {
test_write_read(value);
to_string_test(value, ethalon);
}
struct with_operator{};
inline bool operator==(with_operator, with_operator) {
return true;
}
std::ostream& operator<<(std::ostream& os, with_operator) {
return os << "{with_operator}";
}
std::istream& operator>>(std::istream& is, with_operator&) {
std::string s;
is >> s;
return is;
}
int main() {
struct test1 {
int f0;
int f1;
char f2;
int f3;
short f4;
};
test_type(test1{1, 2, '3', 4, 5}, "{1, 2, 3, 4, 5}");
test_type(test1{199, 299, '9', 499, 599}, "{199, 299, 9, 499, 599}");
#ifdef BOOST_PFR_TEST_PRECISE
struct test2 {
with_operator f0;
with_operator f1;
with_operator f2;
with_operator f3;
with_operator f4;
};
test_type(test2{}, "{{with_operator}, {with_operator}, {with_operator}, {with_operator}, {with_operator}}");
struct test3 {
int f0;
int f1;
char f2;
int f3;
with_operator f4;
};
test_type(
test3{1, 2, '3', 4, {}},
"{1, 2, 3, 4, {with_operator}}"
);
#if (BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE) \
&& !defined(_MSC_VER) /* TODO: remove after fixing strange errors https://ci.appveyor.com/project/apolukhin/magic-get/build/1.65.108-develop */
struct test4 {
int f0;
std::string f1;
char f2;
int f3;
std::string f4;
};
test_type(
test4{1, {"my o my"}, '3', 4, {"hello there!"} },
"{1, \"my o my\", 3, 4, \"hello there!\"}"
);
#if 0
// TODO:
std::string f1_referenced{"my O my"};
std::string f4_referenced{"Hello There!"};
struct test5 {
int f0;
const std::string& f1;
char f2;
int f3;
const std::string& f4;
};
to_string_test(
test5{1, f1_referenced, '3', 4, f4_referenced },
"{1, \"my o my\", 3, 4, \"hello there!\"}"
);
#endif
#endif
#endif // BOOST_PFR_TEST_PRECISE
return boost::report_errors();
}

View File

@@ -0,0 +1,45 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_PRECISE
# include <boost/pfr/precise/core.hpp>
# define BOOST_PFR_TEST_FUNCTION(x) boost::pfr::get<I>(x)
#elif defined(BOOST_PFR_TEST_FLAT)
# include <boost/pfr/flat/core.hpp>
# define BOOST_PFR_TEST_FUNCTION(x) boost::pfr::flat_get<I>(x)
#else
# error Misused test
#endif
#include <boost/core/lightweight_test.hpp>
namespace helper {
template <std::size_t I, class T>
decltype(auto) get(T&& v) {
return BOOST_PFR_TEST_FUNCTION(std::forward<T>(v));
}
}
int main() {
using namespace std;
using namespace helper;
struct foo { int i; short s;};
foo f{1, 2};
BOOST_TEST_EQ(get<0>(f), 1);
const foo cf{1, 2};
BOOST_TEST_EQ(get<1>(cf), 2);
std::tuple<int, short> t{10, 20};
BOOST_TEST_EQ(get<0>(t), 10);
const std::tuple<int, short> ct{10, 20};
BOOST_TEST_EQ(get<1>(ct), 20);
return boost::report_errors();
}

View File

@@ -0,0 +1,126 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/precise/core.hpp>
template <class T1, std::size_t CountInT, std::size_t CountHelpers>
void test_counts_on_multiple_chars_impl_1() {
using boost::pfr::flat_tuple_size_v;
using boost::pfr::tuple_size_v;
struct t1_c { T1 v1; char c[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_c> == CountInT + CountHelpers, "");
struct t1_s { T1 v1; short s[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_s> == CountInT + CountHelpers, "");
struct t1_i { T1 v1; const int i[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_i> == CountInT + CountHelpers, "");
struct t1_p { T1 v1; void* p[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_p> == CountInT + CountHelpers, "");
struct t1_ll { T1 v1; long long ll[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_ll> == CountInT + CountHelpers, "");
struct rt1_c { char c[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_c> == CountInT + CountHelpers, "");
struct rt1_s { const short s[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_s> == CountInT + CountHelpers, "");
struct rt1_i { int i[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_i> == CountInT + CountHelpers, "");
struct rt1_p { void* p[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_p> == CountInT + CountHelpers, "");
struct rt1_ll { long long ll[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_ll> == CountInT + CountHelpers, "");
struct rt1_ll_1 { rt1_ll v1; };
static_assert(flat_tuple_size_v<rt1_ll_1> == CountInT + CountHelpers, "");
static_assert(tuple_size_v<rt1_ll_1> == 1, "");
}
template <class T1, std::size_t CountInT>
void test_counts_on_multiple_chars_impl() {
using boost::pfr::flat_tuple_size_v;
using boost::pfr::tuple_size_v;
struct t1_0 { T1 v1; };
static_assert(flat_tuple_size_v<t1_0> == CountInT, "");
static_assert(flat_tuple_size_v<T1> == CountInT, "");
static_assert(flat_tuple_size_v<std::conditional_t<std::is_fundamental<T1>::value, T1*, void*> > == 1, "");
#if !defined(__GNUC__) || __GNUC__ != 8
// GCC-8 has big problems with this test:
// error: 'constexpr ubiq_constructor::operator Type&() const [with Type = test_counts_on_multiple_chars()::t2*]',
// declared using local type 'test_counts_on_multiple_chars()::t2', is used but never defined [-fpermissive]
//
// Fixed in GCC-9.
static_assert(tuple_size_v<T1*> == 1, "");
#endif
struct t1_0_1 { t1_0 t1; };
static_assert(flat_tuple_size_v<t1_0_1> == CountInT, "");
static_assert(tuple_size_v<t1_0_1> == 1, "");
struct t1_0_2 { t1_0 t1; t1_0 t2; };
static_assert(flat_tuple_size_v<t1_0_2> == CountInT * 2, "");
static_assert(tuple_size_v<t1_0_2> == 2, "");
static_assert(flat_tuple_size_v<T1[5]> == CountInT * 5, "");
test_counts_on_multiple_chars_impl_1<T1, CountInT, 1>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 2>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 3>();
#ifdef BOOST_PFR_RUN_HUGE_TESTS
test_counts_on_multiple_chars_impl_1<T1, CountInT, 4>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 5>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 6>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 7>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 8>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 9>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 10>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 11>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 12>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 13>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 14>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 15>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 16>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 17>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 18>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 19>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 20>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 23>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 24>();
#endif
}
template <class T>
void test_counts_on_multiple_chars() {
using boost::pfr::tuple_size_v;
test_counts_on_multiple_chars_impl<T, 1>();
struct t2 { T v1; T v2; };
static_assert(tuple_size_v<t2> == 2, "");
test_counts_on_multiple_chars_impl<t2, 2>();
test_counts_on_multiple_chars_impl<T[2], 2>();
test_counts_on_multiple_chars_impl<T[3], 3>();
test_counts_on_multiple_chars_impl<T[4], 4>();
struct t8 { T v1; T v2; T v3; T v4; T v5; T v6; T v7; T v8; };
test_counts_on_multiple_chars_impl<t8, 8>();
}
int main() {
test_counts_on_multiple_chars< BOOST_PFR_RUN_TEST_ON >();
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) 2018 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/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
struct test_with_virtual {
int i = 0;
char c = 'a';
double d = 3.4;
float f = 3.5f;
virtual double sum() const { return i + d + c + f; }
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_virtual>::value;
#else
return boost::pfr::tuple_size<test_with_virtual>::value;
#endif
}

709
test/flat/core.cpp Normal file
View File

@@ -0,0 +1,709 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//#define BOOST_PFR_RELAX_POD_REQUIREMENT
#include <boost/pfr.hpp>
#include <boost/core/lightweight_test.hpp>
//#include <boost/type_index.hpp> // for debugging
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <cstring>
using namespace boost::pfr;
template <std::size_t I, class T>
void print(T& f) {
std::cout << flat_get<I>(f) << "\t\t"
<< typeid(flat_tuple_element_t<I, T>).name()
<< std::endl;
}
struct make_my_life_harder { int a0; short a1; };
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
struct foo {
unsigned char v0;
unsigned int v1;
unsigned short v2;
unsigned long long v3;
unsigned char v4and5[2];
int v6;
std::size_t v7;
int* v8;
const void* v9;
int const**const volatile**volatile** v10;
const double v11;
make_my_life_harder v12and13;
make_my_life_even_more_harder v14and15andv16and17;
};
void test_print() {
foo f {
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
, {18, 19}
, {20, 21, {22, 23}}
};
print<0>(f); print<1>(f); print<2>(f);
print<3>(f); print<4>(f); print<5>(f);
print<6>(f); print<7>(f); print<8>(f);
print<9>(f); print<10>(f); print<11>(f);
print<12>(f); print<13>(f); print<14>(f);
print<15>(f); print<16>(f); print<17>(f);
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
int a[] = {0, 1, 2, 3};
std::cout << '\n' << flat_get<1>(a) << std::endl;
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
std::cout << flat_get<4>(b) << std::endl;
int i = 777;
std::cout << flat_get<0>(i) << std::endl;
}
void test_runtime(const foo& f) {
BOOST_TEST_EQ( flat_get<0>(f), f.v0);
BOOST_TEST_EQ( flat_get<1>(f), f.v1);
BOOST_TEST_EQ( flat_get<2>(f), f.v2);
BOOST_TEST_EQ( flat_get<3>(f), f.v3);
BOOST_TEST_EQ( flat_get<4>(f), f.v4and5[0]);
BOOST_TEST_EQ( flat_get<5>(f), f.v4and5[1]);
BOOST_TEST_EQ( flat_get<6>(f), f.v6);
BOOST_TEST_EQ( flat_get<7>(f), f.v7);
BOOST_TEST_EQ( flat_get<8>(f), f.v8);
BOOST_TEST_EQ( flat_get<9>(f), f.v9);
BOOST_TEST_EQ( flat_get<10>(f), f.v10);
BOOST_TEST( flat_get<11>(f) < f.v11 + 0.001); BOOST_TEST( flat_get<11>(f) > f.v11 - 0.001);
BOOST_TEST_EQ( flat_get<12>(f), f.v12and13.a0);
BOOST_TEST_EQ( flat_get<13>(f), f.v12and13.a1);
BOOST_TEST_EQ( flat_get<14>(f), f.v14and15andv16and17.b0);
BOOST_TEST_EQ( flat_get<15>(f), f.v14and15andv16and17.b1);
BOOST_TEST_EQ( flat_get<16>(f), f.v14and15andv16and17.cr.a0);
BOOST_TEST_EQ( flat_get<17>(f), f.v14and15andv16and17.cr.a1);
}
template <class T>
void test_compiletime() {
constexpr T f{};
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
}
template <class T>
constexpr void test_compiletime_array() {
{
constexpr T f[20] = {0};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
{
constexpr T f[2][10] = {{0}};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
{
constexpr T f[2][5][2] = {{{0}}};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
}
void test_with_enums() {
enum class my_enum: unsigned {
VALUE1 = 17, VALUE2, VALUE3
};
struct my_struct { my_enum e; int i; short s; };
my_struct s {my_enum::VALUE1, 10, 11};
std::tuple<unsigned, int, short> t = flat_structure_to_tuple(s);
BOOST_TEST_EQ(std::get<0>(t), 17u);
BOOST_TEST_EQ(std::get<1>(t), 10);
BOOST_TEST_EQ(std::get<2>(t), 11);
flat_get<1>(s) = 101;
BOOST_TEST_EQ(flat_get<1>(s), 101);
flat_get<2>(s) = 111;
BOOST_TEST_EQ(flat_get<2>(s), 111);
BOOST_TEST(flat_structure_tie(s) == flat_structure_tie(s));
BOOST_TEST(flat_structure_tie(s) == flat_structure_to_tuple(s));
BOOST_TEST(flat_structure_tie(s) != t);
flat_structure_tie(s) = t;
BOOST_TEST_EQ(flat_get<0>(s), 17u);
BOOST_TEST_EQ(flat_get<1>(s), 10);
BOOST_TEST_EQ(flat_get<2>(s), 11);
static_assert(std::is_same<
int, flat_tuple_element_t<1, my_struct>
>::value, "");
static_assert(std::is_same<
short, flat_tuple_element_t<2, my_struct>
>::value, "");
static_assert(std::is_same<
const int, flat_tuple_element_t<1, const my_struct>
>::value, "");
static_assert(std::is_same<
volatile short, flat_tuple_element_t<2, volatile my_struct>
>::value, "");
static_assert(std::is_same<
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
>::value, "");
static_assert(
3 == flat_tuple_size_v<const volatile my_struct>,
""
);
}
void test_comparable_struct() {
struct comparable_struct {
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
};
using namespace flat_ops;
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
comparable_struct s2 = s1;
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
BOOST_TEST(s1 == s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
BOOST_TEST(!(s1 != s2));
BOOST_TEST(!(s1 == s3));
BOOST_TEST(s1 != s3);
BOOST_TEST(s1 < s3);
BOOST_TEST(s3 > s2);
BOOST_TEST(s1 <= s3);
BOOST_TEST(s3 >= s2);
std::cout << s1 << std::endl;
comparable_struct s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
BOOST_TEST(s1 == s4);
int i = 1, j = 2;
BOOST_TEST_NE(i, j);
}
void test_empty_struct() {
struct empty {};
using namespace flat_ops;
std::cout << empty{} << std::endl;
BOOST_TEST(empty{} == empty{});
}
void test_pods_with_int_operators() {
using namespace flat_ops;
std::stringstream ss;
ss << std::is_pod<int>{};
int i = 0;
ss >> i;
BOOST_TEST_EQ(i, 1);
std::cout << i << std::endl;
}
void test_struct_with_single_field() {
struct f1 { int i; };
using namespace flat_ops;
std::stringstream ss;
ss << f1{ 777 };
f1 var{};
ss >> var;
BOOST_TEST_EQ(var.i, 777);
BOOST_TEST(var == f1{ 777 });
BOOST_TEST(var != f1{ 778 });
BOOST_TEST(var <= f1{ 777 });
BOOST_TEST(var <= f1{ 778 });
BOOST_TEST(var < f1{ 778 });
BOOST_TEST(var >= f1{ 777 });
BOOST_TEST(var >= f1{ 776 });
BOOST_TEST(var > f1{ 776 });
}
template <class Comparator>
void test_with_contatiners() {
struct testing { bool b1, b2; int i; };
struct testing2 { bool b1, b2; int i; };
std::set<testing, Comparator > t{
{true, true, 100},
{false, true, 100},
{true, false, 100},
{true, true, 101}
};
BOOST_TEST(t.find({true, true, 100}) != t.end());
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
BOOST_TEST(t.find(testing2{true, true, 100}) != t.end());
std::set<testing2, Comparator > t2{
{true, true, 101},
{true, true, 100},
{true, false, 100},
{false, true, 100}
};
BOOST_TEST(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
BOOST_TEST(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
std::vector<testing> res;
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
std::back_inserter(res), Comparator{});
BOOST_TEST_EQ(res.size(), 4u);
}
void test_with_user_defined_constructor() {
struct pr {
int i;
short s;
pr() = default;
pr(const pr&) = default;
pr(pr&&) = default;
pr(int ii, short is) noexcept
: i(ii), s(is)
{}
};
pr p{1, 2};
//assert(flat_get<1>(p) == 2); // Compilation error
}
void test_hash() {
struct almost_pair { int i; short s; };
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
s.insert({0, 1});
s.insert({1, 0});
s.insert({1, 1});
BOOST_TEST_EQ(s.size(), 3u);
flat_hash<almost_pair> hs;
BOOST_TEST_NE(hs({0, 1}), hs({1, 0}));
BOOST_TEST_EQ(hs({0, 1}), hs({0, 1}));
BOOST_TEST_EQ(hs({1, 1}), hs({1, 1}));
BOOST_TEST_NE(hs({0, 0}), hs({1, 1}));
struct single_field { int i; };
BOOST_TEST_NE(flat_hash<single_field>()({1}), std::hash<int>()(1));
BOOST_TEST_NE(flat_hash<single_field>()({199}), std::hash<int>()(199));
}
// Test case by Lisa Lippincott
void test_alignment_with_nested_structure() {
struct A0 {
short s;
char c;
};
struct B0 {
A0 a;
char c1;
char c2;
};
B0 test_struct;
std::memset(&test_struct, 0, sizeof(test_struct));
test_struct.a.s = 0;
test_struct.a.c = '1';
test_struct.c1 = '2';
test_struct.c2 = '3';
BOOST_TEST_EQ(flat_get<0>(test_struct), 0);
BOOST_TEST_EQ(flat_get<1>(test_struct), '1');
BOOST_TEST_EQ(flat_get<2>(test_struct), '2');
BOOST_TEST_EQ(flat_get<3>(test_struct), '3');
}
template <std::size_t... I>
void test_and_debug_internals(std::index_sequence<I...>) {
struct A0 {
short s;
char c;
};
A0 a0 { 3, '4' };
BOOST_TEST_EQ(boost::pfr::flat_get<0>(a0), 3);
BOOST_TEST_EQ(boost::pfr::flat_get<1>(a0), '4');
struct A1 {
int i;
};
struct B1 {
A1 a;
int j;
};
B1 b1 { {5}, 6 };
BOOST_TEST_EQ(boost::pfr::flat_get<0>(b1), 5);
BOOST_TEST_EQ(boost::pfr::flat_get<1>(b1), 6);
/*
struct B0 {
A0 a;
char c1;
char c2;
};
typedef B0 type;
typedef B0 T;
using namespace boost::pfr::detail;
constexpr auto a = flat_array_of_type_ids<T>();
(void)a; // `a` is unused if T is an empty type
constexpr size_array<a.size()> skips_in_subtuples {{
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
}};
constexpr size_array<sizeof...(I) + 1> indexes_in_subtuples_uncleanuped {{ 1, 1 + I...}};
constexpr auto indexes_plus_1_and_zeros_as_skips = remove_skips(indexes_in_subtuples_uncleanuped, skips_in_subtuples);
constexpr auto new_size = size_t_<indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
constexpr auto indexes = resize_dropping_zeros_and_decrementing(new_size, indexes_plus_1_and_zeros_as_skips);
static_assert(indexes.data[0] == 0, "");
static_assert(indexes.data[1] == 4, "");
static_assert(indexes.data[2] == 5, "");
static_assert(
std::is_same<
decltype(boost::pfr::detail::as_flat_tuple_impl<type>(
detail::make_index_sequence< decltype(boost::pfr::detail::flat_array_of_type_ids<type>())::size() >()
)),
boost::pfr::detail::sequence_tuple::tuple<boost::pfr::detail::sequence_tuple::tuple<short, char>, char, char>
>::value,
""
);
constexpr auto res = as_flat_tuple_impl<foo>(
detail::make_index_sequence< decltype(flat_array_of_type_ids<foo>())::size() >()
);
auto afoo = flat_array_of_type_ids<foo>();
std::cerr << "\n\n";
for (std::size_t i = 0; i < afoo.size(); ++i) {
std::cerr << afoo.data[i] << ' ';
}
std::cerr << boost::typeindex::type_id<decltype(res)>() << "\n\n";*/
}
// test by Alexey Moiseytsev
void another_test_with_unusual_alignment() {
struct nested {
char c0;
char c1;
int i0;
short s0;
char c2;
};
struct pair {
nested n0;
nested n1;
};
// layout:
// offset struct tuple
// 0 n0.c0 n0.c0
// 1 n0.c1 n0.c1
// 2 padding padding
// 3 padding padding
// 4 n0.i0 n0.i0
// 5 n0.i0 n0.i0
// 6 n0.i0 n0.i0
// 7 n0.i0 n0.i0
// 8 n0.s0 n0.s0
// 9 n0.s0 n0.s0
// 10 n0.c2 n0.c2
// 11 padding n1.c0 !!!
// 12 n1.c0 n1.c1 !!!
// 13 n1.c1 padding !!!
// 14 padding padding
// 15 padding padding
// 16 n1.i0 n1.i0
// 17 n1.i0 n1.i0
// 18 n1.i0 n1.i0
// 19 n1.i0 n1.i0
// 20 n1.s0 n1.s0
// 21 n1.s0 n1.s0
// 22 n1.c2 n1.c2
// 23 padding padding
pair s{{'q', 'w', 12, 32, 'e'}, {'a', 's', 24, 64, 'd'}};
BOOST_TEST_EQ(flat_get<0>(s), 'q');
BOOST_TEST_EQ(flat_get<1>(s), 'w');
BOOST_TEST_EQ(flat_get<2>(s), 12);
BOOST_TEST_EQ(flat_get<3>(s), 32);
BOOST_TEST_EQ(flat_get<4>(s), 'e');
BOOST_TEST_EQ(flat_get<5>(s), 'a');
BOOST_TEST_EQ(flat_get<6>(s), 's');
BOOST_TEST_EQ(flat_get<7>(s), 24);
BOOST_TEST_EQ(flat_get<8>(s), 64);
BOOST_TEST_EQ(flat_get<9>(s), 'd');
}
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
// Test inspired by Anton Bikineev
void test_structure_with_default_values() {
struct test_me {
int i = 2;
short s = 14;
};
test_me s;
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
}
// Test inspired by Anton Bikineev
void test_st_layout_structure_with_non_constexpr_type() {
/* TODO: fixme
struct non_literal_structure {
int i1 = 3;
short s1 = 15;
non_literal_structure() = delete;
non_literal_structure(const non_literal_structure&) = delete;
non_literal_structure(non_literal_structure&&) = default;
non_literal_structure& operator=(const non_literal_structure&) = delete;
non_literal_structure& operator=(non_literal_structure&&) = delete;
};
struct test_me {
int i = 2;
short s = 14;
non_literal_structure nonlit{};
};
BOOST_TEST_EQ(tuple_size_v<test_me>, 3);
test_me s{};
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
BOOST_TEST_EQ(flat_get<2>(s), 3);
BOOST_TEST_EQ(flat_get<3>(s), 15);*/
}
// Test inspired by Anton Bikineev
void test_structure_with_user_provided_default_constructor() {
struct test_me {
short s = 2;
constexpr test_me(short){}
};
test_me s{0};
(void)s;
BOOST_TEST_EQ(flat_get<0>(s), 2); // TODO: fix compile time error message
}
#endif
/*
void test_copy_only_pod() {
struct copy_only_pod {
int i1;
short s1;
copy_only_pod() = delete;
copy_only_pod(copy_only_pod&&) = delete;
copy_only_pod(const copy_only_pod&) = default;
copy_only_pod& operator=(const copy_only_pod&) = delete;
copy_only_pod& operator=(copy_only_pod&&) = delete;
};
copy_only_pod s{2, 14};
BOOST_TEST_EQ(tuple_size_v<copy_only_pod>, 2u);
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
struct with_reference {
int& i;
int* p;
};
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
struct with_nested_copy_only_pod {
int i;
copy_only_pod p;
};
BOOST_TEST_EQ(tuple_size_v<with_nested_copy_only_pod>, 2u);
with_nested_copy_only_pod np{2, {3, 4}};
BOOST_TEST_EQ(flat_get<0>(np), 2);
BOOST_TEST_EQ(flat_get<1>(np), 3);
BOOST_TEST_EQ(flat_get<2>(np), 4);
} // */
/* // TODO: think of something with it!
void test_move_only_pod() {
struct move_only_pod {
int i1;
short s1;
move_only_pod() = delete;
//move_only_pod(move_only_pod&&) = delete;
move_only_pod(const move_only_pod&) = delete;
move_only_pod(move_only_pod&&) = default;
move_only_pod& operator=(const move_only_pod&) = delete;
move_only_pod& operator=(move_only_pod&&) = delete;
};
move_only_pod s{2, 14};
BOOST_TEST_EQ(tuple_size_v<move_only_pod>, 2u);
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
struct with_reference {
int& i;
int* p;
};
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
struct with_nested_move_only_pod {
int i;
short s;
move_only_pod p;
char c;
};
BOOST_TEST_EQ(tuple_size_v<with_nested_move_only_pod>, 4u);
// with_nested_move_only_pod np{2, {3, 4}};
// BOOST_TEST_EQ(flat_get<0>(np), 2);
// BOOST_TEST_EQ(flat_get<1>(np), 3);
// BOOST_TEST_EQ(flat_get<2>(np), 4);
} // */
int main() {
test_compiletime<foo>();
test_compiletime_array<int>();
test_compiletime_array<void*>();
test_compiletime_array<const void*>();
test_compiletime_array<char>();
test_compiletime_array<char const volatile*>();
{
foo f {
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
, {18, 19}
, {20, 21, {22, 23}}
};
test_runtime(f);
}
{
foo f {
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
, {-18, -19}
, {656565, 65535, {-22, -23}}
};
test_runtime(f);
}
test_with_enums();
test_comparable_struct();
test_empty_struct();
test_pods_with_int_operators();
test_struct_with_single_field();
test_with_contatiners<flat_less<>>();
test_with_contatiners<flat_greater<>>();
test_print();
test_with_user_defined_constructor();
test_hash();
struct non_pod1 {
std::string s;
std::vector<int> v;
int i;
struct foo {
std::string s2;
} f;
};
static_assert(tuple_size<non_pod1>::value == 4, "Must not be a compile error");
struct non_pod2 {
unsigned ui1: 1;
unsigned ui2: 2;
std::string s;
std::vector<int> v;
int i;
struct foo {
std::string s2;
} f;
};
static_assert(tuple_size<non_pod2>::value == 6, "Must not be a compile error even with bitfields");
int i_2dimens[2][2] = {{10, 11}, {12, 13} };
static_assert(tuple_size<decltype(i_2dimens)>::value == 4, "");
static_assert(flat_tuple_size<decltype(i_2dimens)>::value == 4, "");
test_and_debug_internals(detail::make_index_sequence<6>{});
test_alignment_with_nested_structure();
another_test_with_unusual_alignment();
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
test_structure_with_default_values();
test_st_layout_structure_with_non_constexpr_type();
test_structure_with_user_provided_default_constructor();
#endif
//test_copy_only_pod();
//test_move_only_pod();
return boost::report_errors();
}

View File

@@ -0,0 +1,57 @@
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
struct point {
int x, y;
};
auto line(point a, point b) {
struct {
int timestamp;
point a, b;
} res = {123456, a, b};
return res;
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
int main() {
auto l = line({1, 2}, {3, 4});
int t, a, b, c, d;
using namespace boost::pfr;
using std::ignore;
flat_tie_from_structure (t, a, b, c, d) = l;
BOOST_TEST_EQ(t, 123456);
BOOST_TEST_EQ(a, 1);
BOOST_TEST_EQ(b, 2);
BOOST_TEST_EQ(c, 3);
BOOST_TEST_EQ(d, 4);
flat_tie_from_structure (ignore, ignore, a, b, c) = l;
BOOST_TEST_EQ(a, 2);
BOOST_TEST_EQ(b, 3);
BOOST_TEST_EQ(c, 4);
flat_tie_from_structure (ignore, a, b, c, ignore) = l;
BOOST_TEST_EQ(a, 1);
BOOST_TEST_EQ(b, 2);
BOOST_TEST_EQ(c, 3);
return boost::report_errors();
}
#else // C++14 without loophole
#include <iostream>
int main(int, char** argv) {
std::cerr << argv[0] << ": Not supported in C++14 without reflection loophole.\n";
}
#endif

View File

@@ -0,0 +1,28 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
int main() {
struct nested { int i; short data[3]; };
struct foo { int i; nested n; };
std::size_t sum = 0;
boost::pfr::flat_for_each_field(foo{1, {2, {3, 4, 5}}}, [&sum](auto v) {
sum += v;
});
BOOST_TEST_EQ(sum, 15u);
sum = 0;
int array[] = {0, 1, 0, 2, 3, 0, 4, 5};
boost::pfr::flat_for_each_field(array, [&sum](auto v) {
sum += v;
});
BOOST_TEST_EQ(sum, 15u);
return boost::report_errors();
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// requires: C++14
#include <iostream>
#include "boost/pfr.hpp"
struct my_struct { // no ostream operator defined!
int i;
char c;
double d;
};
int main() {
using namespace boost::pfr::flat_ops; // ostream operator out-of-the-box for all PODs!
my_struct s{100, 'H', 3.141593};
std::cout << "my_struct has " << boost::pfr::flat_tuple_size<my_struct>::value
<< " fields: " << s << "\n";
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include "boost/pfr.hpp"
struct my_struct { // no ostream operator defined!
std::string s;
int i;
};
int main() {
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
using namespace boost::pfr::flat_ops; // C++17 out-of-the-box ostream operators for aggregate initializables!
my_struct s{{"Das ist fantastisch!"}, 100};
std::cout << "my_struct has " << boost::pfr::flat_tuple_size<my_struct>::value
<< " fields: " << s << "\n";
#endif
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
int main() {
struct foo { int i; char c;};
static_assert(boost::pfr::flat_tuple_size_v<foo> == 2, "");
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
struct bf {
unsigned int i1: 1;
unsigned int i2: 1;
unsigned int i3: 1;
unsigned int i4: 1;
unsigned int i5: 1;
unsigned int i6: 1;
};
int main() {
(void)boost::pfr::flat_tuple_size<bf>::value; // Must be a compile time error
return boost::report_errors();
}

View File

@@ -0,0 +1,16 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <tuple>
int main() {
(void)boost::pfr::flat_tuple_size<std::pair<int, short>>::value; // Must be a compile time error
return boost::report_errors();
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/core/lightweight_test.hpp>
struct bf {
unsigned int i1: 1;
unsigned int i2: 1;
unsigned int i3: 1;
unsigned int i4: 1;
unsigned int i5: 1;
unsigned int i6: 1;
};
int main() {
(void)boost::pfr::tuple_size<bf>::value;
return boost::report_errors();
}

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/core/lightweight_test.hpp>
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
auto parseHex(char const* p, size_t limit = ~0u) {
struct { size_t val; char const* rest; } res = { 0, p };
while (limit) {
int v = *res.rest;
if (v >= '0' && v <= '9')
v = v - '0';
else if (v >= 'A' && v <= 'F')
v = 10 + v - 'A';
else if (v >= 'a' && v <= 'f')
v = 10 + v - 'a';
else
break;
res.val = (res.val << 4) + v;
--limit;
++res.rest;
}
return res;
}
auto parseLinePrefix(char const* line) {
struct {
size_t byteCount, address, recordType; char const* rest;
} res;
using namespace boost::pfr;
tie_from_structure (res.byteCount, line) = parseHex(line, 2);
tie_from_structure (res.address, line) = parseHex(line, 4);
tie_from_structure (res.recordType, line) = parseHex(line, 2);
res.rest = line;
return res;
}
int main() {
auto line = "0860E000616263646566000063";
auto meta = parseLinePrefix(line);
BOOST_TEST_EQ(meta.byteCount, 8);
BOOST_TEST_EQ(meta.address, 24800);
BOOST_TEST_EQ(meta.recordType, 0);
BOOST_TEST_EQ(meta.rest, line + 8);
size_t val;
using namespace boost::pfr;
tie_from_structure (val, std::ignore) = parseHex("a73b");
BOOST_TEST_EQ(val, 42811);
tie_from_structure (std::ignore, line) = parseHex(line, 8);
BOOST_TEST_EQ(line, meta.rest);
return boost::report_errors();
}
#else // C++14 without loophole
#include <iostream>
int main(int, char** argv) {
std::cerr << argv[0] << ": Not supported in C++14 without reflection loophole.\n";
}
#endif

View File

@@ -0,0 +1,101 @@
// Copyright (c) 2018 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Example from https://github.com/apolukhin/magic_get/issues/21
// boost::pfr::for_each_field crashes when sizeof(MyConfig) > 248 (probably >= 256)
#include <boost/pfr/precise.hpp>
#include <iostream>
#include <type_traits>
template <typename T>
class CfgAttrib {
public:
using value_type = T;
const char* getAttrName() const { return name; }
const T& getValue() const { return value; }
static constexpr std::true_type is_config_field{};
const char* const name;
T value;
//char dummy[8];
};
// a marker class for the code reflection
struct CfgSection {
const char* const name{ "UNNAMED" };
static constexpr std::false_type is_config_field{};
};
// a marker class for the code reflection
struct CfgSubSection {
const char* const name{ "UNNAMED" };
static constexpr std::false_type is_config_field{};
};
// all configuration data apart from audio and midi devices, which is handled by special juce support
// the class is supposed to be iterated with boost::pfr library.
// Thus its members must met the requirements (aggregate initializeable)
class MyConfig {
public:
// Configuration / Section Data fields
CfgSection sectionMain{ "section1" };
CfgAttrib<unsigned> attr1{ "attr1", 1 };
CfgSection section2{ "section2" };
CfgAttrib<unsigned> attr3{ "attr3", 13 };
CfgAttrib<unsigned> attr4{ "attr4", 2};
CfgAttrib<unsigned> attr5{ "attr5", 0 };
CfgAttrib<unsigned> attr6{ "attr6", 6 };
CfgSection section3{ "section3" };
CfgAttrib<long long int> attr7{ "attr7", 0 };
CfgSection section4{ "section4" };
CfgAttrib<long long int> attr8{ "attr8", 0 };
CfgAttrib<long long int> attr9{ "attr9", 0 };
CfgAttrib<long long int> attr10{ "attr10", 0 };
CfgSection section5{ "section5" };
CfgAttrib<long long int> attr11{ "attr11", 0 };
CfgSection section666{ "section666" };
CfgAttrib<long long int> attr12{ "attr12", 0 };
CfgAttrib<unsigned> attr13{ "attr13", 0 };
};
template <class T>
void printer(const T& value, std::true_type) {
std::cout << "- " << value.getAttrName() << ": " << value.getValue() << std::ends;
}
template <class T>
void printer(const T& value, std::false_type) {
std::cout << "Section \"" << value.name << "\":" << std::ends;
}
int main() {
std::cout << "sizeof(MyConfig) = " << sizeof(MyConfig) << std::ends;
MyConfig aCfg;
boost::pfr::for_each_field(aCfg, [](auto& value) {
printer(value, value.is_config_field);
});
#if BOOST_PFR_USE_CPP17
boost::pfr::get<0>(aCfg); // also C1202
#endif
}

View File

@@ -0,0 +1,113 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <sstream>
// Test case was inspired by Bruno Dutra. Thanks!
enum class color {
red,
green,
blue
};
std::ostream& operator <<(std::ostream& os, color c) {
switch(c) {
case color::red:
os << "red";
break;
case color::green:
os << "green";
break;
case color::blue:
os << "blue";
break;
};
return os;
}
struct my_constexpr {
constexpr my_constexpr() {}
};
std::ostream& operator <<(std::ostream& os, my_constexpr) {
return os << "{}";
}
struct reg {
const int a;
char b;
const my_constexpr d;
const color f;
const char* g;
};
struct simple {
int a;
char b;
short d;
};
int main () {
std::size_t control = 0;
int v = {};
boost::pfr::for_each_field(v, [&control](auto&& val, std::size_t i) {
BOOST_TEST_EQ(i, control);
(void)val;
++ control;
});
BOOST_TEST_EQ(control, 1);
control = 0;
int array[10] = {};
boost::pfr::for_each_field(array, [&control](auto&& val, std::size_t i) {
BOOST_TEST_EQ(i, control);
(void)val;
++ control;
});
BOOST_TEST_EQ(control, 10);
std::stringstream ss;
boost::pfr::for_each_field(reg{42, 'a', {}, color::green, "hello world!"}, [&ss](auto&& val, std::size_t i) {
if (i) {
ss << ", ";
}
ss << val;
});
BOOST_TEST_EQ(std::string("42, a, {}, green, hello world!"), ss.str());
ss.str("");
control = 0;
boost::pfr::for_each_field(reg{42, 'a', {}, color::green, "hello world!"}, [&ss, &control](auto&& val, auto i) {
if (!!decltype(i)::value) {
ss << ", ";
}
BOOST_TEST_EQ(decltype(i)::value, control);
++ control;
ss << val;
});
BOOST_TEST_EQ(std::string("42, a, {}, green, hello world!"), ss.str());
ss.str("");
boost::pfr::for_each_field(reg{42, 'a', {}, color::green, "hello world!"}, [&ss](auto&& val) {
ss << val << ' ';
});
BOOST_TEST_EQ(std::string("42 a {} green hello world! "), ss.str());
ss.str("");
std::cout << '\n';
boost::pfr::for_each_field(simple{42, 'a', 3}, [&ss](auto&& val) {
ss << val << ' ';
});
BOOST_TEST_EQ("42 a 3 ", ss.str());
return boost::report_errors();
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2018 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/precise.hpp>
#include <boost/core/lightweight_test.hpp>
template <class T>
struct non_default_constructible {
T val_;
non_default_constructible() = delete;
template <class U> non_default_constructible(U&& /*v*/){}
};
struct Foo {
non_default_constructible<int> a;
};
int main() {
#if BOOST_PFR_USE_LOOPHOLE || BOOST_PFR_USE_CPP17
Foo f{0};
f.a.val_ = 5;
BOOST_TEST_EQ(boost::pfr::get<0>(f).val_, 5);
return boost::report_errors();
#endif
}

31
test/precise/issue30.cpp Normal file
View File

@@ -0,0 +1,31 @@
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Test case for https://github.com/apolukhin/magic_get/issues/30
#include <memory>
#include <boost/pfr.hpp>
#include <boost/core/lightweight_test.hpp>
struct Message {
std::unique_ptr<int> data;
};
struct Message2 {
std::unique_ptr<int> data41 = std::make_unique<int>(41);
std::unique_ptr<int> data42 = std::make_unique<int>(42);
};
int main() {
Message message;
auto& ptr = boost::pfr::get<0>(message);
BOOST_TEST(ptr == nullptr);
Message2 message2;
auto& ptr2 = boost::pfr::get<1>(message2);
BOOST_TEST_EQ(*ptr2, 42);
return boost::report_errors();
}

26
test/precise/issue33.cpp Normal file
View File

@@ -0,0 +1,26 @@
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Test case for https://github.com/apolukhin/magic_get/issues/33
#include <iostream>
#include <vector>
#include <boost/pfr.hpp>
#include <boost/core/lightweight_test.hpp>
struct TestStruct {
std::vector<std::unique_ptr<int>> vec;
};
int main() {
TestStruct temp;
temp.vec.emplace_back();
boost::pfr::for_each_field(temp, [](const auto& value) {
BOOST_TEST_EQ(value.size(), 1);
});
return boost::report_errors();
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// requires: C++14
#include <iostream>
#include "boost/pfr/precise.hpp"
struct my_struct { // no ostream operator defined!
int i;
char c;
double d;
};
int main() {
using namespace boost::pfr::ops; // out-of-the-box ostream operator for all PODs!
my_struct s{100, 'H', 3.141593};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include <string>
#include "boost/pfr/precise.hpp"
struct some_person {
std::string name;
unsigned birth_year;
};
int main() {
#if BOOST_PFR_USE_LOOPHOLE || BOOST_PFR_USE_CPP17
some_person val{"Edgar Allan Poe", 1809};
std::cout << boost::pfr::get<0>(val)
<< " was born in " << boost::pfr::get<1>(val);
#endif
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include "boost/pfr/precise.hpp"
struct my_struct { // no ostream operator defined!
std::string s;
int i;
};
int main() {
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
using namespace boost::pfr::ops; // C++17 out-of-the-box ostream operators for aggregate initializables!
my_struct s{{"Das ist fantastisch!"}, 100};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
#endif
}

View File

@@ -0,0 +1,16 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <tuple>
int main() {
(void)boost::pfr::tuple_size<std::pair<int, short>>::value; // Must be a compile time error
return boost::report_errors();
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2018 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/precise.hpp>
#include <boost/core/lightweight_test.hpp>
template <class T>
struct optional_like {
T val_;
optional_like() = default;
template <class U> optional_like(U&& /*v*/){}
};
struct Foo {
optional_like<int> a;
};
int main() {
#if BOOST_PFR_USE_LOOPHOLE || BOOST_PFR_USE_CPP17
Foo f{0};
f.a.val_ = 5;
BOOST_TEST_EQ(boost::pfr::get<0>(f).val_, 5);
return boost::report_errors();
#endif
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2019-2020 Antony Polukhin.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <type_traits>
#include <boost/pfr/precise/core.hpp>
template <class T>
struct constrained_template {
constrained_template() = default;
template <
class U = T,
std::enable_if_t<
std::is_constructible<T, U&&>::value
|| sizeof(decltype(T{std::declval<U&&>()}))
, bool> = false>
constexpr constrained_template(U&& val)
: value_{std::forward<U>(val)}
{}
T value_;
};
struct int_element {
int value_;
};
struct aggregate_constrained {
constrained_template<short> a;
constrained_template<int_element> b;
};
int main() {
static_assert(
std::is_same<
boost::pfr::tuple_element_t<0, aggregate_constrained>,
constrained_template<short>
>::value,
"Precise reflection with template constructors fails to work"
);
static_assert(
std::is_same<
boost::pfr::tuple_element_t<1, aggregate_constrained>,
constrained_template<int_element>
>::value,
"Precise reflection with template constructors fails to work"
);
short s = 3;
aggregate_constrained aggr{s, 4};
return boost::pfr::get<1>(aggr).value_.value_ - 4;
}

View File

@@ -0,0 +1,82 @@
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <type_traits>
#include <boost/pfr/precise/core.hpp>
//#include <boost/multiprecision/cpp_dec_float.hpp>
//const int kPrecision = 18;
//using Numeric = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<kPrecision>>;
template <class T>
struct unconstrained_template {
unconstrained_template() = default;
unconstrained_template(const unconstrained_template&) = default;
unconstrained_template(unconstrained_template&&) = default;
template <class U>
constexpr unconstrained_template(const U& val)
: value_{val}
{}
T value_{};
};
struct int_element {
int value_;
};
struct aggregate_unconstrained {
unconstrained_template<int> a;
unconstrained_template<int_element> b;
// Numeric c;
};
// TODO: WIP
int main() {
using sanity = decltype(aggregate_unconstrained{
boost::pfr::detail::ubiq_lref_constructor{0},
boost::pfr::detail::ubiq_lref_constructor{1},
});
static_assert(
std::is_same<
sanity, aggregate_unconstrained
>::value,
"Precise reflection with template constructors sanity check fails"
);
boost::pfr::detail::enable_if_constructible_helper_t<aggregate_unconstrained, 2> foo;
static_assert(
std::is_same<
boost::pfr::tuple_element_t<0, aggregate_unconstrained>,
unconstrained_template<int>
>::value,
"Precise reflection with template constructors fails to work"
);
static_assert(
std::is_same<
boost::pfr::tuple_element_t<1, aggregate_unconstrained>,
unconstrained_template<int_element>
>::value,
"Precise reflection with template constructors fails to work"
);
/*
static_assert(
std::is_same<
boost::pfr::tuple_element_t<2, aggregate_unconstrained>,
Numeric
>::value,
"Precise reflection with template constructors fails to work"
);
*/
aggregate_unconstrained aggr{3, 4};
return boost::pfr::get<1>(aggr).value_.value_ - 4;
}

View File

@@ -0,0 +1,94 @@
// Copyright (c) 2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <boost/pfr/precise/ops.hpp>
#include <string>
#if defined(__has_include)
# if __has_include(<optional>)
# include <optional>
# endif
#endif
namespace some {
struct struct1{ int i; };
struct struct2{ int i; };
}
namespace testing {
namespace {
#ifdef __cpp_lib_optional
struct anon_with_optional {
std::string a;
std::optional<some::struct1> b;
std::optional<some::struct2> c;
};
struct other_anon_with_optional {
std::string a;
int b;
std::optional<anon_with_optional> c;
std::optional<some::struct2> d;
};
#endif
struct other_anon {
int data;
};
struct anon {
other_anon a;
other_anon b;
};
void test_in_anon_ns() {
anon x{{1}, {2}};
auto v = boost::pfr::structure_tie(x);
BOOST_TEST_EQ(std::get<0>(v).data, 1);
BOOST_TEST_EQ(std::get<1>(v).data, 2);
#ifdef __cpp_lib_optional
other_anon_with_optional opt{"test", {}, {}, {}};
auto opt_val = boost::pfr::structure_tie(opt);
BOOST_TEST_EQ(std::get<0>(opt_val), "test");
#endif
}
} // anonymous namespace
void test_in_non_non_ns() {
anon x{{1}, {2}};
auto v = boost::pfr::structure_tie(x);
BOOST_TEST_EQ(std::get<0>(v).data, 1);
BOOST_TEST_EQ(std::get<1>(v).data, 2);
#ifdef __cpp_lib_optional
other_anon_with_optional opt{"test again", {}, {}, {}};
auto opt_val = boost::pfr::structure_tie(opt);
BOOST_TEST_EQ(std::get<0>(opt_val), "test again");
#endif
}
} // namespace testing
int main() {
testing::test_in_anon_ns();
testing::test_in_non_non_ns();
return boost::report_errors();
}

View File

@@ -0,0 +1,16 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
int main() {
struct nested { int i; char data[20]; };
struct foo { int i; char c; nested n; };
static_assert(boost::pfr::tuple_size_v<foo> == 3, "");
struct with_reference { int& i; char data; };
static_assert(boost::pfr::tuple_size_v<with_reference> == 2, "");
}