mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
398 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3daf98c9e9 | ||
|
|
a5f84b38a6 | ||
|
|
e88e44cc14 | ||
|
|
f28952c544 | ||
|
|
eb37b11dfc | ||
|
|
2719abe88c | ||
|
|
01af26370f | ||
|
|
eb7a7a2d92 | ||
|
|
33b5003883 | ||
|
|
99f5037a00 | ||
|
|
e15cb59f76 | ||
|
|
8fd5392b3b | ||
|
|
1a6ff4cf77 | ||
|
|
57cb27a5ca | ||
|
|
812f3f62f3 | ||
|
|
9c6f5fd2c0 | ||
|
|
2568ef5fe6 | ||
|
|
ed4505ca05 | ||
|
|
8c4934c17d | ||
|
|
00643f5aff | ||
|
|
5a1cc330b9 | ||
|
|
43c671a2ee | ||
|
|
890d352327 | ||
|
|
affa1ec6c0 | ||
|
|
cef16a47a5 | ||
|
|
d797b30d3b | ||
|
|
1245236d16 | ||
|
|
6168a1e000 | ||
|
|
43014fd9f5 | ||
|
|
10816795e7 | ||
|
|
57d8482245 | ||
|
|
fe326ac9e4 | ||
|
|
3582a4597f | ||
|
|
3b369d6303 | ||
|
|
d2ac7325bd | ||
|
|
dfb3771e4f | ||
|
|
4fe0615262 | ||
|
|
020b855686 | ||
|
|
642937c7f4 | ||
|
|
4ec21adbab | ||
|
|
5daf55c5e2 | ||
|
|
8d26298e0a | ||
|
|
4d89b42a66 | ||
|
|
f40d2f773a | ||
|
|
759b84d7cc | ||
|
|
4f52ff8516 | ||
|
|
11dc14e61b | ||
|
|
77110ea65f | ||
|
|
2ae179cc00 | ||
|
|
5713fa0aa7 | ||
|
|
7fe5f9b9b4 | ||
|
|
2331a3bc6b | ||
|
|
af4120c5fd | ||
|
|
44c3ae3969 | ||
|
|
0acdbfc7a5 | ||
|
|
fa119761f6 | ||
|
|
1d64f96a1e | ||
|
|
59357a7cb5 | ||
|
|
7bff3ec9f2 | ||
|
|
77e714c79d | ||
|
|
655662b3e2 | ||
|
|
dd0d53eded | ||
|
|
c32fb3271f | ||
|
|
1365e2779b | ||
|
|
ea068caf14 | ||
|
|
a16d99b7f1 | ||
|
|
b56e45f277 | ||
|
|
19c4eead83 | ||
|
|
03afd0b83c | ||
|
|
aeaa6698e5 | ||
|
|
5c94e55195 | ||
|
|
467f3c1db1 | ||
|
|
2c23291231 | ||
|
|
00e45d8b9c | ||
|
|
e0b40b15bd | ||
|
|
5b53815408 | ||
|
|
98bf98e0a4 | ||
|
|
21f08e5654 | ||
|
|
9d831ab09f | ||
|
|
50d58a2e84 | ||
|
|
76ac44a9ca | ||
|
|
4205a2e553 | ||
|
|
89b1d45ff7 | ||
|
|
26867f47b7 | ||
|
|
b9166fd38e | ||
|
|
915bd9217c | ||
|
|
0885412a7d | ||
|
|
86ebac6e0c | ||
|
|
39e9b4c5fe | ||
|
|
01fd8db5b4 | ||
|
|
077ea5451c | ||
|
|
3a36467d96 | ||
|
|
3eee880972 | ||
|
|
41a22fcd21 | ||
|
|
e354ba8b25 | ||
|
|
7a0f5f90df | ||
|
|
041b0dd226 | ||
|
|
ff1c5e3a7f | ||
|
|
4c48a220c2 | ||
|
|
ed6fe1431d | ||
|
|
16db439e8c | ||
|
|
c3ccb7a525 | ||
|
|
d6e44dde8f | ||
|
|
63b5f1f791 | ||
|
|
dc814c7e7f | ||
|
|
671cc3f282 | ||
|
|
8ca6b531a6 | ||
|
|
f24698f131 | ||
|
|
950e4aa0ee | ||
|
|
b9bea47e4f | ||
|
|
6d1fc03667 | ||
|
|
ba65dd23ef | ||
|
|
5b28535b8e | ||
|
|
802c7033ba | ||
|
|
4a593c0628 | ||
|
|
b603f6fdef | ||
|
|
1a620d36dd | ||
|
|
93cb89cf05 | ||
|
|
d2964544a4 | ||
|
|
74c460fd18 | ||
|
|
abb467c0e2 | ||
|
|
a22f9bd5ec | ||
|
|
b53c54688f | ||
|
|
aeaca7ece5 | ||
|
|
a651c13c19 | ||
|
|
eca39f2c5f | ||
|
|
74a62a24af | ||
|
|
8f5aaf41ce | ||
|
|
ff778d5430 | ||
|
|
449d6769a2 | ||
|
|
72df78ad28 | ||
|
|
f4ce2d25f1 | ||
|
|
82658caf7c | ||
|
|
d9ade9ca8d | ||
|
|
c7ea287362 | ||
|
|
48180bd6bf | ||
|
|
f64ee68961 | ||
|
|
eac7e089cf | ||
|
|
07e155aa53 | ||
|
|
2b75edf571 | ||
|
|
6c576cd436 | ||
|
|
72e218fb2e | ||
|
|
e2e6a2d13f | ||
|
|
e1e74817ee | ||
|
|
291ca069ca | ||
|
|
68d04a99a7 | ||
|
|
8a1471a387 | ||
|
|
d84cd84c34 | ||
|
|
259cc9470f | ||
|
|
c2adec8743 | ||
|
|
afa3cc8483 | ||
|
|
556e3f479a | ||
|
|
ceb9e352b0 | ||
|
|
447bfcc3c3 | ||
|
|
6f35c872c8 | ||
|
|
6b03224636 | ||
|
|
8e9ac75fd7 | ||
|
|
e993693cb4 | ||
|
|
8bb5eb2f33 | ||
|
|
129d8d9471 | ||
|
|
9520aa703f | ||
|
|
dd556977c0 | ||
|
|
7e299067eb | ||
|
|
f7df20f4f8 | ||
|
|
7f506ece26 | ||
|
|
eebc3241e1 | ||
|
|
38cfc1dbbd | ||
|
|
cf3094e63e | ||
|
|
c4b5538024 | ||
|
|
aa663303ed | ||
|
|
d665911f2c | ||
|
|
46d2f2f91b | ||
|
|
aaa47e7858 | ||
|
|
1f463688ea | ||
|
|
5bcbfa810d | ||
|
|
5365521f8f | ||
|
|
3229e76d48 | ||
|
|
eaf13a38ca | ||
|
|
f026cc6c8a | ||
|
|
f486a148b4 | ||
|
|
f0d9551a01 | ||
|
|
158f3e779c | ||
|
|
3630668c2d | ||
|
|
7ee6c785d8 | ||
|
|
606e6c34b2 | ||
|
|
9ab62bf32e | ||
|
|
a9b25ef1c3 | ||
|
|
40ade16430 | ||
|
|
354f9f00d5 | ||
|
|
4a9452318c | ||
|
|
e2f9f0df5c | ||
|
|
2921e8a1a9 | ||
|
|
953bdc9bf9 | ||
|
|
88c65b3af3 | ||
|
|
3e46450ee1 | ||
|
|
d1ee7629c9 | ||
|
|
6bfa69b15d | ||
|
|
6d8caf8ca7 | ||
|
|
cf30a51da4 | ||
|
|
6052d93b75 | ||
|
|
757b02f7c6 | ||
|
|
4ce90db718 | ||
|
|
15549e642b | ||
|
|
79d87e37f4 | ||
|
|
068f98346a | ||
|
|
1b49ad3791 | ||
|
|
c5130dd9e5 | ||
|
|
6304fc6b29 | ||
|
|
5439885958 | ||
|
|
437308871b | ||
|
|
5b79f61e07 | ||
|
|
0f9edaf9ad | ||
|
|
2169841e68 | ||
|
|
d8cb24b660 | ||
|
|
09266c929c | ||
|
|
42f707b388 | ||
|
|
793842e94e | ||
|
|
c53f623d4d | ||
|
|
89d41cb599 | ||
|
|
bcc2101fa0 | ||
|
|
060437a01d | ||
|
|
8470938009 | ||
|
|
86c9934c40 | ||
|
|
b0229248de | ||
|
|
7d4a705f74 | ||
|
|
7a098eea97 | ||
|
|
e27bb2a979 | ||
|
|
aec668962d | ||
|
|
8efe184b7a | ||
|
|
4ca855fdbb | ||
|
|
ee7a716b6d | ||
|
|
d36729a3ad | ||
|
|
4a6d8d10c7 | ||
|
|
cb12e9a05d | ||
|
|
ea47144b60 | ||
|
|
e7abff68f6 | ||
|
|
8b575abe43 | ||
|
|
d9735b867c | ||
|
|
a229d560ee | ||
|
|
a11ff11ab4 | ||
|
|
250d5011f4 | ||
|
|
30d65a2ad4 | ||
|
|
2007f2f339 | ||
|
|
1bdc6cae9b | ||
|
|
72b69d3288 | ||
|
|
8031f575fe | ||
|
|
999e7d8619 | ||
|
|
b8f5ddd70f | ||
|
|
f686c9a77e | ||
|
|
6a5a04de55 | ||
|
|
372f72a9fd | ||
|
|
a9e5e73c30 | ||
|
|
0c0332fe97 | ||
|
|
ab5140df52 | ||
|
|
d487496605 | ||
|
|
52b7f8f83a | ||
|
|
d7cfbef235 | ||
|
|
c48df9ba12 | ||
|
|
12f8e1baa1 | ||
|
|
1b138a4bd7 | ||
|
|
623e0ec093 | ||
|
|
5770f67671 | ||
|
|
6814449a82 | ||
|
|
f91d809fc0 | ||
|
|
41d73e45d4 | ||
|
|
d37163cc98 | ||
|
|
29ab2524aa | ||
|
|
96b7c38666 | ||
|
|
a9b952cdb8 | ||
|
|
f75fa56076 | ||
|
|
af8be96595 | ||
|
|
3aba48c9a9 | ||
|
|
62b972e500 | ||
|
|
6844dcb48f | ||
|
|
2a6a4752b8 | ||
|
|
f0dfa5ed4e | ||
|
|
6cab0a9684 | ||
|
|
c03977e29f | ||
|
|
49ae43f99f | ||
|
|
551b36a536 | ||
|
|
1bf21ae5b9 | ||
|
|
b67893d92e | ||
|
|
14d59f5340 | ||
|
|
28a787a6a8 | ||
|
|
3d8b5c33e6 | ||
|
|
0cf44d634e | ||
|
|
79a7a1b25d | ||
|
|
a6d655e064 | ||
|
|
7b0939289f | ||
|
|
2a28aacc17 | ||
|
|
982cb04375 | ||
|
|
5262e209e4 | ||
|
|
1bdd543304 | ||
|
|
b0f042d1d8 | ||
|
|
1dfcc666c1 | ||
|
|
78251885b4 | ||
|
|
efd11f441f | ||
|
|
b7d7abd65d | ||
|
|
62a9e5b758 | ||
|
|
33ec908c44 | ||
|
|
f788912a71 | ||
|
|
34fd387877 | ||
|
|
2c24e038d0 | ||
|
|
04f2714475 | ||
|
|
191184a422 | ||
|
|
bea67d5078 | ||
|
|
afc6fe1272 | ||
|
|
7992256108 | ||
|
|
fd68ea93ee | ||
|
|
3eda0d10c6 | ||
|
|
2f3c46dd9d | ||
|
|
7d422edf85 | ||
|
|
b4f147722e | ||
|
|
afd995e5dd | ||
|
|
6ea565dd6d | ||
|
|
7532ba8ba1 | ||
|
|
cfee20e36f | ||
|
|
459a25f817 | ||
|
|
9bca907657 | ||
|
|
af0a937126 | ||
|
|
63a41e0256 | ||
|
|
bc849f583e | ||
|
|
32b682261d | ||
|
|
d6d1082157 | ||
|
|
0147c60f1e | ||
|
|
88f7ad3902 | ||
|
|
2d289f6b28 | ||
|
|
fb04223e5e | ||
|
|
1314722a22 | ||
|
|
cb876b55a8 | ||
|
|
e815460aed | ||
|
|
26fffe6ff0 | ||
|
|
e353fd63f2 | ||
|
|
a277cdac19 | ||
|
|
48b86158f0 | ||
|
|
8e0f27baee | ||
|
|
9c88c56cb3 | ||
|
|
c110bdf0e6 | ||
|
|
5ae2e2fd5f | ||
|
|
7c252b4ca5 | ||
|
|
a144d044df | ||
|
|
558734e7f8 | ||
|
|
940cb1507f | ||
|
|
378acb1fe9 | ||
|
|
c9bc21ed9c | ||
|
|
d6687e5d18 | ||
|
|
b0347fb617 | ||
|
|
ac034a6ef7 | ||
|
|
138a7aff2e | ||
|
|
12940c6ed9 | ||
|
|
282094999e | ||
|
|
72c831cb1a | ||
|
|
3dad4f6271 | ||
|
|
46ca2b70b2 | ||
|
|
558a49daee | ||
|
|
fd381c5dd4 | ||
|
|
313d667664 | ||
|
|
4c2f7fbce4 | ||
|
|
f4126ca464 | ||
|
|
217b4f9d50 | ||
|
|
b5dea7e0c4 | ||
|
|
79a79332ae | ||
|
|
16e28d3c3c | ||
|
|
452e01ff0b | ||
|
|
9fbb780839 | ||
|
|
494a9cf6ca | ||
|
|
67b1b5c06a | ||
|
|
212efb1be0 | ||
|
|
135faf692d | ||
|
|
9ecedfe6ca | ||
|
|
27cd2d78e3 | ||
|
|
7d9dec3b44 | ||
|
|
2751725148 | ||
|
|
4211404f20 | ||
|
|
6ef486f0b7 | ||
|
|
2ca4142e93 | ||
|
|
c9bb66911a | ||
|
|
1b0ae91a52 | ||
|
|
74a1bb1eac | ||
|
|
b9987c70ab | ||
|
|
54f82e9482 | ||
|
|
3ee92b6a14 | ||
|
|
a83f1043f3 | ||
|
|
1405b1ab64 | ||
|
|
2854894a74 | ||
|
|
d78d300380 | ||
|
|
2284d6f703 | ||
|
|
dc585f67fd | ||
|
|
ebd3750681 | ||
|
|
9fb1071862 | ||
|
|
f058b9b771 | ||
|
|
96b0c9b7d7 | ||
|
|
620f9f4f80 | ||
|
|
36d22fe4de | ||
|
|
efe421e982 | ||
|
|
db967a38a8 | ||
|
|
11aa87e21f | ||
|
|
99e3c623f4 |
97
.gitattributes
vendored
Normal file
97
.gitattributes
vendored
Normal 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
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
doc/autodoc*
|
||||
doc/html
|
||||
178
.travis.yml
178
.travis.yml
@@ -2,44 +2,176 @@
|
||||
# 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 and use the folder for tests. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_LIBS_FOLDER=$(basename $TRAVIS_BUILD_DIR)
|
||||
# This will force to use local repo content, instead of the Boost's default.
|
||||
- BOOST_LIBS_FOLDER=pfr #$(basename $TRAVIS_BUILD_DIR)
|
||||
|
||||
# Global options for sanitizers
|
||||
- UBSAN_OPTIONS=print_stacktrace=1
|
||||
- LSAN_OPTIONS=verbosity=1:log_threads=1
|
||||
|
||||
# Cloning minimal set of Boost libraries
|
||||
- BOOST=$HOME/boost-local
|
||||
- echo "Testing $BOOST_LIBS_FOLDER, to remove $BOOST/libs/$BOOST_LIBS_FOLDER, testing branch $BOOST_BRANCH"
|
||||
- git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git $BOOST
|
||||
- cd $BOOST
|
||||
- git submodule update --init --depth 10 tools/build tools/boostdep
|
||||
|
||||
# Replacing Boost module with this project and installing Boost dependencies
|
||||
- rm -rf $BOOST/libs/$BOOST_LIBS_FOLDER
|
||||
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$BOOST_LIBS_FOLDER
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$BOOST_LIBS_FOLDER
|
||||
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" -I example -I examples $(basename $TRAVIS_BUILD_DIR)
|
||||
- git status
|
||||
|
||||
# Adding missing toolsets and preparing Boost headers
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
- |-
|
||||
echo "using gcc ;" >> ~/user-config.jam
|
||||
echo "using clang ;" >> ~/user-config.jam
|
||||
echo "using clang : 3.8 : clang++-3.8 ;" >> ~/user-config.jam
|
||||
echo "using clang : 4 : clang++-4.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 5 : clang++-5.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 6 : clang++-6.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 7 : clang++-7.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 8 : clang++-8 ;" >> ~/user-config.jam
|
||||
echo "using clang : 10 : clang++-10 ;" >> ~/user-config.jam
|
||||
echo "using clang : libc++ : clang++-libc++ ;" >> ~/user-config.jam
|
||||
- cd $BOOST/libs/$BOOST_LIBS_FOLDER/test/
|
||||
|
||||
script:
|
||||
# `--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"
|
||||
|
||||
# Preparing Coveralls data by changind data format to a readable one
|
||||
- echo "$LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info"
|
||||
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing /test/ /example/ folder data
|
||||
- cd $BOOST
|
||||
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$BOOST_LIBS_FOLDER/test/*" $IGNORE_COVERAGE "*/$BOOST_LIBS_FOLDER/tests/*" "*/$BOOST_LIBS_FOLDER/examples/*" "*/$BOOST_LIBS_FOLDER/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing data that is not related to this project directly
|
||||
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$BOOST_LIBS_FOLDER\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
- echo $OTHER_LIBS
|
||||
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
|
||||
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
23
LICENSE_1_0.txt
Normal file
23
LICENSE_1_0.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
200
README.md
200
README.md
@@ -1,170 +1,100 @@
|
||||
#Magic Get [](https://travis-ci.org/apolukhin/magic_get)
|
||||
# Boost.PFR
|
||||
|
||||
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 is a C++14 library for very basic reflection that gives you access to structure elements by index and provides other `std::tuple` like methods for user defined types without any macro or boilerplate code.
|
||||
|
||||
|
||||
### Motivating example
|
||||
[Latest documentation](http://apolukhin.github.com/magic_get/index.html)
|
||||
|
||||
### Test results
|
||||
|
||||
Branches | Build | Tests coverage | More info
|
||||
----------------|-------------- | -------------- |-----------
|
||||
Develop: | [](https://travis-ci.org/apolukhin/magic_get) [](https://ci.appveyor.com/project/apolukhin/magic-get/branch/develop) | [](https://coveralls.io/github/apolukhin/magic_get?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/pfr.html)
|
||||
Master: | [](https://travis-ci.org/apolukhin/magic_get) [](https://ci.appveyor.com/project/apolukhin/magic-get/branch/master) | [](https://coveralls.io/github/apolukhin/magic_get?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/pfr.html)
|
||||
|
||||
### Motivating Example #0
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include "magic_get.hpp"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
struct my_struct {
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
struct some_person {
|
||||
std::string name;
|
||||
unsigned birth_year;
|
||||
};
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
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!
|
||||
|
||||
if (argc > 1) {
|
||||
std::ofstream ofs(argv[1]);
|
||||
ofs << boost::pfr::io(val); // File now contains: {"Edgar Allan Poe", 1809}
|
||||
}
|
||||
}
|
||||
```
|
||||
Outputs:
|
||||
```
|
||||
Edgar Allan Poe was born in 1809
|
||||
```
|
||||
|
||||
|
||||
### Motivating Example #1
|
||||
```c++
|
||||
#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";
|
||||
my_struct s{100, 'H', 3.141593};
|
||||
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
|
||||
<< " fields: " << boost::pfr::io(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; };
|
||||
#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() {
|
||||
my_struct s{{"Das ist fantastisch!"}, 100};
|
||||
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
|
||||
<< " fields: " << boost::pfr::io(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
|
||||
* Static variables are ignored
|
||||
[See docs](http://apolukhin.github.com/magic_get/index.html).
|
||||
|
||||
### License
|
||||
|
||||
|
||||
69
doc/Jamfile.v2
Normal file
69
doc/Jamfile.v2
Normal file
@@ -0,0 +1,69 @@
|
||||
# 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= \\
|
||||
\"forcedlink{1}=\\xmlonly<link linkend='boost.pfr.\\1'>\\endxmlonly boost::pfr::\\1\\xmlonly</link>\\endxmlonly\" \\
|
||||
\"podops=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.three_ways_of_getting_operators'>\\endxmlonly 'Three ways of getting operators' \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"customio=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.custom_printing_of_aggregates'>\\endxmlonly 'Custom printing of aggregates' \\xmlonly</link>\\endxmlonly for info on how to implement your own manipulator with custom format.\" \\
|
||||
\"aggregate=\\xmlonly<link linkend='boost_pfr.limitations_and_configuration'>\\endxmlonly simple aggregate \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"BOOST_PFR_DOXYGEN_INVOKED\" \\
|
||||
"
|
||||
;
|
||||
|
||||
doxygen autodoc_pfr
|
||||
:
|
||||
[ glob ../../../boost/pfr.hpp ]
|
||||
[ glob ../../../boost/pfr/*.hpp ]
|
||||
:
|
||||
$(doxygen_params)
|
||||
<xsl:param>"boost.doxygen.reftitle=Reference Section"
|
||||
;
|
||||
|
||||
boostbook pfr-doc
|
||||
:
|
||||
pfr.qbk
|
||||
:
|
||||
<dependency>autodoc_pfr
|
||||
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_72_0
|
||||
#<xsl:param>boost.root=../../../.
|
||||
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: pfr-doc/<format>docbook
|
||||
:
|
||||
:
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
|
||||
530
doc/pfr.qbk
Normal file
530
doc/pfr.qbk
Normal file
@@ -0,0 +1,530 @@
|
||||
[library Boost.PFR
|
||||
[quickbook 1.6]
|
||||
[version 2.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 Intro]
|
||||
|
||||
Boost.PFR is a C++14 library for a very basic reflection. It gives you access to structure elements by index and provides other `std::tuple` like methods for user defined types without macro or boilerplate code:
|
||||
|
||||
[import ../example/motivating_example0.cpp]
|
||||
[pfr_motivating_example]
|
||||
|
||||
See [link boost_pfr.limitations_and_configuration [*limitations]].
|
||||
|
||||
|
||||
[h2 Usecase example]
|
||||
|
||||
Imagine that you are writing the wrapper library for a database. Depending on the usage of Boost.PFR users code will look differently:
|
||||
|
||||
[table:hand_made_vs_pfr_1
|
||||
[[ Without Boost.PFR ] [ With Boost.PFR ]]
|
||||
[[
|
||||
```
|
||||
#include <db/api.hpp>
|
||||
|
||||
struct user_info {
|
||||
std::int64_t id;
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
user_info retrieve_friend(std::string_view name) {
|
||||
std::tuple info_tuple
|
||||
= db::one_row_as<std::int64_t, std::string, std::string, std::string>(
|
||||
"SELECT id, name, email, login FROM user_infos WHERE name=$0",
|
||||
name
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
user_info info {
|
||||
std::move(std::get<0>(info_tuple)),
|
||||
std::move(std::get<1>(info_tuple)),
|
||||
std::move(std::get<2>(info_tuple)),
|
||||
std::move(std::get<3>(info_tuple)),
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto friend_info = ask_user_for_friend(std::move(info));
|
||||
|
||||
db::insert(
|
||||
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
|
||||
std::move(friend_info.id), //////////////////////////////////////////////
|
||||
std::move(friend_info.name), // Users are forced to move individual fields
|
||||
std::move(friend_info.email), // because your library can not iterate over
|
||||
std::move(friend_info.login) // the fields of a user provided structure
|
||||
);
|
||||
|
||||
return friend_info;
|
||||
}
|
||||
```
|
||||
][
|
||||
```
|
||||
#include <db/api.hpp>
|
||||
|
||||
struct user_info {
|
||||
std::int64_t id;
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
user_info retrieve_friend(std::string_view name) {
|
||||
// With Boost.PFR you can put data directly into user provided structures
|
||||
user_info info = db::one_row_as<user_info>(
|
||||
"SELECT id, name, email, login FROM user_infos WHERE name=$0",
|
||||
name
|
||||
);
|
||||
|
||||
////////////////// No boilerplate code to move data around /////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto friend_info = ask_user_for_friend(std::move(info));
|
||||
|
||||
db::insert(
|
||||
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
|
||||
friend_info ////////////////////////////////////////////////////////////
|
||||
// Boost.PFR allows you to iterate over all the fields of a
|
||||
// user provided structure
|
||||
//
|
||||
);
|
||||
|
||||
return friend_info;
|
||||
}
|
||||
```
|
||||
]]
|
||||
]
|
||||
|
||||
Otherwise your library could require a customization point for a user type:
|
||||
|
||||
|
||||
[table:hand_made_vs_pfr_2
|
||||
[[ Without Boost.PFR ] [ With Boost.PFR ]]
|
||||
[[
|
||||
```
|
||||
#include <db/api.hpp>
|
||||
|
||||
struct user_info {
|
||||
std::int64_t id;
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
/// Customizations via hand-written code or macro like BOOST_FUSION_ADAPT_STRUCT ///
|
||||
auto db_api_tie(user_info& ui) noexcept {
|
||||
return std::tie(ui.id, ui.name, ui.email, ui.login);
|
||||
}
|
||||
|
||||
auto db_api_tie(const user_info& ui) noexcept {
|
||||
return std::tie(ui.id, ui.name, ui.email, ui.login);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
```
|
||||
][
|
||||
```
|
||||
#include <db/api.hpp>
|
||||
|
||||
struct user_info {
|
||||
std::int64_t id;
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
//////// With Boost.PFR there's no need in hand written customizations /////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
```
|
||||
]]
|
||||
]
|
||||
|
||||
|
||||
With Boost.PFR the code is shorter, more readable and more pleasant to write.
|
||||
|
||||
|
||||
|
||||
[h2 Out of the box functionality ]
|
||||
|
||||
Boost.PFR adds the following out-of-the-box functionality for aggregate initializable structures:
|
||||
|
||||
* comparison functions
|
||||
* heterogeneous comparators
|
||||
* hash
|
||||
* IO streaming
|
||||
* access to members by index
|
||||
* member type retrieval
|
||||
* methods for cooperation with `std::tuple`
|
||||
* methods to visit each field of the structure
|
||||
|
||||
Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder [@https://github.com/boostorg/pfr from the github] into your project, and the library will work fine.
|
||||
|
||||
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Short Examples for the Impatient]
|
||||
|
||||
[import ../example/quick_examples.cpp]
|
||||
|
||||
|
||||
[table:quick_examples
|
||||
[[ Code snippet ] [ Reference: ]]
|
||||
[
|
||||
[ [pfr_quick_examples_get] ]
|
||||
[ [funcref boost::pfr::get] ]
|
||||
][
|
||||
[ [pfr_quick_examples_ops] ]
|
||||
[
|
||||
|
||||
[headerref boost/pfr/ops.hpp Header boost/pfr/ops.hpp]:
|
||||
|
||||
* [funcref boost::pfr::eq]
|
||||
|
||||
* [funcref boost::pfr::ne]
|
||||
|
||||
* [funcref boost::pfr::gt]
|
||||
|
||||
* ...
|
||||
|
||||
]
|
||||
][
|
||||
[ [pfr_quick_examples_for_each] ]
|
||||
[
|
||||
[funcref boost::pfr::for_each_field]
|
||||
|
||||
[funcref boost::pfr::io]
|
||||
]
|
||||
][
|
||||
[ [pfr_quick_examples_functions_for] ]
|
||||
[ [macroref BOOST_PFR_FUNCTIONS_FOR] ]
|
||||
][
|
||||
[ [pfr_quick_examples_eq_fields] ]
|
||||
[
|
||||
[headerref boost/pfr/ops_fields.hpp Header boost/pfr/ops_fields.hpp ]:
|
||||
|
||||
* [funcref boost::pfr::eq_fields]
|
||||
|
||||
* [funcref boost::pfr::ne_fields]
|
||||
|
||||
* [funcref boost::pfr::gt_fields]
|
||||
|
||||
* ...
|
||||
|
||||
[headerref boost/pfr/io_fields.hpp Header boost/pfr/io_fields.hpp ]
|
||||
|
||||
* [funcref boost::pfr::io_fields]
|
||||
|
||||
]
|
||||
][
|
||||
[ [pfr_quick_examples_for_each_idx] ]
|
||||
[ [funcref boost::pfr::for_each_field] ]
|
||||
][
|
||||
[ [pfr_quick_examples_tuple_size] ]
|
||||
[ [classref boost::pfr::tuple_size] ]
|
||||
][
|
||||
[ [pfr_quick_examples_structure_to_tuple] ]
|
||||
[ [funcref boost::pfr::structure_to_tuple] ]
|
||||
][
|
||||
[ [pfr_quick_examples_structure_tie] ]
|
||||
[ [funcref boost::pfr::structure_tie] ]
|
||||
]]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Tutorial]
|
||||
|
||||
[import ../example/sample_printing.cpp]
|
||||
[import ../example/get.cpp]
|
||||
|
||||
|
||||
[section Why tuples are bad and aggregates are more preferable?]
|
||||
|
||||
`std::tuple` and `std::pair` are good for generic programming, however they have disadvantages. First of all, code that uses them becomes barely readable. Consider two definitions:
|
||||
|
||||
[table:tuples_vs_aggregates
|
||||
[[ Tuple ] [ Aggregate ]]
|
||||
[[
|
||||
```
|
||||
using auth_info_tuple = std::tuple<
|
||||
std::int64_t, // What does this integer represents?
|
||||
std::int64_t,
|
||||
std::time_t
|
||||
>;
|
||||
```
|
||||
][
|
||||
```
|
||||
struct auth_info_aggregate {
|
||||
std::int64_t user_id; // Oh, now I see!
|
||||
std::int64_t session_id;
|
||||
std::time_t valid_till;
|
||||
};
|
||||
```
|
||||
]]
|
||||
]
|
||||
|
||||
Definition via aggregate initializable structure is much more clear. Same story with usages: `return std::get<1>(value);` vs. `return value.session_id;`.
|
||||
|
||||
Another advantage of aggregates is a more efficient copy, move construction and assignments.
|
||||
|
||||
Because of the above issues some guidelines recommend to [*use aggregates instead of tuples]. However aggregates fail when it comes to the functional like programming.
|
||||
|
||||
Boost.PFR library [*provides tuple like methods for aggregate initializable structures], making aggregates usable in contexts where only tuples were useful.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Accessing structure member by index] [pfr_example_get] [endsect]
|
||||
[section Custom printing of aggregates] [pfr_sample_printing] [endsect]
|
||||
|
||||
|
||||
[section Three ways of getting operators ]
|
||||
|
||||
There are three ways to start using Boost.PFR hashing, comparison and streaming for type `T` in your code. Each method has its own drawbacks and suits own cases.
|
||||
|
||||
[table:ops_comp Different approaches for operators
|
||||
[[ Approach
|
||||
][ When to use
|
||||
][ 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/ops.hpp boost/pfr/ops.hpp: eq, ne, gt, lt, le, ge]
|
||||
|
||||
[headerref boost/pfr/io.hpp boost/pfr/io.hpp: io]
|
||||
][
|
||||
Use when you need to compare values by provided for them operators or via field-by-field comparison.
|
||||
][ no ][ yes ][ yes ][ no ][ yes ]]
|
||||
|
||||
[[
|
||||
[macroref BOOST_PFR_FUNCTIONS_FOR BOOST_PFR_FUNCTIONS_FOR(T)]
|
||||
][
|
||||
Use near the type definition to define the whole set of operators for your type.
|
||||
][ yes ][ no ][ no ][ yes for T ] [ no (compile time error) ]]
|
||||
|
||||
[[
|
||||
[headerref boost/pfr/ops_fields.hpp boost/pfr/ops_fields.hpp: eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields]
|
||||
|
||||
[headerref boost/pfr/io.hpp boost/pfr/io_fields.hpp: io_fields]
|
||||
][
|
||||
Use to implement the required set of operators for your type.
|
||||
][ no ][ yes ][ yes ][ yes ][ yes ]]
|
||||
]
|
||||
|
||||
More detailed description follows:
|
||||
|
||||
[*1. `eq, ne, gt, lt, le, ge, io` approach]
|
||||
|
||||
This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there are no operators defined for the type:
|
||||
|
||||
```
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
template <class T>
|
||||
struct uniform_comparator_less {
|
||||
bool operator()(const T& lhs, const T& rhs) const noexcept {
|
||||
// If T has operator< or conversion operator then it is used.
|
||||
return boost::pfr::lt(lhs, rhs);
|
||||
}
|
||||
};
|
||||
```
|
||||
This methods effects are local to the function. It works even for local types, like structures defined in functions.
|
||||
|
||||
|
||||
[*2. BOOST_PFR_FUNCTIONS_FOR(T) approach]
|
||||
|
||||
This method is good if you're writing a structure and wish to define operators for that structure.
|
||||
```
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
struct pair_like {
|
||||
int first;
|
||||
short second;
|
||||
};
|
||||
|
||||
BOOST_PFR_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_FUNCTIONS_FOR BOOST_PFR_FUNCTIONS_FOR(T)]
|
||||
can not be used for local types. It does not respect conversion operators of `T`, so for example the following code
|
||||
will output different values:
|
||||
```
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
struct empty {
|
||||
operator std::string() { return "empty{}"; }
|
||||
};
|
||||
// Uncomment to get different output:
|
||||
// BOOST_PFR_FUNCTIONS_FOR(empty)
|
||||
|
||||
// ...
|
||||
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
|
||||
```
|
||||
|
||||
[*3. `eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields, io_fields` approach]
|
||||
|
||||
This method is good if you're willing to provide only some operators for your type:
|
||||
|
||||
```
|
||||
#include <boost/pfr/io_fields.hpp>
|
||||
|
||||
struct pair_like {
|
||||
int first;
|
||||
std::string second;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const pair_like& x) {
|
||||
return os << bost::pfr::io_fields(x);
|
||||
}
|
||||
```
|
||||
|
||||
All the `*_fields` functions do ignore user defined operators and work only with fields of a type. This makes them perfect for defining you own operators.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Reflection of unions ]
|
||||
|
||||
You could use tuple-like representation if a type contains union. But be sure that operations for union are manually defined:
|
||||
|
||||
```
|
||||
#include <boost/pfr/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
|
||||
|
||||
bool some_function(test_union f1, test_union f2) {
|
||||
return boost::pfr::eq(f1, f2); // OK
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Reflection of unions is disabled in the Boost.PFR library for safety reasons. Alas, there's no way to find out [*active] member of a union and accessing an inactive member is an Undefined Behavior. For example, library could always return the first member, but ostreaming `u` in `union {char* c; long long ll; } u; u.ll= 1;` will crash your program with an invalid pointer 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 Limitations and Configuration]
|
||||
|
||||
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
|
||||
|
||||
Boost.PFR library works with types that satisfy the requirements of `SimpleAggregate`: aggregate types without base classes, `const` fields, references, or C arrays:
|
||||
|
||||
```
|
||||
struct simple_aggregate { // SimpleAggregate
|
||||
std::string name;
|
||||
int age;
|
||||
boost::uuids::uuid uuid;
|
||||
};
|
||||
|
||||
struct empty { // SimpleAggregate
|
||||
};
|
||||
|
||||
struct aggregate : empty { // not a SimpleAggregate
|
||||
std::string name;
|
||||
int age;
|
||||
boost::uuids::uuid uuid;
|
||||
};
|
||||
```
|
||||
The library may work with aggregates that don't satisfy the requirements of `SimpleAggregate`, but the behavior tends to be non-portable.
|
||||
|
||||
[h2 Configuration Macro]
|
||||
|
||||
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
|
||||
[table:linkmacro Macros
|
||||
[[Macro name] [Effect]]
|
||||
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to override Boost.PFR choice and use C++17 structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++17 structured bindings usage.]]
|
||||
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]]
|
||||
[[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use Boost.PFR version of that metafunction. Define to `1` to override Boost.PFR detection logic. ]]
|
||||
]
|
||||
|
||||
|
||||
[h2 Details on Limitations]
|
||||
|
||||
The Boost.PFRs reflection has some limitations that depend on a C++ Standard and compiler capabilities:
|
||||
|
||||
* Static variables are ignored
|
||||
* T must be aggregate initializable without empty base classes
|
||||
* if T contains C arrays or it is inherited from non-empty type then the result of reflection may differ depending on the C++ version and library configuration
|
||||
* Additional limitations if [*BOOST_PFR_USE_CPP17 == 0]:
|
||||
* Non of the member fields should have a template constructor from one parameter.
|
||||
* Additional limitations if [*BOOST_PFR_USE_LOOPHOLE == 0]:
|
||||
* T must be constexpr aggregate initializable and all its fields must be constexpr default constructible
|
||||
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/core.hpp boost::pfr::tuple_element] require T to be a POD type with built-in types only.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section How it works]
|
||||
|
||||
Short description:
|
||||
|
||||
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
||||
* [*BOOST_PFR_USE_CPP17 == 1]:
|
||||
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
|
||||
* [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 1]:
|
||||
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
||||
# at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
|
||||
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
|
||||
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
|
||||
# at run-time: get pointer to each field, knowing the structure address and each field offset
|
||||
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
|
||||
* [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 0]:
|
||||
# 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 [link boost_pfr.limitations_and_configuration [*BOOST_PFR_USE_LOOPHOLE == 0]]: [@https://youtu.be/abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling].
|
||||
Description of the [*BOOST_PFR_USE_LOOPHOLE == 1] technique by its inventor Alexandr Poltavsky [@http://alexpolt.github.io/type-loophole.html in his blog].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Acknowledgements]
|
||||
|
||||
Many thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/apolukhin/magic_get/issues/5 Manual type registering/structured bindings might be unnecessary].
|
||||
|
||||
Many thanks to Alexandr Poltavsky for initial implementation the [*BOOST_PFR_USE_LOOPHOLE == 1] technique and for describing it [@http://alexpolt.github.io/type-loophole.html in his blog].
|
||||
|
||||
Many thanks to Chris Beck for implementing the detect-offsets-and-get-field-address functionality that avoids Undefined Behavior of reinterpret_casting layout compatible structures.
|
||||
|
||||
Many thanks to the Boost people who participated in the formal review, especially to Benedek Thaler, Steven Watanabe and Andrzej Krzemienski.
|
||||
|
||||
[endsect]
|
||||
|
||||
[xinclude autodoc_pfr.xml]
|
||||
42
example/get.cpp
Normal file
42
example/get.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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>.)
|
||||
|
||||
//[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/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]
|
||||
|
||||
|
||||
int main() {
|
||||
if (r1 != 777) return 1;
|
||||
if (r2 != '!') return 2;
|
||||
|
||||
r1 = 42;
|
||||
r2 = 'A';
|
||||
|
||||
if (r1 != 42) return 3;
|
||||
if (r2 != 'A') return 4;
|
||||
if (f.some_integer != 42) return 5;
|
||||
if (f.c != 'A') return 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
26
example/motivating_example0.cpp
Normal file
26
example/motivating_example0.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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)
|
||||
|
||||
|
||||
//[pfr_motivating_example
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
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!
|
||||
|
||||
std::cout << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809}
|
||||
}
|
||||
//]
|
||||
188
example/quick_examples.cpp
Normal file
188
example/quick_examples.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
// 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>
|
||||
|
||||
void test_examples() {
|
||||
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
{
|
||||
//[pfr_quick_examples_ops
|
||||
// Assert equality.
|
||||
// Note that the equality operator for structure is not defined.
|
||||
|
||||
struct test {
|
||||
std::string f1;
|
||||
std::string_view f2;
|
||||
};
|
||||
|
||||
assert(
|
||||
boost::pfr::eq(test{"aaa", "zomg"}, test{"aaa", "zomg"})
|
||||
);
|
||||
//]
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_for_each
|
||||
// Increment each field of the variable on 1 and
|
||||
// output the content of the variable.
|
||||
|
||||
struct test {
|
||||
int f1;
|
||||
long f2;
|
||||
};
|
||||
|
||||
test var{42, 43};
|
||||
|
||||
boost::pfr::for_each_field(var, [](auto& field) {
|
||||
field += 1;
|
||||
});
|
||||
|
||||
// Outputs: {43, 44}
|
||||
std::cout << boost::pfr::io(var);
|
||||
//]
|
||||
}
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_for_each_idx
|
||||
// Iterate over fields of a varible and output index and
|
||||
// type of a variable.
|
||||
|
||||
struct tag0{};
|
||||
struct tag1{};
|
||||
struct sample {
|
||||
tag0 a;
|
||||
tag1 b;
|
||||
};
|
||||
|
||||
// Outputs:
|
||||
// 0: tag0
|
||||
// 1: tag1
|
||||
boost::pfr::for_each_field(sample{}, [](const auto& field, std::size_t idx) {
|
||||
std::cout << '\n' << idx << ": "
|
||||
<< boost::typeindex::type_id_runtime(field);
|
||||
});
|
||||
//]
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_tuple_size
|
||||
// Getting fields count of some structure
|
||||
|
||||
struct some { int a,b,c,d,e; };
|
||||
|
||||
std::cout << "Fields count in structure: "
|
||||
<< boost::pfr::tuple_size<some>::value // Outputs: 5
|
||||
<< '\n';
|
||||
//]
|
||||
}
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_get
|
||||
// Get field by index and assign new value to that field
|
||||
|
||||
struct sample {
|
||||
char c;
|
||||
float f;
|
||||
};
|
||||
|
||||
sample var{};
|
||||
boost::pfr::get<1>(var) = 42.01f;
|
||||
|
||||
std::cout << var.f; // Outputs: 42.01
|
||||
//]
|
||||
}
|
||||
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
{
|
||||
//[pfr_quick_examples_structure_to_tuple
|
||||
// Getting a std::tuple of values from structures fields
|
||||
|
||||
struct foo { int a, b; };
|
||||
struct other {
|
||||
char c;
|
||||
foo nested;
|
||||
};
|
||||
|
||||
other var{'A', {3, 4}};
|
||||
std::tuple<char, foo> t = boost::pfr::structure_to_tuple(var);
|
||||
assert(std::get<0>(t) == 'A');
|
||||
assert(
|
||||
boost::pfr::eq(std::get<1>(t), foo{3, 4})
|
||||
);
|
||||
//]
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
{
|
||||
//[pfr_quick_examples_structure_tie
|
||||
// Getting a std::tuple of references to structure fields
|
||||
|
||||
struct foo { int a, b; };
|
||||
struct other {
|
||||
char c;
|
||||
foo f;
|
||||
};
|
||||
|
||||
other var{'A', {14, 15}};
|
||||
std::tuple<char&, foo&> t = boost::pfr::structure_tie(var);
|
||||
std::get<1>(t) = foo{1, 2};
|
||||
|
||||
std::cout << boost::pfr::io(var.f); // Outputs: {1, 2}
|
||||
//]
|
||||
}
|
||||
#endif
|
||||
|
||||
} // void test_examples()
|
||||
|
||||
//[pfr_quick_examples_functions_for
|
||||
// Define all the comparison and IO operators for my_structure type along
|
||||
// with hash_value function.
|
||||
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
namespace my_namespace {
|
||||
struct my_structure {
|
||||
int a,b,c,d,e,f,g;
|
||||
// ...
|
||||
};
|
||||
BOOST_PFR_FUNCTIONS_FOR(my_structure)
|
||||
}
|
||||
//]
|
||||
|
||||
//[pfr_quick_examples_eq_fields
|
||||
// Define only the equality and inequality operators for my_eq_ne_structure.
|
||||
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
namespace my_namespace {
|
||||
struct my_eq_ne_structure {
|
||||
float a,b,c,d,e,f,g;
|
||||
// ...
|
||||
};
|
||||
|
||||
inline bool operator==(const my_eq_ne_structure& x, const my_eq_ne_structure& y) {
|
||||
return boost::pfr::eq_fields(x, y);
|
||||
}
|
||||
|
||||
inline bool operator!=(const my_eq_ne_structure& x, const my_eq_ne_structure& y) {
|
||||
return boost::pfr::ne_fields(x, y);
|
||||
}
|
||||
}
|
||||
//]
|
||||
|
||||
int main() {
|
||||
test_examples();
|
||||
}
|
||||
95
example/sample_printing.cpp
Normal file
95
example/sample_printing.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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>.)
|
||||
|
||||
//[pfr_sample_printing
|
||||
/*`
|
||||
The following example shows how to write your own io-manipulator for printing:
|
||||
*/
|
||||
#include <boost/pfr/ops.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace my_ns {
|
||||
|
||||
/// Usage:
|
||||
/// struct foo {std::uint8_t a, b;};
|
||||
/// ...
|
||||
/// std::cout << my_ns::my_io(foo{42, 22});
|
||||
///
|
||||
/// Output: 42, 22
|
||||
template <class T>
|
||||
auto my_io(const T& value);
|
||||
|
||||
namespace detail {
|
||||
// Helpers to print individual values
|
||||
template <class T>
|
||||
void print_each(std::ostream& out, const T& v) { out << v; }
|
||||
void print_each(std::ostream& out, std::uint8_t v) { out << static_cast<unsigned>(v); }
|
||||
void print_each(std::ostream& out, std::int8_t v) { out << static_cast<int>(v); }
|
||||
|
||||
// Structure to keep a reference to value, that will be ostreamed lower
|
||||
template <class T>
|
||||
struct io_reference {
|
||||
const T& value;
|
||||
};
|
||||
|
||||
// Output each field of io_reference::value
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, io_reference<T>&& x) {
|
||||
const char* sep = "";
|
||||
|
||||
boost::pfr::for_each_field(x.value, [&](const auto& v) {
|
||||
out << std::exchange(sep, ", ");
|
||||
detail::print_each(out, v);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
// Definition:
|
||||
template <class T>
|
||||
auto my_io(const T& value) {
|
||||
return detail::io_reference<T>{value};
|
||||
}
|
||||
|
||||
} // namespace my_ns
|
||||
//] [/pfr_sample_printing]
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
int main() {
|
||||
struct foo {std::uint8_t a, b;};
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << my_ns::my_io(foo{42, 22});
|
||||
|
||||
if (oss.str() != "42, 22") {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct two_big_strings {
|
||||
std::string first;
|
||||
std::string second;
|
||||
};
|
||||
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
const char* huge_string = "Some huge string that should not fit into std::string SSO."
|
||||
"And by 'huge' I mean really HUGE string with multiple statements and a lot of periods........."
|
||||
;
|
||||
|
||||
oss.str({});
|
||||
oss << my_ns::my_io(two_big_strings{
|
||||
huge_string, huge_string
|
||||
});
|
||||
|
||||
if (oss.str() != huge_string + std::string(", ") + huge_string) {
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
21
include/boost/pfr.hpp
Normal file
21
include/boost/pfr.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
#include <boost/pfr/functors.hpp>
|
||||
#include <boost/pfr/io.hpp>
|
||||
#include <boost/pfr/io_fields.hpp>
|
||||
#include <boost/pfr/ops.hpp>
|
||||
#include <boost/pfr/ops_fields.hpp>
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#endif // BOOST_PFR_HPP
|
||||
226
include/boost/pfr/core.hpp
Normal file
226
include/boost/pfr/core.hpp
Normal file
@@ -0,0 +1,226 @@
|
||||
// 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_CORE_HPP
|
||||
#define BOOST_PFR_CORE_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/stdtuple.hpp>
|
||||
#include <boost/pfr/detail/for_each_field_impl.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/tie_from_structure_tuple.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
/// \file boost/pfr/core.hpp
|
||||
/// Contains all the basic tuple-like interfaces \forcedlink{get}, \forcedlink{tuple_size}, \forcedlink{tuple_element_t}, and others.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// \brief Returns reference or const reference to a field with index `I` in \aggregate `val`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
/// assert(boost::pfr::get<0>(s) == 10);
|
||||
/// boost::pfr::get<1>(s) = 0;
|
||||
/// \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
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) noexcept {
|
||||
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
|
||||
}
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = 0) noexcept {
|
||||
return std::move(detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) ));
|
||||
}
|
||||
|
||||
|
||||
/// \brief `tuple_element` has a member typedef `type` that returns the type of a field with index I in \aggregate T.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \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 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 a `std::tuple` from fields of an \aggregate `val`.
|
||||
///
|
||||
/// \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 std::tie` like function that ties fields of a structure.
|
||||
///
|
||||
/// \returns a `std::tuple` with lvalue and const lvalue references to fields of an \aggregate `val`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// void foo(const int&, const short&);
|
||||
/// struct my_struct { int i, short s; };
|
||||
///
|
||||
/// const my_struct const_s{1, 2};
|
||||
/// std::apply(foo, structure_tie(const_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(const T& val) noexcept {
|
||||
return detail::make_conststdtiedtuple_from_tietuple(
|
||||
detail::tie_as_tuple(const_cast<T&>(val)),
|
||||
detail::make_index_sequence< tuple_size_v<T> >()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// \overload structure_tie
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T& val
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) noexcept {
|
||||
return detail::make_stdtiedtuple_from_tietuple(
|
||||
detail::tie_as_tuple(val),
|
||||
detail::make_index_sequence< tuple_size_v<T> >()
|
||||
);
|
||||
}
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
/// \overload structure_tie
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on non const non assignable type is allowed only in C++17");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// \overload structure_tie
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = 0) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on rvalue references is forbidden");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Calls `func` for each field of a `value`.
|
||||
///
|
||||
/// \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. Its lambdas do not capture constexprs.
|
||||
constexpr std::size_t fields_count_val_in_lambda
|
||||
= boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
|
||||
::boost::pfr::detail::for_each_field_impl(
|
||||
t,
|
||||
std::forward<F>(f),
|
||||
detail::make_index_sequence<fields_count_val_in_lambda>{},
|
||||
std::is_rvalue_reference<T&&>{}
|
||||
);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_val>{}
|
||||
);
|
||||
}
|
||||
|
||||
/// \brief std::tie-like function that allows assigning to tied values from aggregates.
|
||||
///
|
||||
/// \returns an object with lvalue references to `args...`; on assignment of an \aggregate value to that
|
||||
/// object each field of an aggregate is assigned to the corresponding `args...` reference.
|
||||
///
|
||||
/// \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_CORE_HPP
|
||||
75
include/boost/pfr/detail/cast_to_layout_compatible.hpp
Normal file
75
include/boost/pfr/detail/cast_to_layout_compatible.hpp
Normal 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
|
||||
80
include/boost/pfr/detail/config.hpp
Normal file
80
include/boost/pfr/detail/config.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
// 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
|
||||
|
||||
#include <type_traits> // to get non standard platform macro definitions (__GLIBCXX__ for example)
|
||||
|
||||
// Reminder:
|
||||
// * MSVC++ 14.2 _MSC_VER == 1927 <- Loophole is known to work (Visual Studio ????)
|
||||
// * MSVC++ 14.1 _MSC_VER == 1916 <- Loophole is known to NOT work (Visual Studio 2017)
|
||||
// * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
|
||||
// * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# if !defined(_MSVC_LANG) || _MSC_VER <= 1900
|
||||
# error Boost.PFR library requires more modern MSVC compiler.
|
||||
# endif
|
||||
#elif __cplusplus < 201402L
|
||||
# error Boost.PFR library requires at least C++14.
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_LOOPHOLE
|
||||
# if defined(_MSC_VER)
|
||||
# if _MSC_VER >= 1927
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# endif
|
||||
# elif defined(__clang_major__) && __clang_major__ >= 8
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_CPP17
|
||||
# ifdef __cpp_structured_bindings
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# elif defined(_MSVC_LANG)
|
||||
# if _MSVC_LANG >= 201703L
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# if !BOOST_PFR_USE_LOOPHOLE
|
||||
# error Boost.PFR requires /std:c++latest or /std:c++17 flags on your compiler.
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE
|
||||
// Assume that libstdc++ since GCC-7.3 does not have linear instantiation depth in std::make_integral_sequence
|
||||
# if defined( __GLIBCXX__) && __GLIBCXX__ >= 20180101
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
# elif defined(_MSC_VER)
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
//# elif other known working lib
|
||||
# else
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(maybe_unused)
|
||||
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_MAYBE_UNUSED
|
||||
# define BOOST_PFR_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CONFIG_HPP
|
||||
24
include/boost/pfr/detail/core.hpp
Normal file
24
include/boost/pfr/detail/core.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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_CORE_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
// Each core provides `boost::pfr::detail::tie_as_tuple` and
|
||||
// `boost::pfr::detail::for_each_field_dispatcher` functions.
|
||||
//
|
||||
// The whole PFR library is build on top of those two functions.
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
# include <boost/pfr/detail/core17.hpp>
|
||||
#elif BOOST_PFR_USE_LOOPHOLE
|
||||
# include <boost/pfr/detail/core14_loophole.hpp>
|
||||
#else
|
||||
# include <boost/pfr/detail/core14_classic.hpp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_HPP
|
||||
703
include/boost/pfr/detail/core14_classic.hpp
Normal file
703
include/boost/pfr/detail/core14_classic.hpp
Normal file
@@ -0,0 +1,703 @@
|
||||
// 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 reflected without Loophole or C++17, 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<std::remove_pointer_t<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>{});
|
||||
}
|
||||
|
||||
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. Change type definition or enable C++17"
|
||||
);
|
||||
return boost::pfr::detail::tie_as_flat_tuple(val);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////// 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 {};
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
|
||||
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>{}
|
||||
);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
|
||||
200
include/boost/pfr/detail/core14_loophole.hpp
Normal file
200
include/boost/pfr/detail/core14_loophole.hpp
Normal file
@@ -0,0 +1,200 @@
|
||||
// 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>{}
|
||||
);
|
||||
}
|
||||
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
}}} // 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
|
||||
|
||||
71
include/boost/pfr/detail/core17.hpp
Normal file
71
include/boost/pfr/detail/core17.hpp
Normal 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
|
||||
1036
include/boost/pfr/detail/core17_generated.hpp
Normal file
1036
include/boost/pfr/detail/core17_generated.hpp
Normal file
File diff suppressed because it is too large
Load Diff
70
include/boost/pfr/detail/detectors.hpp
Normal file
70
include/boost/pfr/detail/detectors.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// 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 <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
|
||||
struct can_not_apply{};
|
||||
|
||||
template <template <class, class> class Detector, class Tleft, class Tright>
|
||||
struct not_appliable {
|
||||
static constexpr bool value = std::is_same<
|
||||
Detector<Tleft, Tright>,
|
||||
can_not_apply
|
||||
>::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> can_not_apply 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> can_not_apply 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> can_not_apply 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> can_not_apply 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> can_not_apply 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> can_not_apply 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> auto hash_detector_msvc_helper(long) -> decltype(std::hash<S>{}(std::declval<S>()));
|
||||
template <class S> can_not_apply hash_detector_msvc_helper(int);
|
||||
template <class T1, class T2> using hash_detector = decltype(hash_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> can_not_apply 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> can_not_apply 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
|
||||
|
||||
|
||||
266
include/boost/pfr/detail/fields_count.hpp
Normal file
266
include/boost/pfr/detail/fields_count.hpp
Normal file
@@ -0,0 +1,266 @@
|
||||
// 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 { // tweak for template_unconstrained.cpp like cases
|
||||
return detail::unsafe_declval<Type&>();
|
||||
};
|
||||
|
||||
template <class Type> constexpr operator Type&() const & noexcept { // tweak for optional_chrono.cpp like cases
|
||||
return detail::unsafe_declval<Type&>();
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////// Structure that can be converted to rvalue reference to anything
|
||||
struct ubiq_rref_constructor {
|
||||
std::size_t ignore;
|
||||
template <class Type> /*constexpr*/ operator Type&&() const && noexcept { // Allows initialization of rvalue reference fields and move-only types
|
||||
return detail::unsafe_declval<Type&&>();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#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 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 built-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
|
||||
54
include/boost/pfr/detail/for_each_field_impl.hpp
Normal file
54
include/boost/pfr/detail/for_each_field_impl.hpp
Normal 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
|
||||
191
include/boost/pfr/detail/functional.hpp
Normal file
191
include/boost/pfr/detail/functional.hpp
Normal file
@@ -0,0 +1,191 @@
|
||||
// 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 <typename T>
|
||||
auto compute_hash(const T& value, long /*priority*/)
|
||||
-> decltype(std::hash<T>()(value))
|
||||
{
|
||||
return std::hash<T>()(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t compute_hash(const T& /*value*/, int /*priority*/) {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: std::hash not specialized for type T");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 {
|
||||
std::size_t h = detail::compute_hash( ::boost::pfr::detail::sequence_tuple::get<I>(val), 1L );
|
||||
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;
|
||||
}
|
||||
|
||||
template <template <std::size_t, std::size_t> class Visitor, class T, class U>
|
||||
constexpr 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 || BOOST_PFR_USE_LOOPHOLE
|
||||
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 boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_FUNCTIONAL_HPP
|
||||
85
include/boost/pfr/detail/io.hpp
Normal file
85
include/boost/pfr/detail/io.hpp
Normal 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
|
||||
96
include/boost/pfr/detail/make_flat_tuple_of_references.hpp
Normal file
96
include/boost/pfr/detail/make_flat_tuple_of_references.hpp
Normal 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
|
||||
90
include/boost/pfr/detail/make_integer_sequence.hpp
Normal file
90
include/boost/pfr/detail/make_integer_sequence.hpp
Normal 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 its 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
|
||||
|
||||
140
include/boost/pfr/detail/offset_based_getter.hpp
Normal file
140
include/boost/pfr/detail/offset_based_getter.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
// 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>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
// 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! Maybe the user-provided type is not a SimpleAggregate?");
|
||||
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
|
||||
35
include/boost/pfr/detail/rvalue_t.hpp
Normal file
35
include/boost/pfr/detail/rvalue_t.hpp
Normal 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
|
||||
127
include/boost/pfr/detail/sequence_tuple.hpp
Normal file
127
include/boost/pfr/detail/sequence_tuple.hpp
Normal 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 its 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
|
||||
79
include/boost/pfr/detail/size_array.hpp
Normal file
79
include/boost/pfr/detail/size_array.hpp
Normal 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
|
||||
18
include/boost/pfr/detail/size_t_.hpp
Normal file
18
include/boost/pfr/detail/size_t_.hpp
Normal 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
|
||||
46
include/boost/pfr/detail/stdtuple.hpp
Normal file
46
include/boost/pfr/detail/stdtuple.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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)...
|
||||
);
|
||||
}
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_conststdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
return std::tuple<
|
||||
std::add_lvalue_reference_t<std::add_const_t<
|
||||
std::remove_reference_t<decltype(boost::pfr::detail::sequence_tuple::get<I>(t))>
|
||||
>>...
|
||||
>(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_STDTUPLE_HPP
|
||||
44
include/boost/pfr/detail/tie_from_structure_tuple.hpp
Normal file
44
include/boost/pfr/detail/tie_from_structure_tuple.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
|
||||
#include <boost/pfr/detail/stdtuple.hpp>
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
|
||||
#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
|
||||
36
include/boost/pfr/detail/unsafe_declval.hpp
Normal file
36
include/boost/pfr/detail/unsafe_declval.hpp
Normal 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!
|
||||
//
|
||||
// GCCs 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
|
||||
|
||||
93
include/boost/pfr/functions_for.hpp
Normal file
93
include/boost/pfr/functions_for.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// 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_FUNCTIONS_FOR_HPP
|
||||
#define BOOST_PFR_FUNCTIONS_FOR_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/ops_fields.hpp>
|
||||
#include <boost/pfr/io_fields.hpp>
|
||||
|
||||
/// \file boost/pfr/functions_for.hpp
|
||||
/// Contains BOOST_PFR_FUNCTIONS_FOR macro that defined comparison and stream operators for T along with hash_value function.
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/functions_for.hpp>
|
||||
///
|
||||
/// namespace my_namespace {
|
||||
/// struct my_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_FUNCTIONS_FOR(my_struct)
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \podops for other ways to define operators and more details.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
|
||||
/// \def BOOST_PFR_FUNCTIONS_FOR(T)
|
||||
/// Defines comparison and stream operators for T along with hash_value function.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/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_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_FUNCTIONS_FOR(T) \
|
||||
BOOST_PFR_MAYBE_UNUSED inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::eq_fields(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::ne_fields(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::lt_fields(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::gt_fields(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::le_fields(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::ge_fields(lhs, rhs); } \
|
||||
template <class Char, class Traits> \
|
||||
BOOST_PFR_MAYBE_UNUSED inline ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
|
||||
return out << ::boost::pfr::io_fields(value); \
|
||||
} \
|
||||
template <class Char, class Traits> \
|
||||
BOOST_PFR_MAYBE_UNUSED inline ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
return in >> ::boost::pfr::io_fields(value); \
|
||||
} \
|
||||
BOOST_PFR_MAYBE_UNUSED inline std::size_t hash_value(const T& v) { \
|
||||
return ::boost::pfr::hash_fields(v); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
#endif // BOOST_PFR_FUNCTIONS_FOR_HPP
|
||||
|
||||
221
include/boost/pfr/functors.hpp
Normal file
221
include/boost/pfr/functors.hpp
Normal file
@@ -0,0 +1,221 @@
|
||||
// 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_FUNCTORS_HPP
|
||||
#define BOOST_PFR_FUNCTORS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
#include <boost/pfr/detail/functional.hpp>
|
||||
|
||||
/// \file boost/pfr/functors.hpp
|
||||
/// Contains functors that are close to the Standard Library ones.
|
||||
/// Each functor calls corresponding Boost.PFR function from boost/pfr/ops.hpp
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/functors.hpp>
|
||||
/// struct my_struct { // No operators defined for that structure
|
||||
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
|
||||
/// };
|
||||
/// // ...
|
||||
///
|
||||
/// std::unordered_set<
|
||||
/// my_struct,
|
||||
/// boost::pfr::hash<>,
|
||||
/// boost::pfr::equal_to<>
|
||||
/// > my_set;
|
||||
/// \endcode
|
||||
///
|
||||
/// \b Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
///////////////////// Comparisons
|
||||
|
||||
/// \brief std::equal_to like comparator that returns \forcedlink{eq}(x, y)
|
||||
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 boost::pfr::eq(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 boost::pfr::eq(x, y);
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::not_equal like comparator that returns \forcedlink{ne}(x, y)
|
||||
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 boost::pfr::ne(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 boost::pfr::ne(x, y);
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::greater like comparator that returns \forcedlink{gt}(x, y)
|
||||
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 boost::pfr::gt(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 boost::pfr::gt(x, y);
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::less like comparator that returns \forcedlink{lt}(x, y)
|
||||
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 boost::pfr::lt(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 boost::pfr::lt(x, y);
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::greater_equal like comparator that returns \forcedlink{ge}(x, y)
|
||||
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 boost::pfr::ge(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 boost::pfr::ge(x, y);
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::less_equal like comparator that returns \forcedlink{le}(x, y)
|
||||
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 boost::pfr::le(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 boost::pfr::le(x, y);
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
|
||||
/// \brief std::hash like functor that returns \forcedlink{hash_value}(x)
|
||||
template <class T> struct hash {
|
||||
/// \return hash value of \b x.
|
||||
std::size_t operator()(const T& x) const {
|
||||
return boost::pfr::hash_value(x);
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_FUNCTORS_HPP
|
||||
113
include/boost/pfr/io.hpp
Normal file
113
include/boost/pfr/io.hpp
Normal 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)
|
||||
|
||||
#ifndef BOOST_PFR_IO_HPP
|
||||
#define BOOST_PFR_IO_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/detectors.hpp>
|
||||
#include <boost/pfr/io_fields.hpp>
|
||||
|
||||
/// \file boost/pfr/io.hpp
|
||||
/// Contains IO stream manipulator \forcedlink{io} for types.
|
||||
/// If type is streamable using its own operator or its conversion operator, then the types operator is used.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/io.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};
|
||||
/// std::cout << boost::pfr::io(s1); // 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 Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
|
||||
///////////////////// Helper typedefs
|
||||
template <class Stream, class Type>
|
||||
using enable_not_ostreamable_t = std::enable_if_t<
|
||||
not_appliable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_not_istreamable_t = std::enable_if_t<
|
||||
not_appliable<istreamable_detector, Stream&, Type&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_ostreamable_t = std::enable_if_t<
|
||||
!not_appliable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_istreamable_t = std::enable_if_t<
|
||||
!not_appliable<istreamable_detector, Stream&, Type&>::value,
|
||||
Stream&
|
||||
>;
|
||||
|
||||
///////////////////// IO impl
|
||||
|
||||
template <class T>
|
||||
struct io_impl {
|
||||
T value;
|
||||
};
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
enable_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, io_impl<T>&& x) {
|
||||
return out << boost::pfr::io_fields(std::forward<T>(x.value));
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
enable_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, io_impl<T>&& x) {
|
||||
return out << x.value;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
enable_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, io_impl<T>&& x) {
|
||||
return in >> boost::pfr::io_fields(std::forward<T>(x.value));
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
enable_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, io_impl<T>&& x) {
|
||||
return in >> x.value;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// IO manupulator to read/write \aggregate `value` using its IO stream operators or using \forcedlink{io_fields} if operators are not awailable.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i; short s; };
|
||||
/// my_struct s;
|
||||
/// std::stringstream ss;
|
||||
/// ss << "{ 12, 13 }";
|
||||
/// ss >> boost::pfr::io(s);
|
||||
/// assert(s.i == 12);
|
||||
/// assert(s.i == 13);
|
||||
/// \endcode
|
||||
///
|
||||
/// \customio
|
||||
template <class T>
|
||||
auto io(T&& value) noexcept {
|
||||
return detail::io_impl<T>{std::forward<T>(value)};
|
||||
}
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_IO_HPP
|
||||
164
include/boost/pfr/io_fields.hpp
Normal file
164
include/boost/pfr/io_fields.hpp
Normal file
@@ -0,0 +1,164 @@
|
||||
// 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_IO_FIELDS_HPP
|
||||
#define BOOST_PFR_IO_FIELDS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/io.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
/// \file boost/pfr/io_fields.hpp
|
||||
/// Contains IO manupulator \forcedlink{io_fields} to read/write \aggregate `value` field-by-field.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct {
|
||||
/// int i;
|
||||
/// short s;
|
||||
/// };
|
||||
///
|
||||
/// std::ostream& operator<<(std::ostream& os, const my_struct& x) {
|
||||
/// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }"
|
||||
/// }
|
||||
///
|
||||
/// std::istream& operator>>(std::istream& is, my_struct& x) {
|
||||
/// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }"
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \podops for other ways to define operators and more details.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct io_fields_impl {
|
||||
T value;
|
||||
};
|
||||
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, io_fields_impl<const T&>&& x) {
|
||||
const T& value = x.value;
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
|
||||
out << '{';
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
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
|
||||
return out << '}';
|
||||
}
|
||||
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, io_fields_impl<T>&& x) {
|
||||
return out << io_fields_impl<const std::remove_reference_t<T>&>{x.value};
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T&>&& x) {
|
||||
T& value = x.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 || BOOST_PFR_USE_LOOPHOLE
|
||||
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);
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<const T&>&& ) {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Atetmpt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier.");
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T>&& ) {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Atetmpt to use istream operator on a boost::pfr::io_fields wrapped temporary of type T.");
|
||||
return in;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// IO manupulator to read/write \aggregate `value` field-by-field.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct {
|
||||
/// int i;
|
||||
/// short s;
|
||||
/// };
|
||||
///
|
||||
/// std::ostream& operator<<(std::ostream& os, const my_struct& x) {
|
||||
/// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }"
|
||||
/// }
|
||||
///
|
||||
/// std::istream& operator>>(std::istream& is, my_struct& x) {
|
||||
/// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }"
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Input and output streaming operators for `boost::pfr::io_fields` are symmetric, meaning that you get the original value by streaming it and
|
||||
/// reading back if each fields streaming operator is symmetric.
|
||||
///
|
||||
/// \customio
|
||||
template <class T>
|
||||
auto io_fields(T&& value) noexcept {
|
||||
return detail::io_fields_impl<T>{std::forward<T>(value)};
|
||||
}
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_IO_FIELDS_HPP
|
||||
187
include/boost/pfr/ops.hpp
Normal file
187
include/boost/pfr/ops.hpp
Normal file
@@ -0,0 +1,187 @@
|
||||
// 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_OPS_HPP
|
||||
#define BOOST_PFR_OPS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/detectors.hpp>
|
||||
#include <boost/pfr/ops_fields.hpp>
|
||||
|
||||
/// \file boost/pfr/ops.hpp
|
||||
/// Contains comparison and hashing functions.
|
||||
/// If type is comparable using its own operator or its conversion operator, then the types operator is used. Otherwise
|
||||
/// the operation is done via corresponding function from boost/pfr/ops.hpp header.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/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(boost::pfr::lt(s1, s2));
|
||||
/// \endcode
|
||||
///
|
||||
/// \podops for other ways to define operators and more details.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
|
||||
///////////////////// Helper typedefs that are used by all the ops
|
||||
template <template <class, class> class Detector, class T, class U>
|
||||
using enable_not_comp_base_t = std::enable_if_t<
|
||||
not_appliable<Detector, T const&, U const&>::value,
|
||||
bool
|
||||
>;
|
||||
|
||||
template <template <class, class> class Detector, class T, class U>
|
||||
using enable_comp_base_t = std::enable_if_t<
|
||||
!not_appliable<Detector, T const&, U const&>::value,
|
||||
bool
|
||||
>;
|
||||
///////////////////// std::enable_if_t like functions that enable only if types do not support operation
|
||||
|
||||
template <class T, class U> using enable_not_eq_comp_t = enable_not_comp_base_t<comp_eq_detector, T, U>;
|
||||
template <class T, class U> using enable_not_ne_comp_t = enable_not_comp_base_t<comp_ne_detector, T, U>;
|
||||
template <class T, class U> using enable_not_lt_comp_t = enable_not_comp_base_t<comp_lt_detector, T, U>;
|
||||
template <class T, class U> using enable_not_le_comp_t = enable_not_comp_base_t<comp_le_detector, T, U>;
|
||||
template <class T, class U> using enable_not_gt_comp_t = enable_not_comp_base_t<comp_gt_detector, T, U>;
|
||||
template <class T, class U> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T, U>;
|
||||
|
||||
template <class T> using enable_not_hashable_t = std::enable_if_t<
|
||||
not_appliable<hash_detector, const T&, const T&>::value,
|
||||
std::size_t
|
||||
>;
|
||||
///////////////////// std::enable_if_t like functions that enable only if types do support operation
|
||||
|
||||
template <class T, class U> using enable_eq_comp_t = enable_comp_base_t<comp_eq_detector, T, U>;
|
||||
template <class T, class U> using enable_ne_comp_t = enable_comp_base_t<comp_ne_detector, T, U>;
|
||||
template <class T, class U> using enable_lt_comp_t = enable_comp_base_t<comp_lt_detector, T, U>;
|
||||
template <class T, class U> using enable_le_comp_t = enable_comp_base_t<comp_le_detector, T, U>;
|
||||
template <class T, class U> using enable_gt_comp_t = enable_comp_base_t<comp_gt_detector, T, U>;
|
||||
template <class T, class U> using enable_ge_comp_t = enable_comp_base_t<comp_ge_detector, T, U>;
|
||||
|
||||
template <class T> using enable_hashable_t = std::enable_if_t<
|
||||
!not_appliable<hash_detector, const T&, const T&>::value,
|
||||
std::size_t
|
||||
>;
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for equality using their own comparison and conversion operators; if no operators avalable returns \forcedlink{eq_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_not_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::eq_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload eq
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for inequality using their own comparison and conversion operators; if no operators avalable returns \forcedlink{ne_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is not equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_not_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::ne_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload ne
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
|
||||
return lhs != rhs;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for less-than using their own comparison and conversion operators; if no operators avalable returns \forcedlink{lt_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is less than rhs; false otherwise
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_not_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::lt_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload lt
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for greater-than using their own comparison and conversion operators; if no operators avalable returns \forcedlink{lt_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is greater than rhs; false otherwise
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_not_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::gt_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload gt
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
|
||||
return lhs > rhs;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for less-equal using their own comparison and conversion operators; if no operators avalable returns \forcedlink{le_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is less or equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_not_le_comp_t<T, U> le(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::le_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload le
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
|
||||
return lhs <= rhs;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compares lhs and rhs for greater-equal using their own comparison and conversion operators; if no operators avalable returns \forcedlink{ge_fields}(lhs, rhs).
|
||||
///
|
||||
/// \returns true if lhs is greater or equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_not_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::ge_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload ge
|
||||
template <class T, class U>
|
||||
constexpr detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
|
||||
return lhs >= rhs;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Hashes value using its own std::hash specialization; if no std::hash specialization avalable returns \forcedlink{hash_fields}(value).
|
||||
///
|
||||
/// \returns std::size_t with hash of the value
|
||||
template <class T>
|
||||
constexpr detail::enable_not_hashable_t<T> hash_value(const T& value) noexcept {
|
||||
return boost::pfr::hash_fields(value);
|
||||
}
|
||||
|
||||
/// \overload hash_value
|
||||
template <class T>
|
||||
constexpr detail::enable_hashable_t<T> hash_value(const T& value) {
|
||||
return std::hash<T>{}(value);
|
||||
}
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_OPS_HPP
|
||||
127
include/boost/pfr/ops_fields.hpp
Normal file
127
include/boost/pfr/ops_fields.hpp
Normal 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_OPS_FIELDS_HPP
|
||||
#define BOOST_PFR_OPS_FIELDS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <boost/pfr/detail/functional.hpp>
|
||||
|
||||
/// \file boost/pfr/ops_fields.hpp
|
||||
/// Contains field-by-fields comparison and hash functions.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/ops_fields.hpp>
|
||||
/// struct comparable_struct { // No operators defined for that structure
|
||||
/// int i; short s;
|
||||
/// };
|
||||
/// // ...
|
||||
///
|
||||
/// comparable_struct s1 {0, 1};
|
||||
/// comparable_struct s2 {0, 2};
|
||||
/// assert(boost::pfr::lt_fields(s1, s2));
|
||||
/// \endcode
|
||||
///
|
||||
/// \podops for other ways to define operators and more details.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// Does a field-by-field equality comparison.
|
||||
///
|
||||
/// \returns `L == R && tuple_size_v<T> == tuple_size_v<U>`, where `L` and
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
constexpr bool eq_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
|
||||
/// Does a field-by-field inequality comparison.
|
||||
///
|
||||
/// \returns `L != R || tuple_size_v<T> != tuple_size_v<U>`, where `L` and
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
constexpr bool ne_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::not_equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
/// Does a field-by-field greter comparison.
|
||||
///
|
||||
/// \returns `L > R || (L == R && tuple_size_v<T> > tuple_size_v<U>)`, where `L` and
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
constexpr bool gt_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::greater_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
|
||||
/// Does a field-by-field less comparison.
|
||||
///
|
||||
/// \returns `L < R || (L == R && tuple_size_v<T> < tuple_size_v<U>)`, where `L` and
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
constexpr bool lt_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::less_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
|
||||
/// Does a field-by-field greater equal comparison.
|
||||
///
|
||||
/// \returns `L > R || (L == R && tuple_size_v<T> >= tuple_size_v<U>)`, where `L` and
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
constexpr bool ge_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::greater_equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
|
||||
/// Does a field-by-field less equal comparison.
|
||||
///
|
||||
/// \returns `L < R || (L == R && tuple_size_v<T> <= tuple_size_v<U>)`, where `L` and
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
constexpr bool le_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::less_equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
|
||||
/// Does a field-by-field hashing.
|
||||
///
|
||||
/// \returns combined hash of all the fields
|
||||
template <class T>
|
||||
std::size_t hash_fields(const T& x) {
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
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_OPS_HPP
|
||||
48
include/boost/pfr/tuple_size.hpp
Normal file
48
include/boost/pfr/tuple_size.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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_TUPLE_SIZE_HPP
|
||||
#define BOOST_PFR_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>
|
||||
|
||||
/// \file boost/pfr/tuple_size.hpp
|
||||
/// Contains tuple-like interfaces to get fields count \forcedlink{tuple_size}, \forcedlink{tuple_size_v}.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// Has a static const member variable `value` that contains fields count in a T.
|
||||
/// Works for any T that supports aggregate initialization.
|
||||
///
|
||||
/// \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.
|
||||
///
|
||||
/// \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_TUPLE_SIZE_HPP
|
||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=../../doc/html/boost_pfr.html">
|
||||
<title>Boost.PFR</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Redirecting you to <a href="../../doc/html/boost_pfr.html">Boost.PFR</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
1127
magic_get.hpp
1127
magic_get.hpp
File diff suppressed because it is too large
Load Diff
471
main.cpp
471
main.cpp
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
17
meta/libraries.json
Normal file
17
meta/libraries.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"key": "pfr",
|
||||
"name": "PFR",
|
||||
"authors": [
|
||||
"Antony Polukhin"
|
||||
],
|
||||
"maintainers": [
|
||||
"Antony Polukhin <antoshkka -at- gmail.com>"
|
||||
],
|
||||
"description": "Basic reflection for user defined types.",
|
||||
"category": [
|
||||
"Data",
|
||||
"Metaprogramming"
|
||||
],
|
||||
"std": [ "proposal" ],
|
||||
"cxxstd": "14"
|
||||
}
|
||||
111
misc/generate_cpp17.py
Normal file
111
misc/generate_cpp17.py
Normal 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; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
|
||||
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 range(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; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
print(" return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");")
|
||||
else:
|
||||
print(" auto& [")
|
||||
print(indexes)
|
||||
print(" ] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
print("")
|
||||
print(" return ::boost::pfr::detail::make_tuple_of_references(")
|
||||
print(indexes)
|
||||
print(" );")
|
||||
|
||||
print("}\n")
|
||||
|
||||
print(EPILOGUE)
|
||||
134
test/Jamfile.v2
Normal file
134
test/Jamfile.v2
Normal file
@@ -0,0 +1,134 @@
|
||||
# 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 python ;
|
||||
import testing ;
|
||||
import ../../config/checks/config : requires ;
|
||||
|
||||
project
|
||||
: source-location .
|
||||
: requirements
|
||||
<toolset>msvc:<cxxflags>"/std:c++latest"
|
||||
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
|
||||
[ requires cxx14_constexpr ]
|
||||
;
|
||||
|
||||
########## BEGIN of helpers to detect Loophole trick support
|
||||
|
||||
actions mp_simple_run_action
|
||||
{
|
||||
$(>) > $(<)
|
||||
}
|
||||
|
||||
rule mp-run-simple ( sources + : args * : input-files * : requirements * : target-name )
|
||||
{
|
||||
exe $(target-name)_exe : $(sources) : $(requirements) ;
|
||||
explicit $(target-name)_exe ;
|
||||
make $(target-name).output : $(target-name)_exe : @mp_simple_run_action ;
|
||||
explicit $(target-name).output ;
|
||||
alias $(target-name) : $(target-name).output ;
|
||||
}
|
||||
|
||||
mp-run-simple loophole_detection.cpp : : : : compiler_supports_loophole ;
|
||||
explicit compiler_supports_loophole ;
|
||||
|
||||
########## END of helpers to detect Loophole trick support
|
||||
|
||||
|
||||
local DISABLE_ON_MSVC = <toolset>msvc:<build>no ;
|
||||
local REQUIRE_LOOPHOLE =
|
||||
[ check-target-builds ../test//compiler_supports_loophole : : <build>no ]
|
||||
;
|
||||
|
||||
local STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=1 [ requires cxx17_structured_bindings ] ;
|
||||
local LOOPHOLE_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=1 <define>BOOST_PFR_USE_CPP17=0 $(REQUIRE_LOOPHOLE) ;
|
||||
local CLASSIC_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 $(DISABLE_ON_MSVC) ;
|
||||
|
||||
test-suite pfr_tests
|
||||
:
|
||||
[ run print_config.cpp : : : <test-info>always_show_run_output : auto_engine_config ]
|
||||
|
||||
[ run offset_based_getter.cpp ]
|
||||
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=void* : test_tuple_sizes_on_voidptrs ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON="std::size_t" : test_tuple_sizes_on_size_ts ]
|
||||
|
||||
[ run run/motivating_example.cpp : : : : auto_engine_motivating ]
|
||||
[ run ../example/sample_printing.cpp : : : : auto_engine_sample_printing ]
|
||||
[ run ../example/get.cpp : : : : auto_engine_get ]
|
||||
[ run ../example/quick_examples.cpp : : : : auto_engine_quick ]
|
||||
;
|
||||
|
||||
local BLACKLIST_TESTS_FOR_LOOPHOLE =
|
||||
constexpr_ops # Loophole is not constexpr usable because of the reinterpret_cast usage
|
||||
get_const_field # boost::pfr::get gives compile time error on const fields
|
||||
optional_chrono # boost::pfr::* has problems with std::optional, produces compile time error
|
||||
template_constructor # Template constructor in one of the fields of the aggregate
|
||||
tie_anonymous_const_field # boost::pfr::structure_tie gives compile time error on const fields
|
||||
;
|
||||
|
||||
# Those tests are either
|
||||
# * reflecting a non literal type
|
||||
# * or calling boost::pfr::get and the result is a user defined structure
|
||||
local BLACKLIST_TESTS_FOR_CLASSIC =
|
||||
constexpr_ops
|
||||
get_const_field
|
||||
get_non_default_constructible
|
||||
get_rvalue
|
||||
issue30
|
||||
issue33
|
||||
motivating_example0
|
||||
motivating_example2
|
||||
optional_chrono
|
||||
optional_like
|
||||
read_write_non_literal
|
||||
template_constructor
|
||||
template_forwarding_ref
|
||||
template_unconstrained
|
||||
tie_anonymous
|
||||
tie_anonymous_const_field
|
||||
;
|
||||
|
||||
for local source_file in [ glob ./run/*.cpp ] [ glob ../example/*.cpp ]
|
||||
{
|
||||
local target_name = $(source_file[1]:B) ;
|
||||
pfr_tests += [ run $(source_file) : : : $(STRUCTURED_BINDING_ENGINE) : $(target_name)_sb ] ;
|
||||
|
||||
if ! $(target_name) in $(BLACKLIST_TESTS_FOR_LOOPHOLE)
|
||||
{
|
||||
pfr_tests += [ run $(source_file) : : : $(LOOPHOLE_ENGINE) : $(target_name)_lh ] ;
|
||||
}
|
||||
else
|
||||
{
|
||||
pfr_tests += [ compile-fail $(source_file) : $(LOOPHOLE_ENGINE) : $(target_name)_lh ] ;
|
||||
}
|
||||
|
||||
if ! $(target_name) in $(BLACKLIST_TESTS_FOR_CLASSIC)
|
||||
{
|
||||
pfr_tests += [ run $(source_file) : : : $(CLASSIC_ENGINE) : $(target_name)_classic ] ;
|
||||
}
|
||||
else
|
||||
{
|
||||
pfr_tests += [ compile-fail $(source_file) : $(CLASSIC_ENGINE) : $(target_name)_classic ] ;
|
||||
}
|
||||
}
|
||||
|
||||
for local source_file in [ glob ./compile-fail/*.cpp ]
|
||||
{
|
||||
local target_name = $(source_file[1]:B) ;
|
||||
pfr_tests += [ compile-fail $(source_file) : $(STRUCTURED_BINDING_ENGINE) : $(target_name)_sb ] ;
|
||||
pfr_tests += [ compile-fail $(source_file) : $(LOOPHOLE_ENGINE) : $(target_name)_lh ] ;
|
||||
pfr_tests += [ compile-fail $(source_file) : $(CLASSIC_ENGINE) : $(target_name)_classic ] ;
|
||||
}
|
||||
|
||||
if [ python.configured ]
|
||||
{
|
||||
testing.make-test run-pyd : ../misc/generate_cpp17.py ;
|
||||
}
|
||||
100
test/appveyor.yml
Normal file
100
test/appveyor.yml
Normal file
@@ -0,0 +1,100 @@
|
||||
# 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:
|
||||
# boost-local/libs/ folder to put this library into. This may be useful, if you're for example running Travis
|
||||
# from `Boost.DLL` repo while Boost already has `dll` and with to replace `dll` with content of`Boost.DLL`.
|
||||
#
|
||||
# Otherwise just leave the default value - set BOOST_LIBS_FOLDER=%APPVEYOR_PROJECT_NAME%
|
||||
- set BOOST_LIBS_FOLDER=pfr # DIFF
|
||||
|
||||
###############################################################################################################
|
||||
# From this point and below code is same for all the Boost libs
|
||||
###############################################################################################################
|
||||
|
||||
version: 1.74.{build}-{branch}
|
||||
|
||||
# branches to build
|
||||
branches:
|
||||
except:
|
||||
- gh-pages
|
||||
|
||||
skip_tags: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
# TOOLSET: msvc # TODO: clang-win ???
|
||||
# ADDRMD: 32,64
|
||||
# CXXSTD: 17,latest
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
|
||||
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 %BOOST_LIBS_FOLDER%"
|
||||
# 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
|
||||
|
||||
- echo "rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%"
|
||||
- rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
||||
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
||||
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" -I example -I examples %BOOST_LIBS_FOLDER%
|
||||
|
||||
build_script:
|
||||
- cmd /c bootstrap
|
||||
- b2.exe headers
|
||||
- cd %BOOST%/libs/%BOOST_LIBS_FOLDER%/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:
|
||||
15
test/compile-fail/fields_count_on_reference.cpp
Normal file
15
test/compile-fail/fields_count_on_reference.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
|
||||
struct some_struct {
|
||||
int i;
|
||||
int j;
|
||||
};
|
||||
|
||||
int main() {
|
||||
return static_cast<int>(boost::pfr::detail::fields_count<some_struct&>());
|
||||
}
|
||||
25
test/compile-fail/movable_and_lvalue_references.cpp
Normal file
25
test/compile-fail/movable_and_lvalue_references.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/pfr/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() {
|
||||
return boost::pfr::tuple_size<test_lvalue_ref_and_movable>::value;
|
||||
}
|
||||
|
||||
16
test/compile-fail/non_aggregate.cpp
Normal file
16
test/compile-fail/non_aggregate.cpp
Normal 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/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();
|
||||
}
|
||||
|
||||
|
||||
18
test/compile-fail/ops_on_union.cpp
Normal file
18
test/compile-fail/ops_on_union.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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)
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
union test_union {
|
||||
const char* c;
|
||||
int i;
|
||||
};
|
||||
|
||||
int main() {
|
||||
test_union v{""};
|
||||
return boost::pfr::eq(v, v);
|
||||
}
|
||||
22
test/compile-fail/ops_unions.cpp
Normal file
22
test/compile-fail/ops_unions.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// 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)
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
union test_union {
|
||||
const char* c;
|
||||
int i;
|
||||
};
|
||||
|
||||
int main() {
|
||||
struct two_unions {
|
||||
test_union u1, u2;
|
||||
};
|
||||
|
||||
two_unions v{{""}, {""}};
|
||||
return boost::pfr::eq(v, v);
|
||||
}
|
||||
28
test/compile-fail/ops_unrestricted_unions.cpp
Normal file
28
test/compile-fail/ops_unrestricted_unions.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable: 4624 ) // destructor was implicitly defined as deleted
|
||||
#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 boost::pfr::eq(*v, *v);
|
||||
}
|
||||
39
test/compile-fail/pfr_review_test2.cpp
Normal file
39
test/compile-fail/pfr_review_test2.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2020 Antony Polukhin
|
||||
// Copyright (c) 2020 Richard Hodges
|
||||
//
|
||||
// Distributed under the 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 from https://github.com/madmongo1/pfr_review/blob/master/pre-cxx20/test-2.cpp
|
||||
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
#include <boost/utility/string_view.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace the_wild {
|
||||
struct animal {
|
||||
std::string name;
|
||||
boost::string_view temperament;
|
||||
};
|
||||
|
||||
// Error: std::hash not specialized for type
|
||||
// OR in C++14:
|
||||
// Error: animal is not constexpr initializable
|
||||
BOOST_PFR_FUNCTIONS_FOR(animal)
|
||||
} // namespace the_wild
|
||||
|
||||
const auto fido = the_wild::animal { "fido", "aloof" };
|
||||
|
||||
int main() {
|
||||
std::ostringstream oss;
|
||||
oss << fido;
|
||||
|
||||
BOOST_TEST_EQ(oss.str(), "{\"fido\", \"aloof\"}");
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
30
test/compile-fail/private_fields.cpp
Normal file
30
test/compile-fail/private_fields.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wunused-private-field"
|
||||
#endif
|
||||
|
||||
|
||||
class test_with_private {
|
||||
private:
|
||||
int i;
|
||||
char c;
|
||||
|
||||
public:
|
||||
double d;
|
||||
float f;
|
||||
};
|
||||
|
||||
int main() {
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
# error No known way to detect private fields.
|
||||
#endif
|
||||
|
||||
return boost::pfr::tuple_size<test_with_private>::value;
|
||||
}
|
||||
|
||||
26
test/compile-fail/protected_fields.cpp
Normal file
26
test/compile-fail/protected_fields.cpp
Normal 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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
class test_with_protected {
|
||||
protected:
|
||||
int i;
|
||||
char c;
|
||||
|
||||
public:
|
||||
double d;
|
||||
float f;
|
||||
};
|
||||
|
||||
int main() {
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
// TODO: No known way to detect protected fields
|
||||
# error No known way to detect protected fields.
|
||||
#endif
|
||||
|
||||
return boost::pfr::tuple_size<test_with_protected>::value;
|
||||
}
|
||||
|
||||
17
test/compile-fail/rvalue_tie.cpp
Normal file
17
test/compile-fail/rvalue_tie.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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/pfr/core.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
struct test_struct {
|
||||
int i;
|
||||
std::string s;
|
||||
};
|
||||
|
||||
int main() {
|
||||
boost::pfr::structure_tie(test_struct{1, "test"});
|
||||
}
|
||||
20
test/compile-fail/virtual_functions.cpp
Normal file
20
test/compile-fail/virtual_functions.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/pfr/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() {
|
||||
return boost::pfr::tuple_size<test_with_virtual>::value;
|
||||
}
|
||||
|
||||
29
test/loophole_detection.cpp
Normal file
29
test/loophole_detection.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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)
|
||||
|
||||
// Detection of type loophole.
|
||||
// Inspired by the blog post: http://alexpolt.github.io/type-loophole.html
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1916
|
||||
# error Compiler fails to do compile time computations for LoopHole. Fixed in later versions of the compiler
|
||||
// Error: boost/pfr/detail/core14_loophole.hpp(98): error C3779: 'boost::pfr::detail::loophole': a function that returns 'auto' cannot be used before it is defined
|
||||
#endif
|
||||
|
||||
|
||||
template <unsigned> struct tag{};
|
||||
|
||||
template <class T, unsigned N>
|
||||
struct loophole_t {
|
||||
friend auto loophole(tag<N>) { return T{}; };
|
||||
};
|
||||
|
||||
auto loophole(tag<0>);
|
||||
|
||||
int main() {
|
||||
sizeof(loophole_t<unsigned, 0>);
|
||||
static_assert( std::is_same<unsigned, decltype( loophole(tag<0>{}) ) >::value, "");
|
||||
}
|
||||
37
test/offset_based_getter.cpp
Normal file
37
test/offset_based_getter.cpp
Normal 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();
|
||||
}
|
||||
35
test/print_config.cpp
Normal file
35
test/print_config.cpp
Normal 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)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Platform info:" << '\n'
|
||||
<< "BOOST_PFR_USE_CPP17 == " << BOOST_PFR_USE_CPP17 << '\n'
|
||||
<< "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n'
|
||||
<< "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n'
|
||||
<< "__cplusplus == " << __cplusplus << '\n'
|
||||
#ifdef __cpp_structured_bindings
|
||||
<< "__cpp_structured_bindings == " << __cpp_structured_bindings << '\n'
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
<< "_MSC_VER == " << _MSC_VER << '\n'
|
||||
#endif
|
||||
#ifdef _MSVC_LANG
|
||||
<< "_MSVC_LANG == " << _MSVC_LANG << '\n'
|
||||
#endif
|
||||
#ifdef __GLIBCXX__
|
||||
<< "__GLIBCXX__ == " << __GLIBCXX__ << '\n'
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
<< "__GNUC__ == " << __GNUC__ << '\n'
|
||||
#endif
|
||||
#ifdef __clang_major__
|
||||
<< "__clang_major__ == " << __clang_major__ << '\n'
|
||||
#endif
|
||||
;
|
||||
}
|
||||
21
test/run/bitfields_count.cpp
Normal file
21
test/run/bitfields_count.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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/tuple_size.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() {
|
||||
static_assert(boost::pfr::tuple_size<bf>::value == 6, "");
|
||||
}
|
||||
|
||||
|
||||
81
test/run/constexpr_ops.cpp
Normal file
81
test/run/constexpr_ops.cpp
Normal 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)
|
||||
|
||||
#include <boost/pfr/ops.hpp>
|
||||
#include <boost/pfr/io.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
#endif
|
||||
|
||||
union test_union {
|
||||
int i;
|
||||
float f;
|
||||
};
|
||||
|
||||
constexpr bool operator< (test_union l, test_union r) noexcept { return l.i < r.i; }
|
||||
constexpr bool operator<=(test_union l, test_union r) noexcept { return l.i <= r.i; }
|
||||
constexpr bool operator> (test_union l, test_union r) noexcept { return l.i > r.i; }
|
||||
constexpr bool operator>=(test_union l, test_union r) noexcept { return l.i >= r.i; }
|
||||
constexpr bool operator==(test_union l, test_union r) noexcept { return l.i == r.i; }
|
||||
constexpr bool operator!=(test_union l, test_union r) noexcept { return l.i != r.i; }
|
||||
|
||||
|
||||
template <class T>
|
||||
void test_constexpr_comparable() {
|
||||
using namespace boost::pfr;
|
||||
constexpr T s1 {110, 1, true, 6,17,8,9,10,11};
|
||||
constexpr T s2 = s1;
|
||||
constexpr T s3 {110, 1, true, 6,17,8,9,10,11111};
|
||||
static_assert(eq(s1, s2), "");
|
||||
static_assert(le(s1, s2), "");
|
||||
static_assert(ge(s1, s2), "");
|
||||
static_assert(!ne(s1, s2), "");
|
||||
static_assert(!eq(s1, s3), "");
|
||||
static_assert(ne(s1, s3), "");
|
||||
static_assert(lt(s1, s3), "");
|
||||
static_assert(gt(s3, s2), "");
|
||||
static_assert(le(s1, s3), "");
|
||||
static_assert(ge(s3, s2), "");
|
||||
}
|
||||
|
||||
namespace foo {
|
||||
struct comparable_struct {
|
||||
int i; short s; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
}
|
||||
|
||||
int main() {
|
||||
// MSVC fails to use strucutred bindings in constexpr:
|
||||
//
|
||||
// error C2131: expression did not evaluate to a constant
|
||||
// pfr/detail/functional.hpp(21): note: failure was caused by a read of a variable outside its lifetime
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1927) || !BOOST_PFR_USE_CPP17
|
||||
test_constexpr_comparable<foo::comparable_struct>();
|
||||
|
||||
struct local_comparable_struct {
|
||||
int i; short s; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
test_constexpr_comparable<local_comparable_struct>();
|
||||
|
||||
struct local_comparable_struct_with_union {
|
||||
int i; short s; bool bl; int a,b,c,d,e; test_union u;
|
||||
};
|
||||
test_constexpr_comparable<local_comparable_struct>();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
60
test/run/destructuring_tie.cpp
Normal file
60
test/run/destructuring_tie.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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/core.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
101
test/run/error_pfr_c1202.cpp
Normal file
101
test/run/error_pfr_c1202.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// 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)
|
||||
|
||||
// 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.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
|
||||
}
|
||||
15
test/run/fields_count_on_const.cpp
Normal file
15
test/run/fields_count_on_const.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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)
|
||||
|
||||
#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, "");
|
||||
}
|
||||
113
test/run/for_each_field.cpp
Normal file
113
test/run/for_each_field.cpp
Normal 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/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();
|
||||
}
|
||||
160
test/run/functions_for.cpp
Normal file
160
test/run/functions_for.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
// 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/functions_for.hpp>
|
||||
|
||||
#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_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_FUNCTIONS_FOR(empty)
|
||||
|
||||
void test_empty_struct() {
|
||||
BOOST_TEST_EQ(empty{}, empty{});
|
||||
}
|
||||
|
||||
namespace foo {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
BOOST_PFR_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_FUNCTIONS_FOR
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct anonymous_comparable_struct {
|
||||
int i; short s; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
|
||||
BOOST_PFR_FUNCTIONS_FOR(anonymous_comparable_struct)
|
||||
|
||||
|
||||
struct other_anonymous_struct {
|
||||
anonymous_comparable_struct a,b;
|
||||
};
|
||||
|
||||
BOOST_PFR_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();
|
||||
}
|
||||
|
||||
|
||||
55
test/run/get_const_field.cpp
Normal file
55
test/run/get_const_field.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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/pfr/core.hpp>
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
struct other_anon {
|
||||
int data;
|
||||
};
|
||||
|
||||
struct anon {
|
||||
other_anon a;
|
||||
const other_anon b;
|
||||
};
|
||||
|
||||
void test_get_in_anon_ns_const_field() {
|
||||
anon x{{1}, {2}};
|
||||
|
||||
BOOST_TEST_EQ(boost::pfr::get<0>(x).data, 1);
|
||||
auto x0_type = boost::typeindex::type_id_with_cvr<decltype(
|
||||
boost::pfr::get<0>(x)
|
||||
)>();
|
||||
// Use runtime check to make sure that Loophole fails to compile structure_tie
|
||||
BOOST_TEST_EQ(x0_type, boost::typeindex::type_id_with_cvr<other_anon&>());
|
||||
|
||||
BOOST_TEST_EQ(boost::pfr::get<1>(x).data, 2);
|
||||
auto x1_type = boost::typeindex::type_id_with_cvr<decltype(
|
||||
boost::pfr::get<1>(x)
|
||||
)>();
|
||||
// Use runtime check to make sure that Loophole fails to compile structure_tie
|
||||
BOOST_TEST_EQ(x1_type, boost::typeindex::type_id_with_cvr<const other_anon&>());
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_get_in_anon_ns_const_field();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
27
test/run/get_non_default_constructible.cpp
Normal file
27
test/run/get_non_default_constructible.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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.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() {
|
||||
Foo f{0};
|
||||
f.a.val_ = 5;
|
||||
|
||||
BOOST_TEST_EQ(boost::pfr::get<0>(f).val_, 5);
|
||||
return boost::report_errors();
|
||||
}
|
||||
31
test/run/get_rvalue.cpp
Normal file
31
test/run/get_rvalue.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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/pfr/core.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct unique_ptrs {
|
||||
std::unique_ptr<int> p1;
|
||||
std::unique_ptr<int> p2;
|
||||
};
|
||||
|
||||
void test_get_rvalue() {
|
||||
unique_ptrs x {
|
||||
std::make_unique<int>(42),
|
||||
std::make_unique<int>(43),
|
||||
};
|
||||
|
||||
auto p = boost::pfr::get<0>(std::move(x));
|
||||
BOOST_TEST_EQ(*p, 42);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_get_rvalue();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
31
test/run/issue30.cpp
Normal file
31
test/run/issue30.cpp
Normal 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/run/issue33.cpp
Normal file
26
test/run/issue33.cpp
Normal 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();
|
||||
}
|
||||
22
test/run/motivating_example.cpp
Normal file
22
test/run/motivating_example.cpp
Normal 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() {
|
||||
my_struct s{100, 'H', 3.141593};
|
||||
std::cout << "my_struct has "
|
||||
<< boost::pfr::tuple_size<my_struct>::value // Outputs: 3
|
||||
<< " fields: "
|
||||
<< boost::pfr::io(s); // Outputs: {100, 'H', 3.141593}
|
||||
}
|
||||
21
test/run/motivating_example2.cpp
Normal file
21
test/run/motivating_example2.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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() {
|
||||
my_struct s{{"Das ist fantastisch!"}, 100};
|
||||
|
||||
std::cout << "my_struct has "
|
||||
<< boost::pfr::tuple_size<my_struct>::value // Outputs: 2
|
||||
<< " fields: "
|
||||
<< boost::pfr::io(s); // Outputs: {"Das ist fantastisch!", 100};
|
||||
}
|
||||
43
test/run/non_copyable_but_movable.cpp
Normal file
43
test/run/non_copyable_but_movable.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#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() {
|
||||
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, "");
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
44
test/run/non_dc_non_cop_but_mov.cpp
Normal file
44
test/run/non_dc_non_cop_but_mov.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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)
|
||||
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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() {
|
||||
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, "");
|
||||
}
|
||||
|
||||
34
test/run/non_default_constructible.cpp
Normal file
34
test/run/non_default_constructible.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
struct X {
|
||||
X(int) {}
|
||||
};
|
||||
struct S { X x0; X x1; int x2; X x3; };
|
||||
|
||||
int main() {
|
||||
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, "");
|
||||
}
|
||||
|
||||
26
test/run/non_std_layout.cpp
Normal file
26
test/run/non_std_layout.cpp
Normal 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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
|
||||
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() {
|
||||
static_assert(boost::pfr::tuple_size<test_with_non_st_layout>::value == 3, "");
|
||||
}
|
||||
|
||||
108
test/run/ops.cpp
Normal file
108
test/run/ops.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// 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/ops.hpp>
|
||||
#include <boost/pfr/io.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
#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;
|
||||
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(eq(s1, s2));
|
||||
BOOST_TEST(le(s1, s2));
|
||||
BOOST_TEST(ge(s1, s2));
|
||||
BOOST_TEST(!ne(s1, s2));
|
||||
BOOST_TEST(!eq(s1, s3));
|
||||
BOOST_TEST(ne(s1, s3));
|
||||
BOOST_TEST(lt(s1, s3));
|
||||
BOOST_TEST(gt(s3, s2));
|
||||
BOOST_TEST(le(s1, s3));
|
||||
BOOST_TEST(ge(s3, s2));
|
||||
|
||||
std::cout << boost::pfr::io(s1);
|
||||
|
||||
T s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << boost::pfr::io(s1);
|
||||
ss >> boost::pfr::io(s4);
|
||||
std::cout << boost::pfr::io(s4);
|
||||
BOOST_TEST(eq(s1, s4));
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
std::cout << boost::pfr::io(empty{});
|
||||
BOOST_TEST(boost::pfr::eq(empty{}, empty{}));
|
||||
}
|
||||
|
||||
void test_implicit_conversions() {
|
||||
std::stringstream ss;
|
||||
ss << boost::pfr::io(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>();
|
||||
|
||||
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);
|
||||
|
||||
test_empty_struct();
|
||||
test_implicit_conversions();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
78
test/run/optional_chrono.cpp
Normal file
78
test/run/optional_chrono.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <optional>
|
||||
|
||||
// This class mimics libc++ implementation of std::chrono::duration with unfxed LWG3050
|
||||
template <class Rep, class Period>
|
||||
class bogus_duration {
|
||||
public:
|
||||
bogus_duration() = default;
|
||||
|
||||
template <class T>
|
||||
explicit bogus_duration(const T& val,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<T, Rep>::value // <= libstdc++ fix for LWG3050 is 's/T/const T&/g'
|
||||
>::type* = nullptr)
|
||||
: rep_(val)
|
||||
{}
|
||||
|
||||
template <class Rep2, class Period2>
|
||||
bogus_duration(const bogus_duration<Rep2, Period2>& val,
|
||||
typename std::enable_if<std::is_convertible<Period2, Rep>::value>::type* = nullptr)
|
||||
: rep_(val)
|
||||
{}
|
||||
|
||||
Rep get_rep() const { return rep_; }
|
||||
|
||||
private:
|
||||
Rep rep_{0};
|
||||
};
|
||||
|
||||
struct struct_with_bogus_duration {
|
||||
std::optional<bogus_duration<long, char>> d0;
|
||||
std::optional<bogus_duration<long, char>> d1;
|
||||
};
|
||||
|
||||
struct struct_with_optional {
|
||||
std::optional<std::chrono::seconds> a;
|
||||
std::optional<std::chrono::milliseconds> b;
|
||||
std::optional<std::chrono::microseconds> c;
|
||||
std::optional<std::chrono::nanoseconds> d;
|
||||
std::optional<std::chrono::steady_clock::duration> e;
|
||||
std::optional<std::chrono::system_clock::duration> f;
|
||||
};
|
||||
|
||||
int main() {
|
||||
struct_with_optional val{
|
||||
std::chrono::seconds{1},
|
||||
std::chrono::seconds{2},
|
||||
std::chrono::seconds{3},
|
||||
std::chrono::seconds{4},
|
||||
std::chrono::seconds{5},
|
||||
std::chrono::seconds{6},
|
||||
};
|
||||
|
||||
using boost::pfr::get;
|
||||
BOOST_TEST(get<0>(val) == std::chrono::seconds{1});
|
||||
BOOST_TEST(get<1>(val) == std::chrono::seconds{2});
|
||||
BOOST_TEST(get<2>(val) == std::chrono::seconds{3});
|
||||
BOOST_TEST(get<3>(val) == std::chrono::seconds{4});
|
||||
BOOST_TEST(get<3>(val) > std::chrono::seconds{0});
|
||||
BOOST_TEST(get<3>(val) > std::chrono::seconds{0});
|
||||
|
||||
struct_with_bogus_duration val2{bogus_duration<long, char>{1}, bogus_duration<long, char>{2}};
|
||||
BOOST_TEST(get<0>(val2)->get_rep() == 1);
|
||||
BOOST_TEST(get<1>(val2)->get_rep() == 2);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
27
test/run/optional_like.cpp
Normal file
27
test/run/optional_like.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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.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() {
|
||||
Foo f{0};
|
||||
f.a.val_ = 5;
|
||||
|
||||
BOOST_TEST_EQ(boost::pfr::get<0>(f).val_, 5);
|
||||
return boost::report_errors();
|
||||
}
|
||||
90
test/run/read_write.cpp
Normal file
90
test/run/read_write.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// 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/io.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
template <class T>
|
||||
void test_write_read(const T& value) {
|
||||
T result;
|
||||
std::stringstream ss;
|
||||
ss << boost::pfr::io(value);
|
||||
ss >> boost::pfr::io(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;
|
||||
ss << boost::pfr::io(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}");
|
||||
|
||||
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}}"
|
||||
);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
75
test/run/read_write_non_literal.cpp
Normal file
75
test/run/read_write_non_literal.cpp
Normal 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)
|
||||
|
||||
#include <boost/pfr/io.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
template <class T>
|
||||
void test_write_read(const T& value) {
|
||||
T result;
|
||||
std::stringstream ss;
|
||||
ss << boost::pfr::io(value);
|
||||
ss >> boost::pfr::io(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;
|
||||
ss << boost::pfr::io(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);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
#if !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
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
36
test/run/std_interactions.cpp
Normal file
36
test/run/std_interactions.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace helper {
|
||||
template <std::size_t I, class T>
|
||||
decltype(auto) get(T&& v) {
|
||||
return boost::pfr::get<I>(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();
|
||||
}
|
||||
|
||||
56
test/run/template_constructor.cpp
Normal file
56
test/run/template_constructor.cpp
Normal 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/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;
|
||||
}
|
||||
69
test/run/template_forwarding_ref.cpp
Normal file
69
test/run/template_forwarding_ref.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
template <class T>
|
||||
struct unconstrained_forwarding_ref {
|
||||
unconstrained_forwarding_ref() = default;
|
||||
unconstrained_forwarding_ref(const unconstrained_forwarding_ref&) = default;
|
||||
unconstrained_forwarding_ref(unconstrained_forwarding_ref&&) = default;
|
||||
unconstrained_forwarding_ref& operator=(const unconstrained_forwarding_ref&) = default;
|
||||
unconstrained_forwarding_ref& operator=(unconstrained_forwarding_ref&&) = default;
|
||||
|
||||
template <class U>
|
||||
constexpr unconstrained_forwarding_ref(U&& val)
|
||||
: value_{std::forward<U>(val)}
|
||||
{}
|
||||
|
||||
T value_{};
|
||||
};
|
||||
|
||||
struct int_element {
|
||||
int value_;
|
||||
};
|
||||
|
||||
|
||||
struct aggregate_unconstrained {
|
||||
unconstrained_forwarding_ref<int> a;
|
||||
unconstrained_forwarding_ref<int_element> b;
|
||||
};
|
||||
|
||||
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;
|
||||
(void)foo;
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
boost::pfr::tuple_element_t<0, aggregate_unconstrained>,
|
||||
unconstrained_forwarding_ref<int>
|
||||
>::value,
|
||||
"Precise reflection with template constructors fails to work"
|
||||
);
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
boost::pfr::tuple_element_t<1, aggregate_unconstrained>,
|
||||
unconstrained_forwarding_ref<int_element>
|
||||
>::value,
|
||||
"Precise reflection with template constructors fails to work"
|
||||
);
|
||||
|
||||
aggregate_unconstrained aggr{3, 4};
|
||||
return boost::pfr::get<1>(aggr).value_.value_ - 4;
|
||||
}
|
||||
69
test/run/template_unconstrained.cpp
Normal file
69
test/run/template_unconstrained.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
template <class T>
|
||||
struct unconstrained_template {
|
||||
unconstrained_template() = default;
|
||||
unconstrained_template(const unconstrained_template&) = default;
|
||||
unconstrained_template(unconstrained_template&&) = default;
|
||||
unconstrained_template& operator=(const unconstrained_template&) = default;
|
||||
unconstrained_template& operator=(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;
|
||||
};
|
||||
|
||||
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;
|
||||
(void)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"
|
||||
);
|
||||
|
||||
aggregate_unconstrained aggr{3, 4};
|
||||
return boost::pfr::get<1>(aggr).value_.value_ - 4;
|
||||
}
|
||||
108
test/run/tie_anonymous.cpp
Normal file
108
test/run/tie_anonymous.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(__has_include)
|
||||
# if __has_include(<optional>) && (__cplusplus >= 201703L)
|
||||
# include <optional>
|
||||
# ifdef __cpp_lib_optional
|
||||
# define BOOST_PFR_TEST_HAS_OPTIONAL 1
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_TEST_HAS_OPTIONAL
|
||||
#define BOOST_PFR_TEST_HAS_OPTIONAL 0
|
||||
#endif
|
||||
|
||||
namespace some {
|
||||
struct struct1{ int i; };
|
||||
struct struct2{ int i; };
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
#if BOOST_PFR_TEST_HAS_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;
|
||||
const other_anon b;
|
||||
};
|
||||
|
||||
void test_in_anon_ns() {
|
||||
const anon const_x{{10}, {20}};
|
||||
|
||||
auto const_v = boost::pfr::structure_tie(const_x);
|
||||
BOOST_TEST_EQ(std::get<0>(const_v).data, 10);
|
||||
BOOST_TEST_EQ(std::get<1>(const_v).data, 20);
|
||||
static_assert(std::is_same<
|
||||
std::tuple<const other_anon&, const other_anon&>, decltype(const_v)
|
||||
>::value, "");
|
||||
|
||||
// TODO: something is wrong with loophole and optional
|
||||
#if BOOST_PFR_TEST_HAS_OPTIONAL && !BOOST_PFR_USE_LOOPHOLE
|
||||
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() {
|
||||
const anon const_x{{10}, {20}};
|
||||
|
||||
auto const_v = boost::pfr::structure_tie(const_x);
|
||||
BOOST_TEST_EQ(std::get<0>(const_v).data, 10);
|
||||
BOOST_TEST_EQ(std::get<1>(const_v).data, 20);
|
||||
static_assert(std::is_same<
|
||||
std::tuple<const other_anon&, const other_anon&>, decltype(const_v)
|
||||
>::value, "");
|
||||
|
||||
// TODO: something is wrong with loophole and optional
|
||||
#if BOOST_PFR_TEST_HAS_OPTIONAL && !BOOST_PFR_USE_LOOPHOLE
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
60
test/run/tie_anonymous_const_field.cpp
Normal file
60
test/run/tie_anonymous_const_field.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <type_traits>
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
struct other_anon {
|
||||
int data;
|
||||
};
|
||||
|
||||
struct anon {
|
||||
other_anon a;
|
||||
const other_anon b;
|
||||
};
|
||||
|
||||
void test_in_anon_ns_const_field() {
|
||||
anon x{{1}, {2}};
|
||||
|
||||
auto v = boost::pfr::structure_tie(x);
|
||||
using v_type = decltype(v);
|
||||
using expected_type = std::tuple<other_anon&, const other_anon&>;
|
||||
|
||||
// Use runtime check to make sure that Loophole fails to compile structure_tie
|
||||
BOOST_TEST(typeid(expected_type) == typeid(v_type));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void test_in_non_non_ns_const_field() {
|
||||
anon x{{1}, {2}};
|
||||
|
||||
auto v = boost::pfr::structure_tie(x);
|
||||
using v_type = decltype(v);
|
||||
using expected_type = std::tuple<other_anon&, const other_anon&>;
|
||||
|
||||
// Use runtime check to make sure that Loophole fails to compile structure_tie
|
||||
BOOST_TEST(typeid(expected_type) == typeid(v_type));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_in_anon_ns_const_field();
|
||||
testing::test_in_non_non_ns_const_field();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
16
test/run/tuple_size.cpp
Normal file
16
test/run/tuple_size.cpp
Normal 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/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, "");
|
||||
}
|
||||
|
||||
53
test/test_tuple_sizes_on.cpp
Normal file
53
test/test_tuple_sizes_on.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
|
||||
template <class T1>
|
||||
void test_counts_on_multiple_chars_impl() {
|
||||
using boost::pfr::tuple_size_v;
|
||||
|
||||
struct t1_0 { T1 v1; };
|
||||
#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(tuple_size_v<t1_0_1> == 1, "");
|
||||
|
||||
struct t1_0_2 { t1_0 t1; t1_0 t2; };
|
||||
static_assert(tuple_size_v<t1_0_2> == 2, "");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_counts_on_multiple_chars() {
|
||||
using boost::pfr::tuple_size_v;
|
||||
|
||||
test_counts_on_multiple_chars_impl<T>();
|
||||
|
||||
struct t2 { T v1; T v2; };
|
||||
static_assert(tuple_size_v<t2> == 2, "");
|
||||
|
||||
test_counts_on_multiple_chars_impl<t2>();
|
||||
test_counts_on_multiple_chars_impl<T[2]>();
|
||||
|
||||
test_counts_on_multiple_chars_impl<T[3]>();
|
||||
test_counts_on_multiple_chars_impl<T[4]>();
|
||||
|
||||
struct t8 { T v1; T v2; T v3; T v4; T v5; T v6; T v7; T v8; };
|
||||
static_assert(tuple_size_v<t8> == 8, "");
|
||||
test_counts_on_multiple_chars_impl<t8>();
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_counts_on_multiple_chars< BOOST_PFR_RUN_TEST_ON >();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user