mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
542 Commits
before_pre
...
boost-1.85
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
449bf360f7 | ||
|
|
5f857d5503 | ||
|
|
9b90f2f6bb | ||
|
|
8f3b819b1e | ||
|
|
4a973c5eb4 | ||
|
|
4c15f217f4 | ||
|
|
e969c57be5 | ||
|
|
16d771f498 | ||
|
|
16a97bb1f5 | ||
|
|
8a0447b486 | ||
|
|
b674d728be | ||
|
|
5b55480c65 | ||
|
|
98789f610a | ||
|
|
c695aa0b32 | ||
|
|
294a4976bd | ||
|
|
2c79036816 | ||
|
|
6b415eaa5c | ||
|
|
11133a4f63 | ||
|
|
b1432d5fa9 | ||
|
|
8a13352854 | ||
|
|
e48f84dcb1 | ||
|
|
ba25324b12 | ||
|
|
df1249f6b8 | ||
|
|
f81c54ced0 | ||
|
|
f23c003c51 | ||
|
|
95a2044e8b | ||
|
|
7738b09132 | ||
|
|
7f5895b3a3 | ||
|
|
245ac56645 | ||
|
|
ec0ea4a338 | ||
|
|
d8a10e2abd | ||
|
|
2674cf4fd4 | ||
|
|
2876b2e793 | ||
|
|
48b9be5070 | ||
|
|
226352be5e | ||
|
|
65bf6b579f | ||
|
|
c82490024c | ||
|
|
552463a4e3 | ||
|
|
642d1f7d23 | ||
|
|
ad7ab1cfc3 | ||
|
|
3438d5e815 | ||
|
|
356e937dd9 | ||
|
|
282e033e4b | ||
|
|
04aef42dcb | ||
|
|
86911e0247 | ||
|
|
f4ebd9d49d | ||
|
|
fc89551a19 | ||
|
|
7e19e45d85 | ||
|
|
53fcd78d4f | ||
|
|
833f32960a | ||
|
|
730f40b6b2 | ||
|
|
67f4fc4398 | ||
|
|
7ba81adbd6 | ||
|
|
defcf22e4d | ||
|
|
9cc76bc277 | ||
|
|
27b9706ac5 | ||
|
|
41e87fbadb | ||
|
|
3f07e7187e | ||
|
|
6dcf66cbd5 | ||
|
|
8794056e20 | ||
|
|
dd8a5277fb | ||
|
|
5a7d6524a7 | ||
|
|
0cb5cf2ae7 | ||
|
|
2c79ac703b | ||
|
|
dbbfa6ea7f | ||
|
|
fcfca74355 | ||
|
|
9b2817a52b | ||
|
|
efd25e9968 | ||
|
|
9b6a0deac6 | ||
|
|
a5b9cd567f | ||
|
|
6e23ed540f | ||
|
|
6f544ceaa7 | ||
|
|
b15196c2e0 | ||
|
|
50c9d6f6e7 | ||
|
|
196aeb6da0 | ||
|
|
fe5a70bac9 | ||
|
|
b5e523f2b3 | ||
|
|
674f3723c5 | ||
|
|
e61fa139b6 | ||
|
|
03e1d768b7 | ||
|
|
963460a3c1 | ||
|
|
275eabb7ed | ||
|
|
2fa9036d56 | ||
|
|
454947de51 | ||
|
|
f09357c1bf | ||
|
|
e8e077c346 | ||
|
|
4a1defaaeb | ||
|
|
b0bf18798c | ||
|
|
9bc057e2a6 | ||
|
|
e460ce2ddc | ||
|
|
d66c0a9551 | ||
|
|
95c06fb7c6 | ||
|
|
ab509a5b32 | ||
|
|
ed28602c2c | ||
|
|
dbc78d7dd9 | ||
|
|
551174b58c | ||
|
|
79b0d65d4f | ||
|
|
2116be9285 | ||
|
|
a9a295e4aa | ||
|
|
2775d19f34 | ||
|
|
633c4bc985 | ||
|
|
b1af355a49 | ||
|
|
ef505f10c3 | ||
|
|
1be5e116f4 | ||
|
|
bca51da20f | ||
|
|
47c6413530 | ||
|
|
52a5a489ba | ||
|
|
fd584a405d | ||
|
|
b6a960757b | ||
|
|
dac40b2153 | ||
|
|
58ce59cf38 | ||
|
|
5010309967 | ||
|
|
bf5bd10b36 | ||
|
|
3279a7b610 | ||
|
|
d7db07e98d | ||
|
|
6a38a07285 | ||
|
|
69a06b98da | ||
|
|
578b5b2ac2 | ||
|
|
f12f35ac1a | ||
|
|
2b4e2922ae | ||
|
|
b2acaacaaf | ||
|
|
ff6c2b87c0 | ||
|
|
2a3ddbfc17 | ||
|
|
5374f9aebc | ||
|
|
968d692c5e | ||
|
|
5c13668343 | ||
|
|
6f853dad2c | ||
|
|
aa5abd8d76 | ||
|
|
ba40d86097 | ||
|
|
7a3a419c35 | ||
|
|
a70d02103a | ||
|
|
d59b6f9520 | ||
|
|
69c5692cd6 | ||
|
|
8f325567eb | ||
|
|
b10c0c66ed | ||
|
|
1bb4ced005 | ||
|
|
58dcb40a49 | ||
|
|
b7d839b851 | ||
|
|
3396cdca9e | ||
|
|
fbafd21118 | ||
|
|
b0aae28eb0 | ||
|
|
9388c4e4c0 | ||
|
|
4e84a5b159 | ||
|
|
7837449ca7 | ||
|
|
9bb809d2a5 | ||
|
|
2a1fd53724 | ||
|
|
cae0eaad61 | ||
|
|
ba10f9bc94 | ||
|
|
8a8b5bc8d3 | ||
|
|
a73f25d3ff | ||
|
|
a24717a4a1 | ||
|
|
10848f71ae | ||
|
|
7d925660bb | ||
|
|
87e77b9b43 | ||
|
|
b331ef58f5 | ||
|
|
5579d11588 | ||
|
|
51f6422c07 | ||
|
|
87c9c2d76c | ||
|
|
d1e7e87a31 | ||
|
|
14185d614f | ||
|
|
0436e48a79 | ||
|
|
4d9294cb1f | ||
|
|
e75c066ddc | ||
|
|
e51a594dbb | ||
|
|
12f2b3a365 | ||
|
|
2a1b206244 | ||
|
|
b4bee46c54 | ||
|
|
444094f20d | ||
|
|
da12b52759 | ||
|
|
94315117fa | ||
|
|
9c812d4217 | ||
|
|
c9674f6164 | ||
|
|
ed82d60966 | ||
|
|
5ffd7f6317 | ||
|
|
81d33f5bc6 | ||
|
|
a6e50ccf07 | ||
|
|
a7b6dd71a6 | ||
|
|
a3adfcf44b | ||
|
|
fbfb8e4abd | ||
|
|
7ac8beae4c | ||
|
|
42d96c04fb | ||
|
|
4301765f61 | ||
|
|
5ce264629c | ||
|
|
994bc05610 | ||
|
|
b14939376d | ||
|
|
861cc9d6af | ||
|
|
2c4bfdbc68 | ||
|
|
3660cf4c83 | ||
|
|
a3c71ae77d | ||
|
|
22f85d8e90 | ||
|
|
be8e2c65bc | ||
|
|
3b967a5fa7 | ||
|
|
33250407db | ||
|
|
8aa4e0712a | ||
|
|
4e05688247 | ||
|
|
b24b7f6d62 | ||
|
|
e94b247698 | ||
|
|
ea4c6e85f7 | ||
|
|
180db174ad | ||
|
|
186d6aacb6 | ||
|
|
5646daebad | ||
|
|
f33c357af6 | ||
|
|
9390106145 | ||
|
|
3b6d3a4cb9 | ||
|
|
638fefedd0 | ||
|
|
2506fbceb8 | ||
|
|
d2e5b44aec | ||
|
|
bbffc61524 | ||
|
|
36c020b032 | ||
|
|
4b38e4a243 | ||
|
|
9ef5a5646d | ||
|
|
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 |
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
|
||||
194
.github/workflows/ci.yml
vendored
Normal file
194
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- feature/**
|
||||
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
|
||||
jobs:
|
||||
posix:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-13
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-22.04
|
||||
- toolset: gcc-12 # Do not remove! It is the only toolset that tests misc/strip_boost_namespace.sh
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-12"
|
||||
- toolset: gcc-11
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-11"
|
||||
- toolset: gcc-10
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-10"
|
||||
- toolset: gcc-9
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-9"
|
||||
- toolset: clang-15
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-22.04
|
||||
# - toolset: clang
|
||||
# cxxstd: "03,11,14,17,2a"
|
||||
# os: macos-10.15
|
||||
# cxxflags: "cxxflags=-fsanitize=address,undefined -fno-sanitize-recover=undefined"
|
||||
# linkflags: "linkflags=-fsanitize=address,undefined"
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=pfr # Note: changed from ${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init --depth 10 --jobs 2 tools/boostdep tools/inspect libs/filesystem
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 3" filesystem
|
||||
rm -rf libs/$LIBRARY/*
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--depth 10 --jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
./b2 -j4 variant=debug tools/inspect/build
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release "${{matrix.cxxflags}}" "${{matrix.linkflags}}" "${{matrix.launcher}}"
|
||||
dist/bin/inspect libs/$LIBRARY
|
||||
|
||||
- name: Test boost namespace stripping
|
||||
if: ${{matrix.toolset == 'gcc-12'}}
|
||||
run: ../boost-root/libs/$LIBRARY/misc/strip_boost_namespace.sh
|
||||
|
||||
- name: Prepare coverage data
|
||||
if: matrix.gcov_tool
|
||||
run: |
|
||||
mkdir -p $GITHUB_WORKSPACE/coveralls
|
||||
|
||||
echo -e "#!/bin/bash\nexec ${{matrix.gcov_tool}} \"\$@\"" > $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
|
||||
chmod +x $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
|
||||
wget https://github.com/linux-test-project/lcov/archive/v1.16.zip
|
||||
unzip v1.16.zip
|
||||
LCOV="`pwd`/lcov-1.16/bin/lcov --gcov-tool $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh"
|
||||
|
||||
echo "$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory `pwd`/libs/$LIBRARY/test --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info"
|
||||
$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory ../boost-root/ --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info
|
||||
$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info "/usr*" "*/$LIBRARY/test/*" ${{matrix.ignore_coverage}} "*/$LIBRARY/tests/*" "*/$LIBRARY/examples/*" "*/$LIBRARY/example/*" -o $GITHUB_WORKSPACE/coveralls/coverage.info
|
||||
|
||||
cd ../boost-root
|
||||
OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$LIBRARY\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
echo $OTHER_LIBS
|
||||
eval "$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info $OTHER_LIBS -o $GITHUB_WORKSPACE/coveralls/coverage.info"
|
||||
|
||||
- name: Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
if: matrix.gcov_tool
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ./coveralls/coverage.info
|
||||
parallel: true
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: msvc-14.0
|
||||
cxxstd: "14,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
threads: "-j3"
|
||||
- toolset: gcc
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
addrmd: 64
|
||||
os: windows-2019
|
||||
threads: "-j3"
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "20,latest"
|
||||
addrmd: 64
|
||||
os: windows-2022
|
||||
threads: "-j1"
|
||||
- toolset: clang-win
|
||||
cxxstd: "14,17,2a,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
set LIBRARY=pfr
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--jobs 3" %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 ${{matrix.threads}} libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
|
||||
|
||||
finish:
|
||||
needs: posix
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.github_token }}
|
||||
parallel-finished: true
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
doc/autodoc*
|
||||
doc/html
|
||||
67
.travis.yml
67
.travis.yml
@@ -1,67 +0,0 @@
|
||||
# Use, modification, and distribution are
|
||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Copyright Antony Polukhin 2014-2016.
|
||||
|
||||
#
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
# and how it can be used with Boost libraries.
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- CXX_STANDARD=c++14 TOOLSET=g++-5
|
||||
- CXX_STANDARD=c++1z TOOLSET=g++-5
|
||||
#- CXX_STANDARD=c++1y TOOLSET=clang++
|
||||
#- CXX_STANDARD=c++14 TOOLSET=clang++-3.7
|
||||
|
||||
|
||||
###############################################################################################################
|
||||
# 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
|
||||
packages:
|
||||
- valgrind
|
||||
- gcc-5
|
||||
- g++-5
|
||||
#- clang
|
||||
#- clang-3.7
|
||||
|
||||
script:
|
||||
- git clone https://github.com/boostorg/core.git ../boost_core
|
||||
- git clone https://github.com/boostorg/assert.git ../boost_assert
|
||||
- git clone https://github.com/boostorg/config.git ../boost_config
|
||||
- git clone https://github.com/boostorg/functional.git ../boost_functional
|
||||
- git clone https://github.com/boostorg/integer.git ../boost_integer
|
||||
- git clone https://github.com/boostorg/type_traits.git ../boost_tt
|
||||
- git clone https://github.com/boostorg/mpl.git ../boost_mpl
|
||||
- git clone https://github.com/boostorg/detail.git ../boost_detail
|
||||
- git clone https://github.com/boostorg/static_assert.git ../boost_sa
|
||||
- git clone https://github.com/boostorg/preprocessor.git ../boost_preprocessor
|
||||
- INCLUDES="-I../boost_core/include/ -I../boost_config/include/ -I../boost_assert/include/ -I../boost_preprocessor/include/ -I../boost_sa/include/ -I../boost_functional/include/ -I../boost_detail/include/ -I../boost_integer/include/ -I../boost_tt/include/ -I../boost_mpl/include/ -I./include/"
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/core.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_chars.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_ints.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_long_longs.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_shorts.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_void_ptrs.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/flat_functions_for.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/global_flat_ops.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/minimal.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/flat_ops.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/std_interactions.cpp && valgrind ./a.out && rm ./a.out
|
||||
|
||||
20
CMakeLists.txt
Normal file
20
CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
# Generated by `boostdep --cmake pfr`
|
||||
# Copyright 2020 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_pfr VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_pfr INTERFACE)
|
||||
add_library(Boost::pfr ALIAS boost_pfr)
|
||||
|
||||
target_include_directories(boost_pfr INTERFACE include)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
||||
|
||||
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.
|
||||
149
README.md
149
README.md
@@ -1,14 +1,54 @@
|
||||
#POD Flat Reflection (Magic Get) [](https://travis-ci.org/apolukhin/magic_get) [](https://travis-ci.org/apolukhin/magic_get)
|
||||
# [Boost.PFR](https://boost.org/libs/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.
|
||||
|
||||
[Boost.PFR](https://boost.org/libs/pfr) is a part of the [Boost C++ Libraries](https://github.com/boostorg). However, Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder from the github into your project, and the library will work fine.
|
||||
|
||||
For a version of the library without `boost::` namespace see [PFR](https://github.com/apolukhin/pfr_non_boost).
|
||||
|
||||
### Test results
|
||||
|
||||
Branches | Build | Tests coverage | More info
|
||||
----------------|-------------- | -------------- |-----------
|
||||
Develop: | [](https://github.com/boostorg/pfr/actions/workflows/ci.yml) [](https://ci.appveyor.com/project/apolukhin/pfr/branch/develop) | [](https://coveralls.io/github/apolukhin/magic_get?branch=develop) | [details...](https://www.boost.org/development/tests/develop/developer/pfr.html)
|
||||
Master: | [](https://github.com/boostorg/pfr/actions/workflows/ci.yml) [](https://ci.appveyor.com/project/apolukhin/pfr/branch/master) | [](https://coveralls.io/github/apolukhin/magic_get?branch=master) | [details...](https://www.boost.org/development/tests/master/developer/pfr.html)
|
||||
|
||||
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/boost_pfr.html)
|
||||
|
||||
### Motivating Example #0
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
```
|
||||
|
||||
[Run the above sample](https://godbolt.org/z/PfYsWKb7v)
|
||||
|
||||
|
||||
[Latest documentation](http://apolukhin.github.com/magic_get/index.html)
|
||||
|
||||
[Pre Boost version](https://github.com/apolukhin/magic_get/tree/pre_boost)
|
||||
|
||||
|
||||
### Motivating example
|
||||
### Motivating Example #1
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include "boost/pfr.hpp"
|
||||
@@ -20,14 +60,11 @@ struct my_struct { // no ostream operator defined!
|
||||
};
|
||||
|
||||
int main() {
|
||||
using namespace boost::pfr::flat_ops; // for ostream operator out-of-the-box for all PODs!
|
||||
|
||||
my_struct s{100, 'H', 3.141593};
|
||||
std::cout << "my_struct has " << boost::pfr::flat_tuple_size<my_struct>::value
|
||||
<< " fields: " << s << "\n";
|
||||
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
|
||||
<< " fields: " << boost::pfr::io(s) << "\n";
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Outputs:
|
||||
@@ -35,17 +72,87 @@ Outputs:
|
||||
my_struct has 3 fields: {100, H, 3.14159}
|
||||
```
|
||||
|
||||
### Motivating Example #2
|
||||
|
||||
```c++
|
||||
#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
|
||||
<< " fields: " << boost::pfr::io(s) << "\n";
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Outputs:
|
||||
```
|
||||
my_struct has 2 fields: {"Das ist fantastisch!", 100}
|
||||
```
|
||||
|
||||
### Motivating Example #3
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
#include <boost/fusion/include/adapt_boost_pfr.hpp>
|
||||
|
||||
#include "boost/pfr/io.hpp"
|
||||
|
||||
namespace x3 = boost::spirit::x3;
|
||||
|
||||
struct ast_employee { // No BOOST_FUSION_ADAPT_STRUCT defined
|
||||
int age;
|
||||
std::string forename;
|
||||
std::string surname;
|
||||
double salary;
|
||||
};
|
||||
|
||||
auto const quoted_string = x3::lexeme['"' >> +(x3::ascii::char_ - '"') >> '"'];
|
||||
|
||||
x3::rule<class employee, ast_employee> const employee = "employee";
|
||||
auto const employee_def =
|
||||
x3::lit("employee")
|
||||
>> '{'
|
||||
>> x3::int_ >> ','
|
||||
>> quoted_string >> ','
|
||||
>> quoted_string >> ','
|
||||
>> x3::double_
|
||||
>> '}'
|
||||
;
|
||||
BOOST_SPIRIT_DEFINE(employee);
|
||||
|
||||
int main() {
|
||||
std::string str = R"(employee{34, "Chip", "Douglas", 2500.00})";
|
||||
ast_employee emp;
|
||||
x3::phrase_parse(str.begin(),
|
||||
str.end(),
|
||||
employee,
|
||||
x3::ascii::space,
|
||||
emp);
|
||||
std::cout << boost::pfr::io(emp) << std::endl;
|
||||
}
|
||||
|
||||
```
|
||||
Outputs:
|
||||
```
|
||||
(34 Chip Douglas 2500)
|
||||
```
|
||||
|
||||
|
||||
### Requirements and Limitations
|
||||
|
||||
* C++14 compatible compiler (GCC-5.0+, Clang, ...)
|
||||
* Static variables are ignored
|
||||
|
||||
C++14 limitations (C++17 fixes those):
|
||||
* 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
|
||||
[See docs](https://www.boost.org/doc/libs/develop/doc/html/boost_pfr.html).
|
||||
|
||||
### License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
Distributed under the [Boost Software License, Version 1.0](https://boost.org/LICENSE_1_0.txt).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright Antony Polukhin 2016.
|
||||
# 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)
|
||||
@@ -6,12 +6,21 @@
|
||||
using quickbook ;
|
||||
using boostbook ;
|
||||
using doxygen ;
|
||||
using xsltproc ;
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
[ glob ../../../boost/pfr.hpp ]
|
||||
[ glob ../../../boost/pfr/*.hpp ]
|
||||
:
|
||||
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
|
||||
@@ -21,21 +30,43 @@ doxygen autodoc
|
||||
<doxygen:param>INLINE_SIMPLE_STRUCTS=YES
|
||||
<doxygen:param>SORT_MEMBER_DOCS=NO
|
||||
<doxygen:param>"ALIASES= \\
|
||||
\"flattening{1}=\\xmlonly<link linkend='boost_pod_flat_reflection.quick_start.flattening'>\\1</link>\\endxmlonly\" \\
|
||||
\"podops=\\b See \\b Also: \\xmlonly<link linkend='boost_pod_flat_reflection.quick_start.three_ways_of_getting_operators'>Three ways of getting operators</link>\\endxmlonly\" \\
|
||||
"
|
||||
<doxygen:param>"PREDEFINED=\"BOOST_PFR_DOXYGEN_INVOKED\" \\
|
||||
\"detail::stl_type_info=std::type_info\""
|
||||
<xsl:param>"boost.doxygen.reftitle=Boost.PFR Header Reference"
|
||||
;
|
||||
|
||||
xml pfr : pfr.qbk : <dependency>autodoc ;
|
||||
boostbook standalone
|
||||
:
|
||||
pfr
|
||||
:
|
||||
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_61_0
|
||||
# <xsl:param>boost.root=../../../..
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
|
||||
\"forcedlink{1}=\\xmlonly<link linkend='boost.pfr.\\1'>\\endxmlonly boost::pfr::\\1\\xmlonly</link>\\endxmlonly\" \\
|
||||
\"podops=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.three_ways_of_getting_operators'>\\endxmlonly 'Three ways of getting operators' \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"fnrefl=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.reflection_of_field_name'>\\endxmlonly 'Reflection of field names' \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"customio=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.custom_printing_of_aggregates'>\\endxmlonly 'Custom printing of aggregates' \\xmlonly</link>\\endxmlonly for info on how to implement your own manipulator with custom format.\" \\
|
||||
\"aggregate=\\xmlonly<link linkend='boost_pfr.limitations_and_configuration'>\\endxmlonly simple aggregate \\xmlonly</link>\\endxmlonly\" \\
|
||||
"
|
||||
<doxygen:param>"PREDEFINED= \\
|
||||
\"BOOST_PFR_DOXYGEN_INVOKED=1\" \\
|
||||
"
|
||||
;
|
||||
|
||||
doxygen autodoc_pfr
|
||||
:
|
||||
[ glob ../../../boost/pfr.hpp ]
|
||||
[ glob ../../../boost/pfr/*.hpp ]
|
||||
:
|
||||
$(doxygen_params)
|
||||
<xsl:param>"boost.doxygen.reftitle=Reference Section of PFR"
|
||||
;
|
||||
|
||||
boostbook pfr-doc
|
||||
:
|
||||
pfr.qbk
|
||||
:
|
||||
<dependency>autodoc_pfr
|
||||
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_81_0
|
||||
#<xsl:param>boost.root=../../../.
|
||||
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: pfr-doc/<format>docbook
|
||||
:
|
||||
:
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
|
||||
|
||||
594
doc/pfr.qbk
594
doc/pfr.qbk
@@ -1,7 +1,7 @@
|
||||
[library Boost.POD Flat Reflection
|
||||
[library Boost.PFR
|
||||
[quickbook 1.6]
|
||||
[version 1.0]
|
||||
[copyright 2016 Antony Polukhin]
|
||||
[version 2.2]
|
||||
[copyright 2016-2024 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -10,176 +10,598 @@
|
||||
]
|
||||
]
|
||||
|
||||
[section Motivation]
|
||||
[section Intro]
|
||||
|
||||
In C++ we have:
|
||||
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:
|
||||
|
||||
* tuples - types that provide access to members by index. Those are useful for generic programming.
|
||||
* PODs - types with named fields that do not provide access to members by index. Those are just easy to use.
|
||||
[import ../example/motivating_example0.cpp]
|
||||
[pfr_motivating_example]
|
||||
|
||||
This library provides tuple like methods for POD types, making PODs usable in contexts were only tuples were useful.
|
||||
Experiment with the sample [@https://godbolt.org/z/PfYsWKb7v online].
|
||||
See [link boost_pfr.limitations_and_configuration [*limitations]].
|
||||
|
||||
[note All you have to do is to add `#include <boost/pfr.hpp>`.
|
||||
|
||||
No macro or other type/member registrations required.]
|
||||
[h2 Usecase example]
|
||||
|
||||
Boost.POD Flat Reflection (Boost.PFR) adds following out-of-the-box functionality to PODs:
|
||||
Imagine that you are writing the wrapper library for a database. Depending on the usage of Boost.PFR users code will look differently:
|
||||
|
||||
* comparison operators
|
||||
[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)",
|
||||
friend_info.id, //////////////////////////////////////////////////////
|
||||
friend_info.name, // Users are forced to enumerate fields because your
|
||||
friend_info.email, // library can not iterate over the fields of a user
|
||||
friend_info.login // provided structure
|
||||
);
|
||||
|
||||
return friend_info;
|
||||
}
|
||||
```
|
||||
][
|
||||
```
|
||||
#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 ////////////////////////////////////////
|
||||
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 //////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
```
|
||||
]]
|
||||
]
|
||||
|
||||
|
||||
Imagine that you are writing a serialization library. Serialization of user
|
||||
provided structures (and nested structures) with Boost.PFR it is just as simple as:
|
||||
|
||||
```
|
||||
void Write(Writer& writer, int value);
|
||||
void Write(Writer& writer, std::string_view value);
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<boost::pfr::is_implicitly_reflectable_v<T>> Write(Writer& writer, const T& value) {
|
||||
boost::pfr::for_each_field(
|
||||
value, [&writer](const auto& field) { Write(writer, field); });
|
||||
}
|
||||
```
|
||||
|
||||
With Boost.PFR the code is shorter, more readable and more pleasant to write.
|
||||
|
||||
[note All the above examples were inspired by the Boost.PFR usage in [@https://github.com/userver-framework/userver 🐙 userver framework].]
|
||||
|
||||
|
||||
[h2 Out of the box functionality ]
|
||||
|
||||
Boost.PFR adds the following out-of-the-box functionality for aggregate initializable structures:
|
||||
|
||||
* comparison functions
|
||||
* heterogeneous comparators
|
||||
* hash
|
||||
* stream operators
|
||||
* access to members by index
|
||||
* member reflections
|
||||
* methods for cooperation with `std::tuple`
|
||||
* IO streaming
|
||||
* access to members by index or type
|
||||
* access to member's names by index
|
||||
* member type retrieval
|
||||
* methods for cooperation with `std::tuple` for members
|
||||
* methods for cooperation with `std::array` for member's names
|
||||
* methods to visit each field of the structure
|
||||
* trait to detect potential ability to reflect type, and ability to override trait's decision in user-side code
|
||||
|
||||
[warning This is not an official Boost library! It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library to formal review, if community think that it is interesting!]
|
||||
Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder [@https://github.com/boostorg/pfr from the Boost.PFR github] into your project, and the library will work fine. For a version of the library without `boost::` namespace see [@https://github.com/apolukhin/pfr_non_boost PFR].
|
||||
|
||||
[caution This is a C++14 library! Pre C++14 compilers (C++11, C++03...) are not supported]
|
||||
[caution Recommended C++ Standards are C++20 and above. C++17 completely enough for a user who doesn't want accessing name of structure member. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Quick Start]
|
||||
|
||||
[import ../example/examples.cpp]
|
||||
[section Short Examples for the Impatient]
|
||||
|
||||
[section Accessing POD member by index] [pfr_example_get] [endsect]
|
||||
[section Flattening] [pfr_example_flattening] [pfr_example_flattening_2] [endsect]
|
||||
[/ [section Counting fields] [pfr_example_flat_tuple_size] [endsect] ]
|
||||
[section Three ways of getting operators ]
|
||||
[import ../example/quick_examples.cpp]
|
||||
|
||||
There are three ways to start using Boost.PFR hashing, comparison and streaming operators for type `T` in your code. Each method has it's own drawbacks and suits own cases.
|
||||
|
||||
[table:flat_ops_comp Different approaches for operators
|
||||
[[ Approach ] [ Defines operators in global namespace ]
|
||||
[ Defined operators could be found by ADL ]
|
||||
[ Works for local types ]
|
||||
[ Usable localy, without affecting code from other scopes ]
|
||||
[ Ignores implicit conversion operators ]
|
||||
[ Respects user defined operators ] ]
|
||||
[[ [headerref boost/pfr/flat_ops.hpp] ] [ no ] [ no ] [ yes ] [ yes ] [ no ] [ yes ] ]
|
||||
[[ [headerref boost/pfr/flat_functions_for.hpp] ] [ yes if T is in it ] [ yes ] [ no ] [ no, but could be limited to translation unit ] [ yes for T ] [ no (compile time error) ] ]
|
||||
[[ [headerref boost/pfr/global_flat_ops.hpp] ] [ yes ] [ yes ] [ yes ] [ no, but could be limited to translation unit ] [ yes all ] [ yes ] ]
|
||||
[table:quick_examples
|
||||
[[ Code snippet ] [ Reference: ]]
|
||||
[
|
||||
[ [pfr_quick_examples_get] ]
|
||||
[ [funcref boost::pfr::get] ]
|
||||
][
|
||||
[ [pfr_quick_examples_get_name] ]
|
||||
[ [funcref boost::pfr::get_name] ]
|
||||
][
|
||||
[ [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]
|
||||
[import ../example/get_name.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;
|
||||
};
|
||||
```
|
||||
]]
|
||||
]
|
||||
|
||||
More detailed description:
|
||||
Definition via aggregate initializable structure is much more clear. Same story with usages: `return std::get<1>(value);` vs. `return value.session_id;`.
|
||||
|
||||
[*1) [headerref boost/pfr/flat_ops.hpp] approach]
|
||||
Another advantage of aggregates is a more efficient copy, move construction and assignments.
|
||||
|
||||
This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there's no operators defined for the type:
|
||||
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/flat_ops.hpp>
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
template <class T>
|
||||
struct uniform_comparator_less {
|
||||
bool operator()(const T& lhs, const T& rhs) const noexcept {
|
||||
using namespace flat_ops; // Enables Boost.PFR operators usage in this scope.
|
||||
return lhs < rhs; // If T has operator< or conversion operator then will use it, otherwise will use boost::pfr::flat_less<T>.
|
||||
// If T has operator< or conversion operator then it is used.
|
||||
return boost::pfr::lt(lhs, rhs);
|
||||
}
|
||||
};
|
||||
```
|
||||
This method's effects are local to the function. It works even for local types, like structures defined in functions.
|
||||
However *Argument Dependant Lookup* does not work with it:
|
||||
This methods effects are local to the function. It works even for local types, like structures defined in functions.
|
||||
|
||||
```
|
||||
#include <boost/pfr/flat_ops.hpp>
|
||||
template <class T>
|
||||
struct uniform_comparator_less {
|
||||
bool operator()(const T& lhs, const T& rhs) const noexcept {
|
||||
using namespace flat_ops;
|
||||
return std::less{}(lhs, rhs); // Compile time error if T has neither operator< nor conversion operator to comparable type.
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
[*2) [headerref boost/pfr/flat_functions_for.hpp] approach]
|
||||
[*2. BOOST_PFR_FUNCTIONS_FOR(T) approach]
|
||||
|
||||
This method is good if you're writing POD structure and wish to define operators for that structure.
|
||||
This method is good if you're writing a structure and wish to define operators for that structure.
|
||||
```
|
||||
#include <boost/pfr/flat_functions_for.hpp>
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
struct pair_like {
|
||||
int first;
|
||||
short second;
|
||||
};
|
||||
|
||||
BOOST_PFR_FLAT_FUNCTIONS_FOR(pair_like) // Defines operators
|
||||
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_FLAT_FUNCTIONS_FOR BOOST_PFR_FLAT_FUNCTIONS_FOR(T)]
|
||||
can not be used for local types, it must be called only once in namespace of `T`. It does not respect conversion operators of `T`, so for example the following code
|
||||
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/flat_functions_for.hpp>
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
struct empty {
|
||||
operator std::string() { return "empty{}"; }
|
||||
};
|
||||
// Uncomment to get different output:
|
||||
// BOOST_PFR_FLAT_FUNCTIONS_FOR(empty)
|
||||
// BOOST_PFR_FUNCTIONS_FOR(empty)
|
||||
|
||||
// ...
|
||||
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FLAT_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
|
||||
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
|
||||
```
|
||||
|
||||
[*3) [headerref boost/pfr/global_flat_ops.hpp] approach]
|
||||
[*3. `eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields, io_fields` approach]
|
||||
|
||||
This approach is for those, who wish to have comparisong/streaming/hashing for all their types.
|
||||
This method is good if you're willing to provide only some operators for your type:
|
||||
|
||||
```
|
||||
#include <boost/pfr/global_flat_ops.hpp>
|
||||
#include <boost/pfr/io_fields.hpp>
|
||||
|
||||
struct pair_like {
|
||||
int first;
|
||||
short second;
|
||||
std::string second;
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
assert(pair_like{1, 2} < pair_like{1, 3});
|
||||
inline std::ostream& operator<<(std::ostream& os, const pair_like& x) {
|
||||
return os << bost::pfr::io_fields(x);
|
||||
}
|
||||
```
|
||||
Argument Dependant Lookup works well, `std::less` will find the operators for `struct pair_like`. Operators for local types will be also defined.
|
||||
*All conversion operators of all POD types won't be used during comparisons/streaming/hashing.*
|
||||
|
||||
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]
|
||||
|
||||
|
||||
[section Requirements and Limitations]
|
||||
[section Reflection of field name ]
|
||||
|
||||
[note Boost.PFR does not depend on any Boost library. You may use it's headers even without Boost. ]
|
||||
[pfr_example_get_name]
|
||||
|
||||
See [link boost_pfr.limitations_and_configuration [*Limitations and Configuration]].
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Limitations and Configuration]
|
||||
|
||||
[caution Recommended C++ Standards are C++20 and above. C++17 completely enough for a user who doesn't want accessing name of structure member. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
|
||||
|
||||
Boost.PFR library works with types that satisfy the requirements of `SimpleAggregate`: aggregate types without base classes, `const` fields, references, or C arrays:
|
||||
|
||||
```
|
||||
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.
|
||||
|
||||
Boost.PFRs extraction of field name works with only `SimpleAggregate` types.
|
||||
|
||||
|
||||
[h2 Configuration Macro]
|
||||
|
||||
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
|
||||
[table:linkmacro Macros
|
||||
[[Macro name] [Effect]]
|
||||
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to override Boost.PFR choice and use C++17 structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++17 structured bindings usage.]]
|
||||
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]]
|
||||
[[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use Boost.PFR version of that metafunction. Define to `1` to override Boost.PFR detection logic. ]]
|
||||
[[*BOOST_PFR_HAS_GUARANTEED_COPY_ELISION*] [Define to `0` if your compiler does not implement C++17 guaranteed copy elision properly and fails to reflect aggregates with non-movable fields. Define to `1` to override Boost.PFR detection logic. ]]
|
||||
[[*BOOST_PFR_ENABLE_IMPLICIT_REFLECTION*] [Define to `0` if you are hit by lots of non-effective choices made by implicitly reflection. Define to `1` to override Boost.PFR detection logic. ]]
|
||||
[[*BOOST_PFR_CORE_NAME_ENABLED*] [On platforms where field name extraction is not supported, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_CORE_NAME_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the ability to get a field name. ]]
|
||||
[[*BOOST_PFR_FUNCTION_SIGNATURE*] [For known compilers defined to a compiler specific macro, that outputs the whole function signature including non-type template parameters. ]]
|
||||
[[*BOOST_PFR_CORE_NAME_PARSING*] [Describes extraction of field name from BOOST_PFR_FUNCTION_SIGNATURE macro. See details below. ]]
|
||||
[[*BOOST_PFR_ENABLED*] [On platforms where Boost.PFR is not supported, the `boost/pfr/config.hpp` header defines the BOOST_PFR_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the Boost.PFR library. ]]
|
||||
]
|
||||
|
||||
|
||||
[h2 Details on Limitations]
|
||||
|
||||
The Boost.PFRs reflection has some limitations that depend on a C++ Standard and compiler capabilities:
|
||||
|
||||
* Boost.PFR *requires C++14 compatible compiler* (GCC-5.0+, Clang, ...)
|
||||
* Static variables are ignored
|
||||
* T must be aggregate initializable
|
||||
* T must be aggregate initializable without base classes
|
||||
* if T contains C arrays then the result of reflection may differ depending on the C++ version and library configuration
|
||||
* Additional limitations if [*BOOST_PFR_USE_CPP17 == 0]:
|
||||
* Non of the member fields should have a template constructor from one parameter.
|
||||
* Additional limitations if [*BOOST_PFR_USE_LOOPHOLE == 0]:
|
||||
* T must be constexpr aggregate initializable and all its fields must be constexpr default constructible
|
||||
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/core.hpp boost::pfr::tuple_element] require T to be a POD type with built-in types only.
|
||||
|
||||
C++14 limitations (C++17 fixes those):
|
||||
* 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
|
||||
* All the methods that provide access to filds have a `reinterpret_cast` to an unrelated type. All the possible efforts and compiler scpecific tricks were used to avoid issues. But strictly speaking *this is an Undefined Behavior.
|
||||
The Boost.PFRs extraction of field name has some limitations that depend on a C++ Standard and compiler capabilities:
|
||||
|
||||
* T should be usable like `extern T t;`, i.e. has a non-internal linkage.
|
||||
|
||||
[h2 Adjusting BOOST_PFR_CORE_NAME_PARSING]
|
||||
|
||||
`BOOST_PFR_CORE_NAME_PARSING` is already set up for most of the popular compilers. You need to adjust it only
|
||||
if some static_assert in the library complained on `BOOST_PFR_CORE_NAME_PARSING`.
|
||||
|
||||
To do that:
|
||||
|
||||
# Build `test/core_name/print_name.cpp` with your compiler and run it
|
||||
# Define BOOST_PFR_CORE_NAME_PARSING to `(skip_at_begin, skip_at_end, "")`, where
|
||||
* `skip_at_begin` is equal to characters count before the first occurrence of `user_defined_field` in output
|
||||
* `skip_at_end` is equal to characters count after last occurrence of `user_defined_field` in output
|
||||
# Check that `test/core_name/print_name.cpp` returns "user_defined_field"
|
||||
# If it does not return `user_defined_field`, then define BOOST_PFR_CORE_NAME_PARSING to `(skip_at_begin, skip_at_end, "T = ")`, where
|
||||
* `skip_at_begin` is equal to `skip_at_begin` at step 2
|
||||
* `skip_at_end` is equal to `skip_at_end` at step 2
|
||||
* `"T = "` is equal to characters that are right before the `user_defined_field` in output, use `backward("T = ")` to search for the occurange in the string from the right
|
||||
# (optional, but highly recommended) [@https://github.com/boostorg/pfr/issues create ticket] with
|
||||
feature request to add your compiler to supported compilers list. Include
|
||||
parameters provided to `BOOST_PFR_CORE_NAME_PARSING` macro [*and] the initial output of `test/core_name/print_name.cpp`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section How it works]
|
||||
|
||||
[h2 Fields count detection and getting references to members]
|
||||
|
||||
Short description:
|
||||
|
||||
* at compile-time: uses aggregate initialization to detect fields count in user-provided structure
|
||||
* at compile-time: makes a structure that is convertible to anything and remeber types it has been converted to during aggregate initialization of user-provided structure
|
||||
* at compile-time: creates a tuple with exactly the same layout as in user-provided structure
|
||||
* at run-time: `reinterpret_cast`s pointer to user-provided structure to the tuple pointer => all the tuple methods are available for the structure
|
||||
# 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: [@https://www.youtube.com/watch?v=abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling. ].
|
||||
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].
|
||||
|
||||
[h2 Field name retrieval]
|
||||
|
||||
# at compile-time:
|
||||
* Get references to members of an object of type `T` in `constexpr` function
|
||||
* Feed the reference from previous as a template parameter to a `constexpr` function with `template <auto member_ptr>`.
|
||||
That function returns `__PRETTY_FUNCTION__` or some other vendor specific macro that prints the whole name of a function
|
||||
along with the template arguments.
|
||||
* The returned value from previous step contains the member name ([@https://godbolt.org/z/K4aWdcE9G godbolt example]). Do some
|
||||
compiler specific parsing of the value and make a `std::string_view` that contains only the member name.
|
||||
# at run-time: return the `std::string_view` with the member name.
|
||||
|
||||
[endsect]
|
||||
|
||||
[xinclude autodoc.xml]
|
||||
[section Acknowledgements]
|
||||
|
||||
Many thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/boostorg/pfr/issues/5 Manual type registering/structured bindings might be unnecessary].
|
||||
|
||||
Many thanks to Alexandr Poltavsky for initial implementation the [*BOOST_PFR_USE_LOOPHOLE == 1] technique and for describing it [@http://alexpolt.github.io/type-loophole.html in his blog].
|
||||
|
||||
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]
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// Copyright 2016 Antony Polukhin
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See the accompanying file LICENSE_1_0.txt
|
||||
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//[pfr_example_get
|
||||
/*`
|
||||
The following example shows how to access structure fields by index using [funcref boost::pfr::flat_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::flat_get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer`
|
||||
auto& r2 = boost::pfr::flat_get<1>(f); // accessing field with index 1, returns reference to `foo::c`
|
||||
//] [/pfr_example_get]
|
||||
|
||||
//[pfr_example_flat_tuple_size
|
||||
/*`
|
||||
The following example shows how to count fields using [classref boost::pfr::flat_tuple_size].
|
||||
*/
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
struct foo2 { // defining structure
|
||||
int some_integer;
|
||||
char c;
|
||||
short some_other_field;
|
||||
};
|
||||
|
||||
|
||||
static_assert(
|
||||
boost::pfr::flat_tuple_size<foo2>::value // returns total count of fields in `foo2`
|
||||
== 3, ""
|
||||
);
|
||||
|
||||
static_assert(
|
||||
boost::pfr::flat_tuple_size<int[100]>::value // works with arrays too!
|
||||
== 100, ""
|
||||
);
|
||||
//] [/pfr_example_flat_tuple_size]
|
||||
|
||||
|
||||
|
||||
//[pfr_example_flattening
|
||||
/*`
|
||||
[warning All the functions and metafunctions in Boost.PFR that start with `flat_` represent template parameter type as flat structure without static members! ]
|
||||
|
||||
Take a look at the `struct my_struct`:
|
||||
*/
|
||||
|
||||
struct my_struct_nested { short a1; int a2; };
|
||||
|
||||
struct my_struct {
|
||||
int a0;
|
||||
static const int cvalue = 1000;
|
||||
my_struct_nested nested;
|
||||
short a3_a4[2];
|
||||
};
|
||||
|
||||
/*` It will be flattened and represented as: */
|
||||
|
||||
struct my_struct_flat {
|
||||
int a0;
|
||||
short a1;
|
||||
int a2;
|
||||
short a3;
|
||||
short a4;
|
||||
};
|
||||
//] [/pfr_example_flattening]
|
||||
|
||||
void example_get() {
|
||||
//[pfr_example_flattening_2
|
||||
/*`
|
||||
It means, that:
|
||||
*/
|
||||
boost::pfr::flat_get<2>(my_struct{}); // ... will return `my_struct::my_struct_nested::a2` field.
|
||||
boost::pfr::flat_get<3>(my_struct{}); // ... will return `my_struct::a3_a4[0]` field.
|
||||
|
||||
/*` Exactly the same story with arrays: */
|
||||
|
||||
int i[2][2] = {{10, 11}, {12, 13} };
|
||||
const int& r = boost::pfr::flat_get<1>(i);
|
||||
assert(r == 11);
|
||||
//] [/pfr_example_flattening_2]
|
||||
(void)r;
|
||||
}
|
||||
|
||||
int main() {
|
||||
example_get();
|
||||
}
|
||||
42
example/get.cpp
Normal file
42
example/get.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2016-2024 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;
|
||||
}
|
||||
43
example/get_name.cpp
Normal file
43
example/get_name.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#include <boost/pfr/config.hpp>
|
||||
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17
|
||||
//[pfr_example_get_name
|
||||
/*`
|
||||
Since C++20 it's possible to read name of a structure field by index using Boost.PFR library.
|
||||
The following example shows how to do it using [funcref boost::pfr::get_name].
|
||||
|
||||
Let's define some structure:
|
||||
*/
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct foo { // defining structure
|
||||
int some_integer;
|
||||
char c;
|
||||
};
|
||||
|
||||
/*`
|
||||
We can access field's names of that structure by index:
|
||||
*/
|
||||
constexpr std::string_view n1 = boost::pfr::get_name<0, foo>(); // returns "some_integer"
|
||||
constexpr std::string_view n2 = boost::pfr::get_name<1, foo>(); // returns "c"
|
||||
//] [/pfr_example_get_name]
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17
|
||||
if (n1 != "some_integer") return 1;
|
||||
if (n2 != "c") return 2;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
26
example/motivating_example0.cpp
Normal file
26
example/motivating_example0.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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}
|
||||
}
|
||||
//]
|
||||
211
example/quick_examples.cpp
Normal file
211
example/quick_examples.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright 2016-2024 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>
|
||||
|
||||
// boost-no-inspect
|
||||
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 variable 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/type and assign new value to that field
|
||||
|
||||
struct sample {
|
||||
char c;
|
||||
float f;
|
||||
};
|
||||
|
||||
sample var{};
|
||||
boost::pfr::get<1>(var) = 42.01f;
|
||||
boost::pfr::get<char>(var) = 'A';
|
||||
|
||||
std::cout << var.c << var.f; // Outputs: A 42.01
|
||||
//]
|
||||
}
|
||||
|
||||
// Disabling for MSVC as it gives a hard error on using local types:
|
||||
//
|
||||
// error C7631:
|
||||
// 'boost::pfr::detail::do_not_use_PFR_with_local_types<test_examples::sample>':
|
||||
// variable with internal linkage declared but not defined
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17 && !defined(_MSC_VER)
|
||||
{
|
||||
//[pfr_quick_examples_get_name
|
||||
// Get name of field by index
|
||||
|
||||
struct sample {
|
||||
int f_int;
|
||||
long f_long;
|
||||
};
|
||||
|
||||
std::cout << boost::pfr::get_name<0, sample>()
|
||||
<< boost::pfr::get_name<1, sample>(); // Outputs: f_int f_long
|
||||
//]
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
{
|
||||
//[pfr_quick_examples_structure_to_tuple
|
||||
// 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-2024 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;
|
||||
}
|
||||
@@ -1,16 +1,25 @@
|
||||
// Copyright (c) 2016 Antony Polukhin
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#pragma once
|
||||
#ifndef BOOST_PFR_HPP
|
||||
#define BOOST_PFR_HPP
|
||||
|
||||
/// \file boost/pfr.hpp
|
||||
/// Includes all the Boost.PFR headers, except \xmlonly<link linkend='header.boost.pfr.global_flat_ops_hpp'>boost/pfr/global_flat_ops.hpp</link>\endxmlonly
|
||||
/// Includes all the Boost.PFR headers
|
||||
|
||||
#include <boost/pfr/config.hpp>
|
||||
#include <boost/pfr/core.hpp>
|
||||
//#include <boost/pfr/core17.hpp>
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
#include <boost/pfr/functors.hpp>
|
||||
#include <boost/pfr/flat_ops.hpp>
|
||||
#include <boost/pfr/flat_functions_for.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>
|
||||
#include <boost/pfr/traits_fwd.hpp>
|
||||
#include <boost/pfr/traits.hpp>
|
||||
|
||||
#endif // BOOST_PFR_HPP
|
||||
|
||||
148
include/boost/pfr/config.hpp
Normal file
148
include/boost/pfr/config.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_CONFIG_HPP
|
||||
#define BOOST_PFR_CONFIG_HPP
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus >= 201402L || (defined(_MSC_VER) && defined(_MSVC_LANG) && _MSC_VER > 1900)
|
||||
#include <type_traits> // to get non standard platform macro definitions (__GLIBCXX__ for example)
|
||||
#endif
|
||||
|
||||
/// \file boost/pfr/config.hpp
|
||||
/// Contains all the macros that describe Boost.PFR configuration, like BOOST_PFR_ENABLED
|
||||
///
|
||||
/// \note This header file doesn't require C++14 Standard and supports all C++ compilers, even pre C++14 compilers (C++11, C++03...).
|
||||
|
||||
// Reminder:
|
||||
// * MSVC++ 14.2 _MSC_VER == 1927 <- Loophole is known to work (Visual Studio ????)
|
||||
// * MSVC++ 14.1 _MSC_VER == 1916 <- Loophole is known to NOT work (Visual Studio 2017)
|
||||
// * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
|
||||
// * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
|
||||
|
||||
#ifdef BOOST_PFR_NOT_SUPPORTED
|
||||
# error Please, do not set BOOST_PFR_NOT_SUPPORTED value manually, use '-DBOOST_PFR_ENABLED=0' instead of it
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# if !defined(_MSVC_LANG) || _MSC_VER <= 1900
|
||||
# define BOOST_PFR_NOT_SUPPORTED 1
|
||||
# endif
|
||||
#elif __cplusplus < 201402L
|
||||
# define BOOST_PFR_NOT_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_LOOPHOLE
|
||||
# if defined(_MSC_VER)
|
||||
# if _MSC_VER >= 1927
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# endif
|
||||
# elif defined(__clang_major__) && __clang_major__ >= 8
|
||||
# define BOOST_PFR_USE_LOOPHOLE 0
|
||||
# else
|
||||
# define BOOST_PFR_USE_LOOPHOLE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_CPP17
|
||||
# ifdef __cpp_structured_bindings
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# elif defined(_MSVC_LANG)
|
||||
# if _MSVC_LANG >= 201703L
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_PFR_USE_CPP17 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (!BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_LOOPHOLE)
|
||||
# if (defined(_MSC_VER) && _MSC_VER < 1916) ///< in Visual Studio 2017 v15.9 PFR library with classic engine normally works
|
||||
# define BOOST_PFR_NOT_SUPPORTED 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE
|
||||
// Assume that libstdc++ since GCC-7.3 does not have linear instantiation depth in std::make_integral_sequence
|
||||
# if defined( __GLIBCXX__) && __GLIBCXX__ >= 20180101
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
# elif defined(_MSC_VER)
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
//# elif other known working lib
|
||||
# else
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
# if defined(__cpp_guaranteed_copy_elision) && (!defined(_MSC_VER) || _MSC_VER > 1928)
|
||||
# define BOOST_PFR_HAS_GUARANTEED_COPY_ELISION 1
|
||||
# else
|
||||
# define BOOST_PFR_HAS_GUARANTEED_COPY_ELISION 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
|
||||
# if defined(__cpp_lib_is_aggregate)
|
||||
# define BOOST_PFR_ENABLE_IMPLICIT_REFLECTION 1
|
||||
# else
|
||||
// There is no way to detect potential ability to be reflectable without std::is_aggregare
|
||||
# define BOOST_PFR_ENABLE_IMPLICIT_REFLECTION 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_CORE_NAME_ENABLED
|
||||
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L))
|
||||
# if (defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911) \
|
||||
|| (defined(__clang_major__) && __clang_major__ >= 12)
|
||||
# define BOOST_PFR_CORE_NAME_ENABLED 1
|
||||
# else
|
||||
# define BOOST_PFR_CORE_NAME_ENABLED 0
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_PFR_CORE_NAME_ENABLED 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_PFR_CORE_NAME_PARSING
|
||||
# if defined(_MSC_VER) && !defined(__clang__)
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (sizeof("auto __cdecl boost::pfr::detail::name_of_field_impl<") - 1, sizeof(">(void) noexcept") - 1, backward("->"))
|
||||
# elif defined(__clang__)
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (sizeof("auto boost::pfr::detail::name_of_field_impl() [MsvcWorkaround = ") - 1, sizeof("}]") - 1, backward("."))
|
||||
# elif defined(__GNUC__)
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (sizeof("consteval auto boost::pfr::detail::name_of_field_impl() [with MsvcWorkaround = ") - 1, sizeof(")]") - 1, backward("::"))
|
||||
# else
|
||||
// Default parser for other platforms... Just skip nothing!
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (0, 0, "")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(maybe_unused)
|
||||
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_MAYBE_UNUSED
|
||||
# define BOOST_PFR_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_ENABLED
|
||||
# ifdef BOOST_PFR_NOT_SUPPORTED
|
||||
# define BOOST_PFR_ENABLED 0
|
||||
# else
|
||||
# define BOOST_PFR_ENABLED 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#undef BOOST_PFR_NOT_SUPPORTED
|
||||
|
||||
#endif // BOOST_PFR_CONFIG_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,175 +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)
|
||||
|
||||
|
||||
#ifndef BOOST_PFR_CORE17_HPP
|
||||
#define BOOST_PFR_CORE17_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
|
||||
# include <boost/pfr/detail/core17_generated.hpp>
|
||||
#else
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
template <class T>
|
||||
constexpr auto as_tuple(T&& val) noexcept {
|
||||
static_assert(!sizeof(val), "C++17 required for this function");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using as_tuple_t = decltype( ::boost::pfr::detail::as_tuple(std::declval<T&>()) );
|
||||
}}} // namespace boost::pfr::detail
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// \brief Returns reference or const reference to a field with index `I` in aggregate T.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \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::as_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(T& val) noexcept {
|
||||
return detail::sequence_tuple::get<I>( detail::as_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \brief `tuple_element` has a `typedef type-of-a-field-with-index-I-in-aggregate-T type;`
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \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::teleport_extents<
|
||||
T,
|
||||
typename detail::sequence_tuple::tuple_element<I, detail::as_tuple_t<T> >::type
|
||||
>;
|
||||
|
||||
|
||||
/// \brief Type of a field with index `I` in aggregate `T`.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::vector< boost::pfr::tuple_element_t<0, my_structure> > v;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
using tuple_element_t = typename tuple_element<I, T>::type;
|
||||
|
||||
|
||||
/// \brief Creates an `std::tuple` from an aggregate T.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \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 {
|
||||
typedef detail::as_tuple_t<T> internal_tuple_t;
|
||||
|
||||
return detail::make_stdtuple_from_seqtuple(
|
||||
detail::as_tuple(val),
|
||||
std::make_index_sequence< internal_tuple_t::size_v >()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates an `std::tuple` with lvalue references to fields of an aggregate T.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s;
|
||||
/// tie(s) = std::tuple<int, short>{10, 11};
|
||||
/// assert(s.s == 11);
|
||||
/// \endcode
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T& val) noexcept {
|
||||
typedef detail::as_tuple_t<T> internal_tuple_t;
|
||||
|
||||
return detail::tie_sequence_tuple_impl(
|
||||
detail::as_tuple(val),
|
||||
std::make_index_sequence< internal_tuple_t::size_v >()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Writes aggregate `value` to `out`
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s{12, 13};
|
||||
/// write(std::cout, s); // outputs '{12, 13}'
|
||||
/// \endcode
|
||||
template <class Char, class Traits, class T>
|
||||
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
out << '{';
|
||||
detail::sequence_tuple::print_impl<0, tuple_size_v<T> >::print(out, detail::as_tuple(value));
|
||||
out << '}';
|
||||
}
|
||||
|
||||
/// Reads aggregate `value` from stream `in`
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s;
|
||||
/// std::stringstream ss;
|
||||
/// ss << "{ 12, 13 }";
|
||||
/// ss >> s;
|
||||
/// assert(s.i == 12);
|
||||
/// assert(s.i == 13);
|
||||
/// \endcode
|
||||
template <class Char, class Traits, class T>
|
||||
void read(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
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);
|
||||
detail::sequence_tuple::read_impl<0, tuple_size_v<T> >::read(in, detail::as_tuple(value));
|
||||
|
||||
in >> parenthis;
|
||||
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
|
||||
|
||||
in.flags(prev_flags);
|
||||
in.exceptions(prev_exceptions);
|
||||
}
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_CORE17_HPP
|
||||
88
include/boost/pfr/core_name.hpp
Normal file
88
include/boost/pfr/core_name.hpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_CORE_NAME_HPP
|
||||
#define BOOST_PFR_CORE_NAME_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/core_name.hpp>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/stdarray.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
|
||||
#include <cstddef> // for std::size_t
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
/// \file boost/pfr/core_name.hpp
|
||||
/// Contains functions \forcedlink{get_name} and \forcedlink{names_as_array} to know which names each field of any \aggregate has.
|
||||
///
|
||||
/// \fnrefl for details.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// \brief Returns name of a field with index `I` in \aggregate `T`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
///
|
||||
/// assert(boost::pfr::get_name<0, my_struct>() == "i");
|
||||
/// assert(boost::pfr::get_name<1, my_struct>() == "s");
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
constexpr
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
std::string_view
|
||||
#else
|
||||
auto
|
||||
#endif
|
||||
get_name() noexcept {
|
||||
return detail::get_name<T, I>();
|
||||
}
|
||||
|
||||
// FIXME: implement this
|
||||
// template<class U, class T>
|
||||
// constexpr auto get_name() noexcept {
|
||||
// return detail::sequence_tuple::get_by_type_impl<U>( detail::tie_as_names_tuple<T>() );
|
||||
// }
|
||||
|
||||
/// \brief Creates a `std::array` from names of fields of an \aggregate `T`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// std::array<std::string_view, 2> a = boost::pfr::names_as_array<my_struct>();
|
||||
/// assert(a[0] == "i");
|
||||
/// \endcode
|
||||
template <class T>
|
||||
constexpr
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
std::array<std::string_view, boost::pfr::tuple_size_v<T>>
|
||||
#else
|
||||
auto
|
||||
#endif
|
||||
names_as_array() noexcept {
|
||||
return detail::make_stdarray_from_tietuple(
|
||||
detail::tie_as_names_tuple<T>(),
|
||||
detail::make_index_sequence< tuple_size_v<T> >(),
|
||||
1L
|
||||
);
|
||||
}
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_CORE_NAME_HPP
|
||||
|
||||
26
include/boost/pfr/detail/config.hpp
Normal file
26
include/boost/pfr/detail/config.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CONFIG_HPP
|
||||
#define BOOST_PFR_DETAIL_CONFIG_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/config.hpp>
|
||||
|
||||
#if !BOOST_PFR_ENABLED
|
||||
|
||||
#error Boost.PFR library is not supported in your environment. \
|
||||
Try one of the possible solutions: \
|
||||
1. try to take away an '-DBOOST_PFR_ENABLED=0', if it exists \
|
||||
2. enable C++14; \
|
||||
3. enable C++17; \
|
||||
4. update your compiler; \
|
||||
or disable this error by '-DBOOST_PFR_ENABLED=1' if you really know what are you doing.
|
||||
|
||||
#endif // !BOOST_PFR_ENABLED
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CONFIG_HPP
|
||||
|
||||
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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
706
include/boost/pfr/detail/core14_classic.hpp
Normal file
706
include/boost/pfr/detail/core14_classic.hpp
Normal file
@@ -0,0 +1,706 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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>* = nullptr) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = nullptr) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>* = nullptr) noexcept;
|
||||
template <class Type> constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value && !std::is_union<Type>::value>* = 0) noexcept;
|
||||
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = nullptr) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = nullptr) noexcept;
|
||||
|
||||
|
||||
///////////////////// Definitions of type_to_id and id_to_type for fundamental types
|
||||
/// @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 constructor of a type accepts sizeof...(I) parameters
|
||||
template <class T, std::size_t N, std::size_t... I>
|
||||
constexpr void* flat_type_to_array_of_type_ids(std::size_t* types, std::index_sequence<I...>) noexcept
|
||||
{
|
||||
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>
|
||||
constexpr bool is_flat_refelectable(std::index_sequence<>) noexcept {
|
||||
return true; ///< all empty structs always flat refelectable
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto tie_as_flat_tuple(T& lvalue) noexcept {
|
||||
static_assert(
|
||||
!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 {
|
||||
template<class T2, std::size_t... I2>
|
||||
static constexpr void* constexpr_aggregate_initializer() noexcept {
|
||||
T2 tmp{ ubiq_constructor_constexpr_copy{I2}... };
|
||||
(void)tmp;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <void* = constexpr_aggregate_initializer<T, I...>() >
|
||||
static std::true_type test(long) noexcept;
|
||||
|
||||
static std::false_type test(...) noexcept;
|
||||
|
||||
static constexpr bool value = decltype(test(0)){};
|
||||
};
|
||||
|
||||
|
||||
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."
|
||||
);
|
||||
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-2024 Antony Polukhin.
|
||||
//
|
||||
// Distributed under the 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
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#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
|
||||
|
||||
72
include/boost/pfr/detail/core17.hpp
Normal file
72
include/boost/pfr/detail/core17.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
#pragma once
|
||||
|
||||
#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{};
|
||||
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>
|
||||
constexpr void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
std::forward<F>(f)(
|
||||
detail::tie_as_tuple(t)
|
||||
);
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE17_HPP
|
||||
File diff suppressed because it is too large
Load Diff
29
include/boost/pfr/detail/core_name.hpp
Normal file
29
include/boost/pfr/detail/core_name.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE_NAME_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE_NAME_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
// Each core_name provides `boost::pfr::detail::get_name` and
|
||||
// `boost::pfr::detail::tie_as_names_tuple` functions.
|
||||
//
|
||||
// The whole functional of extracting field's names is build on top of those
|
||||
// two functions.
|
||||
#if BOOST_PFR_CORE_NAME_ENABLED
|
||||
#include <boost/pfr/detail/core_name20_static.hpp>
|
||||
#else
|
||||
#include <boost/pfr/detail/core_name14_disabled.hpp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME_HPP
|
||||
|
||||
43
include/boost/pfr/detail/core_name14_disabled.hpp
Normal file
43
include/boost/pfr/detail/core_name14_disabled.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, std::size_t I>
|
||||
constexpr auto get_name() noexcept {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"====================> Boost.PFR: Field's names extracting functionality requires C++20."
|
||||
);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_names_tuple() noexcept {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"====================> Boost.PFR: Field's names extracting functionality requires C++20."
|
||||
);
|
||||
|
||||
return detail::sequence_tuple::make_sequence_tuple();
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||
|
||||
242
include/boost/pfr/detail/core_name20_static.hpp
Normal file
242
include/boost/pfr/detail/core_name20_static.hpp
Normal file
@@ -0,0 +1,242 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/detail/core.hpp>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/stdarray.hpp>
|
||||
#include <boost/pfr/detail/fake_object.hpp>
|
||||
#include <type_traits>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <memory> // for std::addressof
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
struct core_name_skip {
|
||||
std::size_t size_at_begin;
|
||||
std::size_t size_at_end;
|
||||
bool is_backward;
|
||||
std::string_view until_runtime;
|
||||
|
||||
consteval std::string_view apply(std::string_view sv) const noexcept {
|
||||
// We use std::min here to make the compiler diagnostic shorter and
|
||||
// cleaner in case of misconfigured BOOST_PFR_CORE_NAME_PARSING
|
||||
sv.remove_prefix((std::min)(size_at_begin, sv.size()));
|
||||
sv.remove_suffix((std::min)(size_at_end, sv.size()));
|
||||
if (until_runtime.empty()) {
|
||||
return sv;
|
||||
}
|
||||
|
||||
const auto found = is_backward ? sv.rfind(until_runtime)
|
||||
: sv.find(until_runtime);
|
||||
|
||||
const auto cut_until = found + until_runtime.size();
|
||||
const auto safe_cut_until = (std::min)(cut_until, sv.size());
|
||||
return sv.substr(safe_cut_until);
|
||||
}
|
||||
};
|
||||
|
||||
struct backward {
|
||||
explicit consteval backward(std::string_view value) noexcept
|
||||
: value(value)
|
||||
{}
|
||||
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
|
||||
std::size_t size_at_end,
|
||||
std::string_view until_runtime) noexcept
|
||||
{
|
||||
return core_name_skip{size_at_begin, size_at_end, false, until_runtime};
|
||||
}
|
||||
|
||||
consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
|
||||
std::size_t size_at_end,
|
||||
backward until_runtime) noexcept
|
||||
{
|
||||
return core_name_skip{size_at_begin, size_at_end, true, until_runtime.value};
|
||||
}
|
||||
|
||||
// it might be compilation failed without this workaround sometimes
|
||||
// See https://github.com/llvm/llvm-project/issues/41751 for details
|
||||
template <class>
|
||||
consteval std::string_view clang_workaround(std::string_view value) noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class MsvcWorkaround, auto ptr>
|
||||
consteval auto name_of_field_impl() noexcept {
|
||||
// Some of the following compiler specific macro may be defined only
|
||||
// inside the function body:
|
||||
|
||||
#ifndef BOOST_PFR_FUNCTION_SIGNATURE
|
||||
# if defined(__FUNCSIG__)
|
||||
# define BOOST_PFR_FUNCTION_SIGNATURE __FUNCSIG__
|
||||
# elif defined(__PRETTY_FUNCTION__) || defined(__GNUC__) || defined(__clang__)
|
||||
# define BOOST_PFR_FUNCTION_SIGNATURE __PRETTY_FUNCTION__
|
||||
# else
|
||||
# define BOOST_PFR_FUNCTION_SIGNATURE ""
|
||||
# endif
|
||||
#endif
|
||||
|
||||
constexpr std::string_view sv = detail::clang_workaround<MsvcWorkaround>(BOOST_PFR_FUNCTION_SIGNATURE);
|
||||
static_assert(!sv.empty(),
|
||||
"====================> Boost.PFR: Field reflection parser configured in a wrong way. "
|
||||
"Please define the BOOST_PFR_FUNCTION_SIGNATURE to a compiler specific macro, "
|
||||
"that outputs the whole function signature including non-type template parameters."
|
||||
);
|
||||
|
||||
constexpr auto skip = detail::make_core_name_skip BOOST_PFR_CORE_NAME_PARSING;
|
||||
static_assert(skip.size_at_begin + skip.size_at_end + skip.until_runtime.size() < sv.size(),
|
||||
"====================> Boost.PFR: Field reflection parser configured in a wrong way. "
|
||||
"It attempts to skip more chars than available. "
|
||||
"Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
|
||||
"'Limitations and Configuration' for more information."
|
||||
);
|
||||
constexpr auto fn = skip.apply(sv);
|
||||
static_assert(
|
||||
!fn.empty(),
|
||||
"====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. "
|
||||
"It skipped all the input, leaving the field name empty. "
|
||||
"Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
|
||||
"'Limitations and Configuration' for more information."
|
||||
);
|
||||
auto res = std::array<char, fn.size()+1>{};
|
||||
|
||||
auto* out = res.data();
|
||||
for (auto x: fn) {
|
||||
*out = x;
|
||||
++out;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundefined-var-template"
|
||||
|
||||
// clang 16 and earlier don't support address of non-static member as template parameter
|
||||
// but fortunately it's possible to use C++20 non-type template parameters in another way
|
||||
// even in clang 16 and more older clangs
|
||||
// all we need is to wrap pointer into 'clang_wrapper_t' and then pass it into template
|
||||
template <class T>
|
||||
struct clang_wrapper_t {
|
||||
T v;
|
||||
};
|
||||
template <class T>
|
||||
clang_wrapper_t(T) -> clang_wrapper_t<T>;
|
||||
|
||||
template <class T>
|
||||
constexpr auto make_clang_wrapper(const T& arg) noexcept {
|
||||
return clang_wrapper_t{arg};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
constexpr const T& make_clang_wrapper(const T& arg) noexcept {
|
||||
// It's everything OK with address of non-static member as template parameter support on this compiler
|
||||
// so we don't need a wrapper here, just pass the pointer into template
|
||||
return arg;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <class MsvcWorkaround, auto ptr>
|
||||
consteval auto name_of_field() noexcept {
|
||||
// Sanity check: known field name must match the deduced one
|
||||
static_assert(
|
||||
sizeof(MsvcWorkaround) // do not trigger if `name_of_field()` is not used
|
||||
&& std::string_view{
|
||||
detail::name_of_field_impl<
|
||||
core_name_skip, detail::make_clang_wrapper(std::addressof(
|
||||
detail::fake_object<core_name_skip>().size_at_begin
|
||||
))
|
||||
>().data()
|
||||
} == "size_at_begin",
|
||||
"====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. "
|
||||
"It does not return the proper field name. "
|
||||
"Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
|
||||
"'Limitations and Configuration' for more information."
|
||||
);
|
||||
|
||||
return detail::name_of_field_impl<MsvcWorkaround, ptr>();
|
||||
}
|
||||
|
||||
// Storing part of a string literal into an array minimizes the binary size.
|
||||
//
|
||||
// Without passing 'T' into 'name_of_field' different fields from different structures might have the same name!
|
||||
// See https://developercommunity.visualstudio.com/t/__FUNCSIG__-outputs-wrong-value-with-C/10458554 for details
|
||||
template <class T, std::size_t I>
|
||||
inline constexpr auto stored_name_of_field = detail::name_of_field<T,
|
||||
detail::make_clang_wrapper(std::addressof(detail::sequence_tuple::get<I>(
|
||||
detail::tie_as_tuple(detail::fake_object<T>())
|
||||
)))
|
||||
>();
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto tie_as_names_tuple_impl(std::index_sequence<I...>) noexcept {
|
||||
return detail::sequence_tuple::make_sequence_tuple(std::string_view{stored_name_of_field<T, I>.data()}...);
|
||||
}
|
||||
|
||||
template <class T, std::size_t I>
|
||||
constexpr std::string_view get_name() noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
static_assert(
|
||||
!std::is_array<T>::value,
|
||||
"====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members"
|
||||
);
|
||||
static_assert(
|
||||
sizeof(T) && BOOST_PFR_USE_CPP17,
|
||||
"====================> Boost.PFR: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 macro enabled."
|
||||
);
|
||||
|
||||
return stored_name_of_field<T, I>.data();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_names_tuple() noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
static_assert(
|
||||
!std::is_array<T>::value,
|
||||
"====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members"
|
||||
);
|
||||
static_assert(
|
||||
sizeof(T) && BOOST_PFR_USE_CPP17,
|
||||
"====================> Boost.PFR: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 macro enabled."
|
||||
);
|
||||
|
||||
return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||
|
||||
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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
|
||||
|
||||
57
include/boost/pfr/detail/fake_object.hpp
Normal file
57
include/boost/pfr/detail/fake_object.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
#define BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wundefined-internal"
|
||||
# pragma clang diagnostic ignored "-Wundefined-var-template"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wundefined-var-template"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
// This class has external linkage while T has not sure.
|
||||
template <class T>
|
||||
struct wrapper {
|
||||
const T value;
|
||||
};
|
||||
|
||||
// This variable servers as a link-time assert.
|
||||
// If linker requires it, then `fake_object()` is used at runtime.
|
||||
template <class T>
|
||||
extern const wrapper<T> do_not_use_PFR_with_local_types;
|
||||
|
||||
// For returning non default constructible types, it's exclusively used in member name retrieval.
|
||||
//
|
||||
// Neither std::declval nor boost::pfr::detail::unsafe_declval are usable there.
|
||||
// This takes advantage of C++20 features, while boost::pfr::detail::unsafe_declval works
|
||||
// with the former standards.
|
||||
template <class T>
|
||||
constexpr const T& fake_object() noexcept {
|
||||
return do_not_use_PFR_with_local_types<T>.value;
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif // BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
|
||||
|
||||
330
include/boost/pfr/detail/fields_count.hpp
Normal file
330
include/boost/pfr/detail/fields_count.hpp
Normal file
@@ -0,0 +1,330 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
|
||||
///////////////////// Detect aggregates with inheritance
|
||||
template <class Derived, class U>
|
||||
constexpr bool static_assert_non_inherited() noexcept {
|
||||
static_assert(
|
||||
!std::is_base_of<U, Derived>::value,
|
||||
"====================> Boost.PFR: Boost.PFR: Inherited types are not supported."
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
struct ubiq_lref_base_asserting {
|
||||
template <class Type> constexpr operator Type&() const && // tweak for template_unconstrained.cpp like cases
|
||||
noexcept(detail::static_assert_non_inherited<Derived, Type>()) // force the computation of assert function
|
||||
{
|
||||
return detail::unsafe_declval<Type&>();
|
||||
}
|
||||
|
||||
template <class Type> constexpr operator Type&() const & // tweak for optional_chrono.cpp like cases
|
||||
noexcept(detail::static_assert_non_inherited<Derived, Type>()) // force the computation of assert function
|
||||
{
|
||||
return detail::unsafe_declval<Type&>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
struct ubiq_rref_base_asserting {
|
||||
template <class Type> /*constexpr*/ operator Type() const && // Allows initialization of rvalue reference fields and move-only types
|
||||
noexcept(detail::static_assert_non_inherited<Derived, Type>()) // force the computation of assert function
|
||||
{
|
||||
return detail::unsafe_declval<Type>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, std::size_t I0, std::size_t... I, class /*Enable*/ = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
|
||||
constexpr auto assert_first_not_base(std::index_sequence<I0, I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_lref_base_asserting<T>{}, ubiq_lref_constructor{I}... })>::type
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T, std::size_t I0, std::size_t... I, class /*Enable*/ = typename std::enable_if<!std::is_copy_constructible<T>::value>::type>
|
||||
constexpr auto assert_first_not_base(std::index_sequence<I0, I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_rref_base_asserting<T>{}, ubiq_rref_constructor{I}... })>::type
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void* assert_first_not_base(std::index_sequence<>) noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////// Helper for SFINAE on fields count
|
||||
template <class T, std::size_t... I, class /*Enable*/ = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
|
||||
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_lref_constructor{I}... })>::type;
|
||||
|
||||
template <class T, std::size_t... 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."
|
||||
);
|
||||
|
||||
#if !BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
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)."
|
||||
);
|
||||
#endif // #if !BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
|
||||
|
||||
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
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= 1920)
|
||||
// Workaround for msvc compilers. Versions <= 1920 have a limit of max 1024 elements in template parameter pack
|
||||
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT >= 1024 ? 1024 : sizeof(type) * CHAR_BIT);
|
||||
#else
|
||||
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT); // We multiply by CHAR_BIT because the type may have bitfields in T
|
||||
#endif
|
||||
|
||||
constexpr std::size_t result = detail::detect_fields_count_dispatch<type>(size_t_<max_fields_count>{}, 1L, 1L);
|
||||
|
||||
detail::assert_first_not_base<type>(detail::make_index_sequence<result>{});
|
||||
|
||||
#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
|
||||
66
include/boost/pfr/detail/for_each_field_impl.hpp
Normal file
66
include/boost/pfr/detail/for_each_field_impl.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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{}))>
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I i, long) {
|
||||
std::forward<F>(f)(std::forward<T>(v), i);
|
||||
}
|
||||
|
||||
template <class T, class F, class I>
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I /*i*/, int) {
|
||||
std::forward<F>(f)(std::forward<T>(v));
|
||||
}
|
||||
|
||||
#if !defined(__cpp_fold_expressions) || __cpp_fold_expressions < 201603
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type /*move_values*/) {
|
||||
const int v[] = {0, (
|
||||
detail::for_each_field_impl_apply(sequence_tuple::get<I>(t), std::forward<F>(f), size_t_<I>{}, 1L),
|
||||
0
|
||||
)...};
|
||||
(void)v;
|
||||
}
|
||||
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type /*move_values*/) {
|
||||
const int v[] = {0, (
|
||||
detail::for_each_field_impl_apply(sequence_tuple::get<I>(std::move(t)), std::forward<F>(f), size_t_<I>{}, 1L),
|
||||
0
|
||||
)...};
|
||||
(void)v;
|
||||
}
|
||||
#else
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type /*move_values*/) {
|
||||
(detail::for_each_field_impl_apply(sequence_tuple::get<I>(t), std::forward<F>(f), size_t_<I>{}, 1L), ...);
|
||||
}
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::true_type /*move_values*/) {
|
||||
(detail::for_each_field_impl_apply(sequence_tuple::get<I>(std::move(t)), std::forward<F>(f), size_t_<I>{}, 1L), ...);
|
||||
}
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP
|
||||
239
include/boost/pfr/detail/functional.hpp
Normal file
239
include/boost/pfr/detail/functional.hpp
Normal file
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 <cstdint>
|
||||
|
||||
#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;
|
||||
}
|
||||
};
|
||||
|
||||
// Hash combine functions copied from Boost.ContainerHash
|
||||
// https://github.com/boostorg/container_hash/blob/171c012d4723c5e93cc7cffe42919afdf8b27dfa/include/boost/container_hash/hash.hpp#L311
|
||||
// that is based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
//
|
||||
// This also contains public domain code from MurmurHash. From the
|
||||
// MurmurHash header:
|
||||
//
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
template <typename SizeT>
|
||||
constexpr void hash_combine(SizeT& seed, SizeT value) noexcept {
|
||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
constexpr auto rotl(std::uint32_t x, std::uint32_t r) noexcept {
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
constexpr void hash_combine(std::uint32_t& h1, std::uint32_t k1) noexcept {
|
||||
const std::uint32_t c1 = 0xcc9e2d51;
|
||||
const std::uint32_t c2 = 0x1b873593;
|
||||
|
||||
k1 *= c1;
|
||||
k1 = detail::rotl(k1,15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = detail::rotl(h1,13);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
}
|
||||
|
||||
#if defined(INT64_MIN) && defined(UINT64_MAX)
|
||||
constexpr void hash_combine(std::uint64_t& h, std::uint64_t k) noexcept {
|
||||
const std::uint64_t m = 0xc6a4a7935bd1e995ULL;
|
||||
const int r = 47;
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h ^= k;
|
||||
h *= m;
|
||||
|
||||
// Completely arbitrary number, to prevent 0's
|
||||
// from hashing to 0.
|
||||
h += 0xe6546b64;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
auto compute_hash(const T& value, long /*priority*/)
|
||||
-> decltype(std::hash<T>()(value))
|
||||
{
|
||||
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) {
|
||||
constexpr std::size_t fields_count_rhs_ = detail::fields_count<std::remove_reference_t<U>>();
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
y,
|
||||
[&result, &lhs](const auto& rhs) {
|
||||
result = visitor_t::cmp(lhs, rhs);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_rhs_>{}
|
||||
);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
|
||||
141
include/boost/pfr/detail/offset_based_getter.hpp
Normal file
141
include/boost/pfr/detail/offset_based_getter.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2017-2018 Chris Beck
|
||||
// Copyright (c) 2019-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 <memory> // std::addressof
|
||||
#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 alignment 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
|
||||
49
include/boost/pfr/detail/possible_reflectable.hpp
Normal file
49
include/boost/pfr/detail/possible_reflectable.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP
|
||||
#define BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/traits_fwd.hpp>
|
||||
|
||||
#include <type_traits> // for std::is_aggregate
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// Returns false when the type exactly wasn't be reflectable
|
||||
template <class T, class WhatFor>
|
||||
constexpr decltype(is_reflectable<T, WhatFor>::value) possible_reflectable(long) noexcept {
|
||||
return is_reflectable<T, WhatFor>::value;
|
||||
}
|
||||
|
||||
#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
|
||||
|
||||
template <class T, class WhatFor>
|
||||
constexpr bool possible_reflectable(int) noexcept {
|
||||
# if defined(__cpp_lib_is_aggregate)
|
||||
using type = std::remove_cv_t<T>;
|
||||
return std::is_aggregate<type>();
|
||||
# else
|
||||
return true;
|
||||
# endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class T, class WhatFor>
|
||||
constexpr bool possible_reflectable(int) noexcept {
|
||||
// negative answer here won't change behaviour in PFR-dependent libraries(like Fusion)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP
|
||||
|
||||
|
||||
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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
178
include/boost/pfr/detail/sequence_tuple.hpp
Normal file
178
include/boost/pfr/detail/sequence_tuple.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr const T& get_impl(const base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr volatile T& get_impl(volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr const volatile T& get_impl(const volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr T& get_by_type_impl(base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const T& get_by_type_impl(const base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr volatile T& get_by_type_impl(volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const volatile T& get_by_type_impl(const volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr T&& get_by_type_impl(base_from_member<N, T>&& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const T&& get_by_type_impl(const base_from_member<N, T>&& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class ...Values>
|
||||
struct tuple: tuple_base<
|
||||
detail::index_sequence_for<Values...>,
|
||||
Values...>
|
||||
{
|
||||
using tuple_base<
|
||||
detail::index_sequence_for<Values...>,
|
||||
Values...
|
||||
>::tuple_base;
|
||||
|
||||
constexpr static std::size_t size() noexcept { return sizeof...(Values); }
|
||||
constexpr static bool empty() noexcept { return size() == 0; }
|
||||
};
|
||||
|
||||
|
||||
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>() )
|
||||
) >;
|
||||
|
||||
template <class... Args>
|
||||
constexpr auto make_sequence_tuple(Args... args) noexcept {
|
||||
return ::boost::pfr::detail::sequence_tuple::tuple<Args...>{ args... };
|
||||
}
|
||||
|
||||
}}}} // namespace boost::pfr::detail::sequence_tuple
|
||||
|
||||
#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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
41
include/boost/pfr/detail/stdarray.hpp
Normal file
41
include/boost/pfr/detail/stdarray.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2023 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_STDARRAY_HPP
|
||||
#define BOOST_PFR_DETAIL_STDARRAY_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <utility> // metaprogramming stuff
|
||||
#include <array>
|
||||
#include <type_traits> // for std::common_type_t
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class... Types>
|
||||
constexpr auto make_stdarray(const Types&... t) noexcept {
|
||||
return std::array<std::common_type_t<Types...>, sizeof...(Types)>{t...};
|
||||
}
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdarray_from_tietuple(const T& t, std::index_sequence<I...>, int) noexcept {
|
||||
return detail::make_stdarray(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto make_stdarray_from_tietuple(const T&, std::index_sequence<>, long) noexcept {
|
||||
return std::array<std::nullptr_t, 0>{};
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_STDARRAY_HPP
|
||||
|
||||
49
include/boost/pfr/detail/stdtuple.hpp
Normal file
49
include/boost/pfr/detail/stdtuple.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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...>) {
|
||||
(void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter`
|
||||
return std::make_tuple(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
}
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
(void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter`
|
||||
return std::tie(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
}
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_conststdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
(void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter`
|
||||
return std::tuple<
|
||||
std::add_lvalue_reference_t<std::add_const_t<
|
||||
std::remove_reference_t<decltype(boost::pfr::detail::sequence_tuple::get<I>(t))>
|
||||
>>...
|
||||
>(
|
||||
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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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;
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP
|
||||
37
include/boost/pfr/detail/unsafe_declval.hpp
Normal file
37
include/boost/pfr/detail/unsafe_declval.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2019-2024 Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
#define BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#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 = nullptr;
|
||||
ptr += 42; // suppresses 'null pointer dereference' warnings
|
||||
return static_cast<T>(*ptr);
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
|
||||
@@ -1,149 +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)
|
||||
|
||||
#ifndef BOOST_PFR_FIELDS_COUNT_HPP
|
||||
#define BOOST_PFR_FIELDS_COUNT_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#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 {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
///////////////////// Structure that can be converted to reference to anything
|
||||
struct ubiq_constructor {
|
||||
std::size_t ignore;
|
||||
template <class Type> constexpr operator Type&() const noexcept; // Undefined, allows initialization of reference fields (T& and const T&)
|
||||
//template <class Type> constexpr operator Type&&() const noexcept; // Undefined, allows initialization of rvalue reference fields and move-only types
|
||||
};
|
||||
|
||||
///////////////////// Structure that can be converted to reference to anything except reference to T
|
||||
template <class T>
|
||||
struct ubiq_constructor_except {
|
||||
template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&> () const noexcept; // Undefined
|
||||
};
|
||||
|
||||
///////////////////// Hand-made is_aggregate_initializable_n<T> trait:
|
||||
|
||||
// `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>>::value
|
||||
> {};
|
||||
|
||||
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_constructor{I})...>::value
|
||||
|| is_single_field_and_aggregate_initializable<N, T>::value
|
||||
;
|
||||
}
|
||||
|
||||
static constexpr bool value =
|
||||
std::is_empty<T>::value
|
||||
|| std::is_fundamental<T>::value
|
||||
|| is_not_constructible_n(std::make_index_sequence<N>{})
|
||||
;
|
||||
};
|
||||
|
||||
///////////////////// Methods for detecting max parameters for construction of T
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_constructor{I}... })>::type;
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr void detect_fields_count(std::size_t& count, size_t_<N>, size_t_<N>, long) noexcept {
|
||||
// Hand-made is_aggregate<T> trait:
|
||||
// Aggregates could be constructed from `decltype(ubiq_constructor{I})...` but report that there's no constructor from `decltype(ubiq_constructor{I})...`
|
||||
// Special case for N == 1: `std::is_constructible<T, ubiq_constructor>` returns true if N == 1 and T is copy/move constructible.
|
||||
static_assert(
|
||||
is_aggregate_initializable_n<T, N>::value,
|
||||
"Types with user specified constructors (non-aggregate types) are not supported."
|
||||
);
|
||||
|
||||
count = N;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr void detect_fields_count(std::size_t& count, size_t_<Begin>, size_t_<Middle>, int) noexcept;
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr auto detect_fields_count(std::size_t& count, size_t_<Begin>, size_t_<Middle>, long) noexcept
|
||||
-> decltype( enable_if_constructible_helper<T>(std::make_index_sequence<Middle>()) )
|
||||
{
|
||||
constexpr std::size_t next = Middle + (Middle - Begin + 1) / 2;
|
||||
detect_fields_count<T>(count, size_t_<Middle>{}, size_t_<next>{}, 1L);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr void detect_fields_count(std::size_t& count, size_t_<Begin>, size_t_<Middle>, int) noexcept {
|
||||
constexpr std::size_t next = (Begin + Middle) / 2;
|
||||
detect_fields_count<T>(count, size_t_<Begin>{}, size_t_<next>{}, 1L);
|
||||
}
|
||||
|
||||
///////////////////// Returns non-flattened fields count
|
||||
template <class T>
|
||||
constexpr std::size_t fields_count() noexcept {
|
||||
static_assert(std::is_copy_constructible<std::remove_all_extents_t<T>>::value, "Structure and each field in structure must be copy constructible");
|
||||
std::size_t res = 0u;
|
||||
constexpr std::size_t next = (sizeof(T) * 8) / 2 + 1; // We multiply by 8 because we may have bitfields in T
|
||||
detect_fields_count<T>(res, size_t_<0>{}, size_t_<next>{}, 1L);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
/// \brief Has a static const member variable `value` that constins fields count in a T.
|
||||
/// Works for any T that supports aggregate initialization even if T is not POD.
|
||||
/// \flattening{Flattens} only multidimensional arrays.
|
||||
///
|
||||
/// \b 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>() >;
|
||||
|
||||
|
||||
/// \brief `tuple_size_v` is a template variable that contains fields count in a T and
|
||||
/// works for any T that supports aggregate initialization even if T is not POD.
|
||||
/// \flattening{Flattens} only multidimensional arrays.
|
||||
///
|
||||
/// \b 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_FIELDS_COUNT_HPP
|
||||
@@ -1,76 +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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/functors.hpp>
|
||||
|
||||
/// \def BOOST_PFR_FLAT_FUNCTIONS_FOR(T)
|
||||
/// Defines comparison operators and stream operators for T.
|
||||
/// If POD is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/flat_functions_for.hpp>
|
||||
/// struct comparable_struct { // No operators defined for that structure
|
||||
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
|
||||
/// };
|
||||
/// BOOST_PFR_FLAT_FUNCTIONS_FOR(comparable_struct)
|
||||
/// // ...
|
||||
///
|
||||
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
/// assert(s1 < s2);
|
||||
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
|
||||
/// \endcode
|
||||
///
|
||||
/// \podops for other ways to define operators and more details.
|
||||
///
|
||||
/// \b Defines \b following \b for \b T:
|
||||
/// \code
|
||||
/// bool operator==(const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator!=(const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator< (const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator> (const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator<=(const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator>=(const T& lhs, const T& rhs) noexcept;
|
||||
///
|
||||
/// template <class Char, class Traits>
|
||||
/// std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
|
||||
///
|
||||
/// template <class Char, class Traits>
|
||||
/// std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
|
||||
///
|
||||
/// // helper function for Boost unordered containers and boost::hash<>.
|
||||
/// std::size_t hash_value(const T& value) noexcept;
|
||||
/// \endcode
|
||||
|
||||
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
|
||||
static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
|
||||
static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
|
||||
static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
|
||||
static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs); } \
|
||||
template <class Char, class Traits> \
|
||||
static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
|
||||
::boost::pfr::flat_write(out, value); \
|
||||
return out; \
|
||||
} \
|
||||
template <class Char, class Traits> \
|
||||
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
::boost::pfr::flat_read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
static inline std::size_t hash_value(const T& v) noexcept { \
|
||||
return ::boost::pfr::flat_hash<T>{}(v); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
|
||||
@@ -1,162 +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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/functors.hpp>
|
||||
|
||||
/// \file boost/pfr/flat_ops.hpp
|
||||
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.
|
||||
/// If POD is comparable or streamable using it's own operator or it's conversion operator, then the original operator is used.
|
||||
///
|
||||
/// Just write \b using \b namespace \b flat_ops; and operators will be available in scope.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/flat_ops.hpp>
|
||||
/// struct comparable_struct { // No operators defined for that structure
|
||||
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
|
||||
/// };
|
||||
/// // ...
|
||||
///
|
||||
/// using namespace flat_ops;
|
||||
///
|
||||
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
/// assert(s1 < s2);
|
||||
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
|
||||
/// \endcode
|
||||
///
|
||||
/// \podops for other ways to define operators and more details.
|
||||
///
|
||||
/// \b This \b header \b contains:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
|
||||
template <template <class, class> class Detector, class Tleft, class Tright>
|
||||
struct not_appliable {
|
||||
struct success{};
|
||||
template <class Tl, class Tr> static Detector<Tl, Tr> detector_impl(long) noexcept;
|
||||
template <class Tl, class Tr> static success detector_impl(int) noexcept;
|
||||
|
||||
static constexpr bool value = std::is_same<
|
||||
decltype(detector_impl<Tleft, Tright>(1L)),
|
||||
success
|
||||
>::value;
|
||||
};
|
||||
|
||||
///////////////////// Detectors for different operators
|
||||
template <class T1, class T2> using comp_eq_detector = decltype(std::declval<T1>() == std::declval<T2>());
|
||||
template <class T1, class T2> using comp_ne_detector = decltype(std::declval<T1>() != std::declval<T2>());
|
||||
template <class T1, class T2> using comp_lt_detector = decltype(std::declval<T1>() < std::declval<T2>());
|
||||
template <class T1, class T2> using comp_le_detector = decltype(std::declval<T1>() <= std::declval<T2>());
|
||||
template <class T1, class T2> using comp_gt_detector = decltype(std::declval<T1>() > std::declval<T2>());
|
||||
template <class T1, class T2> using comp_ge_detector = decltype(std::declval<T1>() >= std::declval<T2>());
|
||||
template <class S, class T> using ostreamable_detector = decltype(std::declval<S>() << std::declval<T>());
|
||||
template <class S, class T> using istreamable_detector = decltype(std::declval<S>() >> std::declval<T>());
|
||||
|
||||
///////////////////// Helper typedef that it used by all the enable_not_*_comp_t
|
||||
template <template <class, class> class Detector, class T>
|
||||
using enable_not_comp_base_t = typename std::enable_if<
|
||||
not_appliable<Detector, T const&, T const&>::value && std::is_pod<T>::value,
|
||||
bool
|
||||
>::type;
|
||||
|
||||
///////////////////// std::enable_if_t like functions that enable only if types do not support operation and are PODs
|
||||
|
||||
template <class T> using enable_not_eq_comp_t = enable_not_comp_base_t<comp_eq_detector, T>;
|
||||
template <class T> using enable_not_ne_comp_t = enable_not_comp_base_t<comp_ne_detector, T>;
|
||||
template <class T> using enable_not_lt_comp_t = enable_not_comp_base_t<comp_lt_detector, T>;
|
||||
template <class T> using enable_not_le_comp_t = enable_not_comp_base_t<comp_le_detector, T>;
|
||||
template <class T> using enable_not_gt_comp_t = enable_not_comp_base_t<comp_gt_detector, T>;
|
||||
template <class T> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_not_ostreamable_t = typename std::enable_if<
|
||||
not_appliable<ostreamable_detector, Stream&, Type const&>::value && std::is_pod<Type>::value,
|
||||
Stream&
|
||||
>::type;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_not_istreamable_t = typename std::enable_if<
|
||||
not_appliable<istreamable_detector, Stream&, Type&>::value && std::is_pod<Type>::value,
|
||||
Stream&
|
||||
>::type;
|
||||
} // namespace detail
|
||||
|
||||
namespace flat_ops {
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
|
||||
|
||||
/// \brief helper function for Boost
|
||||
template <class T> std::size_t hash_value(const T& value) noexcept;
|
||||
#else
|
||||
template <class T>
|
||||
static detail::enable_not_eq_comp_t<T> operator==(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_equal_to<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_ne_comp_t<T> operator!=(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_not_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_lt_comp_t<T> operator<(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_less<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_gt_comp_t<T> operator>(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_greater<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_le_comp_t<T> operator<=(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_less_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_ge_comp_t<T> operator>=(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_greater_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static detail::enable_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
flat_write(out, value);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static detail::enable_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
flat_read(in, value);
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
return flat_hash<T>{}(value);
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace flat_ops
|
||||
|
||||
}} // namespace boost::pfr
|
||||
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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
|
||||
@@ -1,169 +1,47 @@
|
||||
// Copyright (c) 2016 Antony Polukhin
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <boost/pfr/ops.hpp>
|
||||
|
||||
#include <boost/pfr/detail/functional.hpp>
|
||||
|
||||
/// \file boost/pfr/functors.hpp
|
||||
/// Contains functors that can work with PODs and are close to the Standard Library ones.
|
||||
/// Each functor \flattening{flattens} the POD type and iterates over its fields.
|
||||
|
||||
/// 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 {
|
||||
|
||||
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 {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) < get<I>(v2)
|
||||
|| (get<I>(v1) == 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 {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) < get<I>(v2)
|
||||
|| (get<I>(v1) == 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 {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) > get<I>(v2)
|
||||
|| (get<I>(v1) == 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 {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) > get<I>(v2)
|
||||
|| (get<I>(v1) == get<I>(v2) && greater_equal_impl<I + 1, N>::cmp(v1, v2));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct greater_equal_impl<N, N> {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T&, const U&) noexcept {
|
||||
return T::size_v >= U::size_v;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SizeT>
|
||||
constexpr void hash_combine(SizeT& seed, SizeT value) noexcept {
|
||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct hash_impl {
|
||||
template <class T>
|
||||
constexpr static std::size_t compute(const T& val) noexcept {
|
||||
typedef std::decay_t<typename detail::sequence_tuple::tuple_element<I, T>::type> elem_t;
|
||||
std::size_t h = std::hash<elem_t>()( ::boost::pfr::detail::sequence_tuple::get<I>(val) );
|
||||
hash_combine(h, hash_impl<I + 1, N>::compute(val) );
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct hash_impl<N, N> {
|
||||
template <class T>
|
||||
constexpr static std::size_t compute(const T&) noexcept {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////// Define min_element and to avoid inclusion of <algorithm>
|
||||
constexpr std::size_t min_size(std::size_t x, std::size_t y) noexcept {
|
||||
return x < y ? x : y;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
///////////////////// Comparisons
|
||||
|
||||
/// \brief std::equal_to like flattening comparator
|
||||
template <class T = void> struct flat_equal_to {
|
||||
/// \return \b true if each field of \b x equals the field with same index of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
/// \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
|
||||
@@ -172,28 +50,26 @@ template <class T = void> struct flat_equal_to {
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_equal_to<void> {
|
||||
template <> struct equal_to<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::equal_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
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 flattening comparator
|
||||
template <class T = void> struct flat_not_equal {
|
||||
/// \return \b true if at least one field \b x not equals the field with same index of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
/// \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
|
||||
@@ -202,26 +78,26 @@ template <class T = void> struct flat_not_equal {
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_not_equal<void> {
|
||||
template <> struct not_equal<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
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 flattening comparator
|
||||
template <class T = void> struct flat_greater {
|
||||
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x eqeal to the same fields of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::greater_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
/// \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
|
||||
@@ -230,29 +106,26 @@ template <class T = void> struct flat_greater {
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_greater<void> {
|
||||
template <> struct greater<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::greater_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
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 flattening comparator
|
||||
template <class T = void> struct flat_less {
|
||||
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x eqeal to the same fields of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::less_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
/// \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
|
||||
@@ -261,30 +134,27 @@ template <class T = void> struct flat_less {
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_less<void> {
|
||||
template <> struct less<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::less_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
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 flattening comparator
|
||||
template <class T = void> struct flat_greater_equal {
|
||||
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x eqeal 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 noexcept {
|
||||
return detail::greater_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
/// \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
|
||||
@@ -293,30 +163,27 @@ template <class T = void> struct flat_greater_equal {
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_greater_equal<void> {
|
||||
template <> struct greater_equal<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::greater_equal_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
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 flattening comparator
|
||||
template <class T = void> struct flat_less_equal {
|
||||
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x eqeal 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 noexcept {
|
||||
return detail::less_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
/// \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
|
||||
@@ -325,18 +192,15 @@ template <class T = void> struct flat_less_equal {
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_less_equal<void> {
|
||||
template <> struct less_equal<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::less_equal_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
bool operator()(const T& x, const U& y) const {
|
||||
return boost::pfr::le(x, y);
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
@@ -344,11 +208,11 @@ template <> struct flat_less_equal<void> {
|
||||
/// @endcond
|
||||
|
||||
|
||||
/// \brief std::hash like flattening functor
|
||||
template <class T> struct flat_hash {
|
||||
/// \return hash value of \b x
|
||||
std::size_t operator()(const T& x) const noexcept {
|
||||
return detail::hash_impl<0, flat_tuple_size_v<T> >::compute(detail::tie_as_flat_tuple(x));
|
||||
/// \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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,110 +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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/functors.hpp>
|
||||
|
||||
/// \file boost/pfr/global_flat_ops.hpp
|
||||
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.
|
||||
/// If POD is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/global_flat_ops.hpp>
|
||||
/// struct comparable_struct { // No operators defined for that structure
|
||||
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
|
||||
/// };
|
||||
/// // ...
|
||||
///
|
||||
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
/// assert(s1 < s2);
|
||||
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
|
||||
/// \endcode
|
||||
///
|
||||
/// \podops for other ways to define operators and more details.
|
||||
///
|
||||
/// \b This \b header \b defines:
|
||||
/// @cond
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
using enable_comparisons = std::enable_if_t<
|
||||
std::is_same<T, U>::value && std::is_pod<T>::value,
|
||||
bool
|
||||
>;
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
/// @endcond
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
|
||||
|
||||
/// \brief helper function for Boost unordered containers and boost::hash<>.
|
||||
template <class T> std::size_t hash_value(const T& value) noexcept;
|
||||
#else
|
||||
template <class T, class U>
|
||||
static boost::pfr::detail::enable_comparisons<T, U> operator==(const T& lhs, const U& rhs) noexcept {
|
||||
return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
static boost::pfr::detail::enable_comparisons<T, U> operator!=(const T& lhs, const U& rhs) noexcept {
|
||||
return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
static boost::pfr::detail::enable_comparisons<T, U> operator<(const T& lhs, const U& rhs) noexcept {
|
||||
return ::boost::pfr::flat_less<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
static boost::pfr::detail::enable_comparisons<T, U> operator>(const T& lhs, const U& rhs) noexcept {
|
||||
return ::boost::pfr::flat_greater<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
static boost::pfr::detail::enable_comparisons<T, U> operator<=(const T& lhs, const U& rhs) noexcept {
|
||||
return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
static boost::pfr::detail::enable_comparisons<T, U> operator>=(const T& lhs, const U& rhs) noexcept {
|
||||
return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_ostream<Char, Traits>&> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
::boost::pfr::flat_write(out, value);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_istream<Char, Traits>&> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
::boost::pfr::flat_read(in, value);
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
return ::boost::pfr::flat_hash<T>{}(value);
|
||||
}
|
||||
#endif
|
||||
113
include/boost/pfr/io.hpp
Normal file
113
include/boost/pfr/io.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 manipulator to read/write \aggregate `value` using its IO stream operators or using \forcedlink{io_fields} if operators are not available.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i; short s; };
|
||||
/// my_struct x;
|
||||
/// std::stringstream ss;
|
||||
/// ss << "{ 12, 13 }";
|
||||
/// ss >> boost::pfr::io(x);
|
||||
/// assert(x.i == 12);
|
||||
/// assert(x.s == 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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 manipulator \forcedlink{io_fields} to read/write any \aggregate 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: Attempt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier.");
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T>&& ) {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped temporary of type T.");
|
||||
return in;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// IO manipulator 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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 available 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 available 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 available 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 available 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 available 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 available 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 available 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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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
|
||||
60
include/boost/pfr/traits.hpp
Normal file
60
include/boost/pfr/traits.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_TRAITS_HPP
|
||||
#define BOOST_PFR_TRAITS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <boost/pfr/detail/possible_reflectable.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
/// \file boost/pfr/traits.hpp
|
||||
/// Contains traits \forcedlink{is_reflectable} and \forcedlink{is_implicitly_reflectable} for detecting an ability to reflect type.
|
||||
///
|
||||
/// \b Synopsis:
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// Has a static const member variable `value` when it is known that type T can or can't be reflected using Boost.PFR; otherwise, there is no member variable.
|
||||
/// Every user may (and in some difficult cases - should) specialize is_reflectable on his own.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// namespace boost { namespace pfr {
|
||||
/// template<class All> struct is_reflectable<A, All> : std::false_type {}; // 'A' won't be interpreted as reflectable everywhere
|
||||
/// template<> struct is_reflectable<B, boost_fusion_tag> : std::false_type {}; // 'B' won't be interpreted as reflectable in only Boost Fusion
|
||||
/// }}
|
||||
/// \endcode
|
||||
/// \note is_reflectable affects is_implicitly_reflectable, the decision made by is_reflectable is used by is_implicitly_reflectable.
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable { /* does not have 'value' because value is unknown */ };
|
||||
|
||||
// these specs can't be inherited from 'std::integral_constant< bool, boost::pfr::is_reflectable<T, WhatFor>::value >',
|
||||
// because it will break the sfinae-friendliness
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<const T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<const volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
/// Checks the input type for the potential to be reflected.
|
||||
/// Specialize is_reflectable if you disagree with is_implicitly_reflectable's default decision.
|
||||
template<class T, class WhatFor>
|
||||
using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::detail::possible_reflectable<T, WhatFor>(1L) >;
|
||||
|
||||
/// Checks the input type for the potential to be reflected.
|
||||
/// Specialize is_reflectable if you disagree with is_implicitly_reflectable_v's default decision.
|
||||
template<class T, class WhatFor>
|
||||
constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable<T, WhatFor>::value;
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_TRAITS_HPP
|
||||
|
||||
21
include/boost/pfr/traits_fwd.hpp
Normal file
21
include/boost/pfr/traits_fwd.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_TRAITS_FWD_HPP
|
||||
#define BOOST_PFR_DETAIL_TRAITS_FWD_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable;
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_TRAITS_FWD_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-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 satisfies \aggregate.
|
||||
///
|
||||
/// \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 satisfies \aggregate.
|
||||
///
|
||||
/// \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
|
||||
37
index.html
Normal file
37
index.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (c) 2014-2024 Antony Polukhin
|
||||
antoshkka at gmail dot com
|
||||
|
||||
Distributed under the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt
|
||||
or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
boost-no-inspect
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=../../doc/html/boost_pfr.html">
|
||||
<title>Boost.Stacktrace</title>
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
a {
|
||||
color: #00f;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="../../doc/html/boost_pfr.html">../../doc/html/boost_pfr.html</a>
|
||||
</p>
|
||||
<p>
|
||||
© 2014-2024 Antony Polukhin
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
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"
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2016 Antony Polukhin
|
||||
# Copyright (c) 2016-2024 Antony Polukhin
|
||||
# Copyright (c) 2023 Denis Mikhailov
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,100 +11,163 @@
|
||||
import sys
|
||||
import string
|
||||
|
||||
# Skipping some letters that mey produce keywords or are hard to read
|
||||
ascii_letters = string.ascii_letters.replace("o", "").replace("O", "").replace("i", "").replace("I", "")
|
||||
# Skipping some letters that may produce keywords or are hard to read, or shadow template parameters
|
||||
ascii_letters = string.ascii_letters.replace("o", "").replace("O", "").replace("i", "").replace("I", "").replace("T", "")
|
||||
WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE = 3
|
||||
|
||||
PROLOGUE = """// Copyright (c) 2016 Antony Polukhin
|
||||
PROLOGUE = """// Copyright (c) 2016-2024 Antony Polukhin
|
||||
// Copyright (c) 2023 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////// This is an auto generated header. Modify pfr/misc/generate_cpp17.py instead. ////////////////////////////
|
||||
//////////////// 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_CORE17_GENERATED_HPP
|
||||
#define BOOST_PFR_CORE17_GENERATED_HPP
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
|
||||
#define BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201606L /* Oulu meeting, not the exact value */
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
# error C++17 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
#include <type_traits> // for std::conditional_t, std::is_reference
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class... Args>
|
||||
constexpr auto make_tuple_of_references(Args&&... args) noexcept {
|
||||
return sequence_tuple::tuple<Args&...>{ std::forward<Args>(args)... };
|
||||
return sequence_tuple::tuple<Args&...>{ args... };
|
||||
}
|
||||
|
||||
template<typename T, typename Arg>
|
||||
constexpr decltype(auto) add_cv_like(Arg& arg) noexcept {
|
||||
if constexpr (std::is_const<T>::value && std::is_volatile<T>::value) {
|
||||
return const_cast<const volatile Arg&>(arg);
|
||||
}
|
||||
else if constexpr (std::is_const<T>::value) {
|
||||
return const_cast<const Arg&>(arg);
|
||||
}
|
||||
else if constexpr (std::is_volatile<T>::value) {
|
||||
return const_cast<volatile Arg&>(arg);
|
||||
}
|
||||
else {
|
||||
return const_cast<Arg&>(arg);
|
||||
}
|
||||
}
|
||||
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78939
|
||||
template<typename T, typename Sb, typename Arg>
|
||||
constexpr decltype(auto) workaround_cast(Arg& arg) noexcept {
|
||||
using output_arg_t = std::conditional_t<!std::is_reference<Sb>(), decltype(detail::add_cv_like<T>(arg)), Sb>;
|
||||
return const_cast<output_arg_t>(arg);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto as_tuple_impl(T&& /*val*/, size_t_<0>) noexcept {
|
||||
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>* = nullptr) noexcept {
|
||||
auto& [a] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
|
||||
return ::boost::pfr::detail::make_tuple_of_references(detail::workaround_cast<T, decltype(a)>(a));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
|
||||
return ::boost::pfr::detail::make_tuple_of_references( val );
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
############################################################################################################################
|
||||
EPILOGUE = """
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
constexpr auto as_tuple(const T& val) noexcept {
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return detail::as_tuple_impl(val, fields_count_tag{});
|
||||
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`");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto as_tuple(T& val) noexcept {
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return detail::as_tuple_impl(val, fields_count_tag{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using as_tuple_t = decltype( ::boost::pfr::detail::as_tuple(std::declval<T&>()) );
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_CORE17_GENERATED_HPP
|
||||
#endif // BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
|
||||
"""
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
indexes = ""
|
||||
print PROLOGUE
|
||||
def fold_workaround_cast(indexes, divider):
|
||||
WORKAROUND_CAST_TEMPLATE = """
|
||||
detail::workaround_cast<T, decltype({arg})>({arg})
|
||||
"""
|
||||
lines = []
|
||||
div = ''
|
||||
tokens = [x.strip() for x in indexes.split(',')]
|
||||
casts = [WORKAROUND_CAST_TEMPLATE.strip().format(arg=tok)
|
||||
for tok in tokens]
|
||||
for i in range(0, len(casts)):
|
||||
if i%WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE==0:
|
||||
div = ''
|
||||
lines.append('')
|
||||
lines[-1] += div + casts[i]
|
||||
div = ','
|
||||
return divider.join(lines)
|
||||
|
||||
def calc_indexes_count(indexes):
|
||||
tokens = [x.strip() for x in indexes.split(',')]
|
||||
return len(tokens)
|
||||
|
||||
class EmptyLinePrinter:
|
||||
def print_once(self):
|
||||
if not self.printed:
|
||||
print("")
|
||||
self.printed = True
|
||||
printed = False
|
||||
|
||||
indexes = " a"
|
||||
print(PROLOGUE)
|
||||
funcs_count = 100 if len(sys.argv) == 1 else int(sys.argv[1])
|
||||
max_args_on_a_line = len(ascii_letters)
|
||||
for i in xrange(funcs_count):
|
||||
if i == 0:
|
||||
indexes = " "
|
||||
elif i % max_args_on_a_line == 0:
|
||||
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 - 1]
|
||||
indexes += ascii_letters[i % max_args_on_a_line]
|
||||
|
||||
print "template <class T>"
|
||||
print "constexpr auto as_tuple_impl(T&& val, size_t_<" + str(i + 1) + ">) noexcept {"
|
||||
printed_casts = fold_workaround_cast(indexes.strip(), ",\n ")
|
||||
indexes_count = calc_indexes_count(indexes.strip())
|
||||
empty_printer = EmptyLinePrinter()
|
||||
|
||||
print("template <class T>")
|
||||
print("constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {")
|
||||
if i < max_args_on_a_line:
|
||||
print " auto& [" + indexes.strip() + "] = std::forward<T>(val);"
|
||||
print " return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");"
|
||||
print(" auto& [" + indexes.strip() + "] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
else:
|
||||
print " auto& ["
|
||||
print indexes
|
||||
print " ] = std::forward<T>(val);"
|
||||
print ""
|
||||
print " return ::boost::pfr::detail::make_tuple_of_references("
|
||||
print indexes
|
||||
print " );"
|
||||
print(" auto& [")
|
||||
print(indexes)
|
||||
print(" ] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
|
||||
empty_printer.print_once()
|
||||
|
||||
if indexes_count < WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE:
|
||||
print(" return ::boost::pfr::detail::make_tuple_of_references(" + printed_casts + ");")
|
||||
else:
|
||||
empty_printer.print_once()
|
||||
print(" return ::boost::pfr::detail::make_tuple_of_references(")
|
||||
print(" " + printed_casts)
|
||||
print(" );")
|
||||
|
||||
print "}\n"
|
||||
print("}\n")
|
||||
|
||||
print EPILOGUE
|
||||
print(EPILOGUE)
|
||||
|
||||
267
misc/generate_fields_names_big.cpp.py
Normal file
267
misc/generate_fields_names_big.cpp.py
Normal file
@@ -0,0 +1,267 @@
|
||||
# Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
# Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
# The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
#
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
import sys
|
||||
import string
|
||||
import random
|
||||
|
||||
# a bigger value might lead to compiler out of heap space error on MSVC
|
||||
STRUCT_COUNT = 50
|
||||
MAX_FIELD_COUNT = 50
|
||||
|
||||
MAIN_TEMPLATE = """// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov, Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Generated by misc/generate_fields_names_big.cpp.py
|
||||
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing {
|
||||
|
||||
template <class... Types>
|
||||
auto make_stdarray(const Types&... t) {
|
||||
return std::array<std::common_type_t<Types...>, sizeof...(Types)>{t...};
|
||||
}
|
||||
|
||||
%STRUCTS_LIST%
|
||||
|
||||
%TEST_GET_NAME_DEFINITIONS_LIST%
|
||||
|
||||
%TEST_GET_NAMES_AS_ARRAY_DEFINITIONS_LIST%
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
%TEST_GET_NAME_CALLS_LIST%
|
||||
%TEST_GET_NAMES_AS_ARRAY_CALLS_LIST%
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
"""
|
||||
|
||||
STRUCT_TEMPLATE = """struct Aggregate%STRUCT_ID% {
|
||||
%FIELD_DEFINITIONS_LIST%
|
||||
};
|
||||
"""
|
||||
|
||||
STRUCT_FIELD_DEFINITION_TEMPLATE = """int %FIELD_NAME%;
|
||||
"""
|
||||
|
||||
TEST_GET_NAME_TEMPLATE = """void test_get_name_%TEST_ID%() {
|
||||
%CHECKERS_LIST%
|
||||
}
|
||||
"""
|
||||
|
||||
TEST_GET_NAME_CHECKER_TEMPLATE = """BOOST_TEST_EQ( ((boost::pfr::get_name<%FIELD_ID%, Aggregate%STRUCT_ID%>())), "%FIELD_NAME%");
|
||||
"""
|
||||
|
||||
TEST_GET_NAMES_AS_ARRAY_TEMPLATE = """void test_names_as_array_%TEST_ID%() {
|
||||
const auto expected = make_stdarray(
|
||||
%FIELD_NAMES_LIST%
|
||||
);
|
||||
const auto value = boost::pfr::names_as_array<Aggregate%STRUCT_ID%>();
|
||||
BOOST_TEST_EQ(expected.size(), value.size());
|
||||
for (std::size_t i=0;i<expected.size();++i) {
|
||||
BOOST_TEST_EQ(value[i], expected[i]);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
FIELD_NAME_TEMPLATE = """std::string_view{"%FIELD_NAME%"}
|
||||
"""
|
||||
|
||||
TEST_GET_NAME_CALL_TEMPLATE = """testing::test_get_name_%TEST_ID%();
|
||||
"""
|
||||
|
||||
TEST_GET_NAMES_AS_ARRAY_CALL_TEMPLATE = """testing::test_names_as_array_%TEST_ID%();
|
||||
"""
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
field_names = {
|
||||
"alignas": True,
|
||||
"alignof": True,
|
||||
"and": True,
|
||||
"and_eq": True,
|
||||
"asm": True,
|
||||
"atomic_cancel": True,
|
||||
"atomic_commit": True,
|
||||
"atomic_noexcept": True,
|
||||
"auto": True,
|
||||
"bitand": True,
|
||||
"bitor": True,
|
||||
"bool": True,
|
||||
"break": True,
|
||||
"case": True,
|
||||
"catch": True,
|
||||
"char": True,
|
||||
"char8_t": True,
|
||||
"char16_t": True,
|
||||
"char32_t": True,
|
||||
"class": True,
|
||||
"compl": True,
|
||||
"concept": True,
|
||||
"const": True,
|
||||
"consteval": True,
|
||||
"constexpr": True,
|
||||
"constinit": True,
|
||||
"const_cast": True,
|
||||
"continue": True,
|
||||
"co_await": True,
|
||||
"co_return": True,
|
||||
"co_yield": True,
|
||||
"decltype": True,
|
||||
"default": True,
|
||||
"delete": True,
|
||||
"do": True,
|
||||
"double": True,
|
||||
"dynamic_cast": True,
|
||||
"else": True,
|
||||
"enum": True,
|
||||
"explicit": True,
|
||||
"export": True,
|
||||
"extern": True,
|
||||
"false": True,
|
||||
"float": True,
|
||||
"for": True,
|
||||
"friend": True,
|
||||
"goto": True,
|
||||
"if": True,
|
||||
"inline": True,
|
||||
"int": True,
|
||||
"long": True,
|
||||
"mutable": True,
|
||||
"namespace": True,
|
||||
"new": True,
|
||||
"noexcept": True,
|
||||
"not": True,
|
||||
"not_eq": True,
|
||||
"nullptr": True,
|
||||
"operator": True,
|
||||
"or": True,
|
||||
"or_eq": True,
|
||||
"private": True,
|
||||
"protected": True,
|
||||
"public": True,
|
||||
"reflexpr": True,
|
||||
"register": True,
|
||||
"reinterpret_cast": True,
|
||||
"requires": True,
|
||||
"return": True,
|
||||
"short": True,
|
||||
"signed": True,
|
||||
"sizeof": True,
|
||||
"static": True,
|
||||
"static_assert": True,
|
||||
"static_cast": True,
|
||||
"struct": True,
|
||||
"switch": True,
|
||||
"synchronized": True,
|
||||
"template": True,
|
||||
"this": True,
|
||||
"thread_local": True,
|
||||
"throw": True,
|
||||
"true": True,
|
||||
"try": True,
|
||||
"typedef": True,
|
||||
"typeid": True,
|
||||
"typename": True,
|
||||
"union": True,
|
||||
"unsigned": True,
|
||||
"using": True,
|
||||
"virtual": True,
|
||||
"void": True,
|
||||
"volatile": True,
|
||||
"wchar_t": True,
|
||||
"while": True,
|
||||
"xor": True,
|
||||
"xor_eq": True
|
||||
}
|
||||
field_names_by_id = {}
|
||||
|
||||
def generate_new_field_name():
|
||||
result = ''
|
||||
name_len = random.randint(1,100)
|
||||
result += random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")
|
||||
for i in range(name_len-1):
|
||||
result += random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")
|
||||
return result
|
||||
|
||||
def generate_field_name(struct_id, field_id):
|
||||
key = (struct_id, field_id)
|
||||
if not key in field_names_by_id:
|
||||
new_name = generate_new_field_name()
|
||||
while new_name in field_names:
|
||||
new_name = generate_new_field_name()
|
||||
field_names[new_name] = True
|
||||
field_names_by_id[key] = new_name
|
||||
return field_names_by_id[key]
|
||||
|
||||
def generate_struct(struct_id):
|
||||
field_definitions = ''
|
||||
fields_count = struct_id
|
||||
for i in range(fields_count):
|
||||
field_definitions += STRUCT_FIELD_DEFINITION_TEMPLATE.replace('%FIELD_NAME%', generate_field_name(struct_id, i))
|
||||
return STRUCT_TEMPLATE.replace('%FIELD_DEFINITIONS_LIST%', field_definitions).replace('%STRUCT_ID%', str(struct_id))
|
||||
|
||||
def generate_structs_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += generate_struct(i+1)
|
||||
return result
|
||||
|
||||
def generate_test_get_name_definition(struct_id):
|
||||
checkers_list = ''
|
||||
fields_count = struct_id
|
||||
for i in range(fields_count):
|
||||
checkers_list += TEST_GET_NAME_CHECKER_TEMPLATE.replace('%FIELD_ID%', str(i)).replace('%STRUCT_ID%', str(struct_id)).replace('%FIELD_NAME%', generate_field_name(struct_id, i))
|
||||
return TEST_GET_NAME_TEMPLATE.replace('%TEST_ID%', str(struct_id)).replace('%CHECKERS_LIST%', checkers_list)
|
||||
|
||||
def generate_test_get_name_definitions_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += generate_test_get_name_definition(i+1)
|
||||
return result
|
||||
|
||||
def generate_test_names_as_array_definition(struct_id):
|
||||
field_names_list = FIELD_NAME_TEMPLATE.replace('%FIELD_NAME%', generate_field_name(struct_id, 0))
|
||||
fields_count = struct_id
|
||||
for i in range(1, fields_count):
|
||||
field_names_list += ', ' + FIELD_NAME_TEMPLATE.replace('%FIELD_NAME%', generate_field_name(struct_id, i))
|
||||
return TEST_GET_NAMES_AS_ARRAY_TEMPLATE.replace('%TEST_ID%', str(struct_id)).replace('%FIELD_NAMES_LIST%', field_names_list).replace('%STRUCT_ID%', str(struct_id))
|
||||
|
||||
def generate_test_names_as_array_definitions_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += generate_test_names_as_array_definition(i+1)
|
||||
return result
|
||||
|
||||
def generate_test_get_name_calls_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += TEST_GET_NAME_CALL_TEMPLATE.replace('%TEST_ID%', str(i+1))
|
||||
return result
|
||||
|
||||
def generate_test_names_as_array_calls_list():
|
||||
result = ''
|
||||
for i in range(STRUCT_COUNT):
|
||||
result += TEST_GET_NAMES_AS_ARRAY_CALL_TEMPLATE.replace('%TEST_ID%', str(i+1))
|
||||
return result
|
||||
|
||||
print(MAIN_TEMPLATE.replace('%STRUCTS_LIST%', generate_structs_list()).replace('%TEST_GET_NAME_DEFINITIONS_LIST%', generate_test_get_name_definitions_list()).replace('%TEST_GET_NAMES_AS_ARRAY_DEFINITIONS_LIST%', generate_test_names_as_array_definitions_list()).replace('%TEST_GET_NAME_CALLS_LIST%', generate_test_get_name_calls_list()).replace('%TEST_GET_NAMES_AS_ARRAY_CALLS_LIST%', generate_test_names_as_array_calls_list()))
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
cat ../include/boost/pfr/core.hpp
|
||||
sed -e '1,/boost\/pfr/d' ../include/boost/pfr/functors.hpp
|
||||
sed -e '1,/boost\/pfr/d' ../include/boost/pfr/flat_functions_for.hpp
|
||||
sed -e '1,/boost\/pfr/d' ../include/boost/pfr/flat_ops.hpp
|
||||
84
misc/strip_boost_namespace.sh
Executable file
84
misc/strip_boost_namespace.sh
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2021 Antony Polukhin
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
echo "***** Making target path"
|
||||
TARGET_PATH="`dirname \"$0\"`/../../pfr_non_boost"
|
||||
rm -rf ${TARGET_PATH}/*
|
||||
mkdir -p ${TARGET_PATH}
|
||||
TARGET_PATH=`cd "${TARGET_PATH}";pwd`
|
||||
|
||||
SOURCE_PATH="`dirname \"$0\"`/.."
|
||||
SOURCE_PATH=`cd "${SOURCE_PATH}";pwd`
|
||||
|
||||
echo "***** Copying from ${SOURCE_PATH} to ${TARGET_PATH}"
|
||||
cp -rf ${SOURCE_PATH}/* ${TARGET_PATH}
|
||||
|
||||
mv ${TARGET_PATH}/include/boost/* ${TARGET_PATH}/include/
|
||||
rm -rf ${TARGET_PATH}/include/boost
|
||||
rm -rf ${TARGET_PATH}/test
|
||||
rm ${TARGET_PATH}/misc/strip_boost_namespace.sh
|
||||
rm -rf ${TARGET_PATH}/meta
|
||||
|
||||
echo "***** Changing sources"
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|namespace boost { ||g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|namespace boost {||g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|} // namespace boost::| // namespace |g'
|
||||
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's/::boost::pfr/::pfr/g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's/boost::pfr/pfr/g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's/BOOST_PFR_/PFR_/g'
|
||||
find ${TARGET_PATH} -type f | xargs sed -i 's|boost/pfr|pfr|g'
|
||||
|
||||
find ${TARGET_PATH}/doc -type f | xargs sed -i 's|boost.pfr.|pfr.|g'
|
||||
find ${TARGET_PATH}/doc -type f | xargs sed -i 's|Boost.PFR|PFR|g'
|
||||
|
||||
sed -i 's|# \[Boost.PFR\](https://boost.org/libs/pfr)|# [PFR](https://apolukhin.github.io/pfr_non_boost/)|g' ${TARGET_PATH}/README.md
|
||||
|
||||
echo -n "***** Testing: "
|
||||
if g++-12 -std=c++2a -DPFR_ENABLE_GET_NAME_STATIC=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n "OK"
|
||||
else
|
||||
echo -n "FAIL"
|
||||
exit 2
|
||||
fi
|
||||
if g++-12 -std=c++2a -DPFR_ENABLE_GET_NAME_STATIC=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n "OK"
|
||||
else
|
||||
echo -n "FAIL"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
if g++-12 -std=c++2a -DPFR_ENABLE_GET_NAME_STATIC=1 -DBOOST_PFR_USE_CPP17=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/get_name.cpp && ./a.out > /dev/null; then
|
||||
echo -e ", OK"
|
||||
else
|
||||
echo -e ", FAIL"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
if g++-12 -std=c++2a -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n "OK"
|
||||
else
|
||||
echo -n "FAIL"
|
||||
exit 5
|
||||
fi
|
||||
if g++-12 -std=c++2a -DPFR_USE_LOOPHOLE=1 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
|
||||
echo -n ", OK"
|
||||
else
|
||||
echo -n ", FAIL"
|
||||
exit 6
|
||||
fi
|
||||
|
||||
if g++-12 -std=c++2a -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/get.cpp && ./a.out > /dev/null; then
|
||||
echo -e ", OK"
|
||||
else
|
||||
echo -e ", FAIL"
|
||||
exit 7
|
||||
fi
|
||||
|
||||
rm a.out || :
|
||||
|
||||
echo "***** Done"
|
||||
10
test/Jamfile
Normal file
10
test/Jamfile
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2023 Denis Mikhailov
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
build-project config ;
|
||||
build-project core ;
|
||||
build-project core_name ;
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (C) 2016, 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)
|
||||
#
|
||||
|
||||
test-suite pfr
|
||||
:
|
||||
[ run core.cpp ]
|
||||
[ run minimal.cpp ]
|
||||
[ run count_fields_on_chars.cpp ]
|
||||
# [ run count_fields_on_ints.cpp ]
|
||||
# [ run count_fields_on_long_longs.cpp ]
|
||||
# [ run count_fields_on_shorts.cpp ]
|
||||
[ run count_fields_on_void_ptrs.cpp ]
|
||||
[ run std_interactions.cpp ]
|
||||
[ run flat_functions_for.cpp ]
|
||||
[ run flat_ops.cpp ]
|
||||
[ run global_flat_ops.cpp ]
|
||||
[ compile-fail non_aggregate1.cpp ]
|
||||
[ compile-fail non_aggregate2.cpp ]
|
||||
[ compile-fail bitfields.cpp ]
|
||||
[ run motivating_example.cpp ]
|
||||
[ run ../example/examples.cpp ]
|
||||
[ run only_fields_count.cpp ]
|
||||
;
|
||||
|
||||
|
||||
104
test/appveyor.yml
Normal file
104
test/appveyor.yml
Normal file
@@ -0,0 +1,104 @@
|
||||
# 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-2021.
|
||||
|
||||
#
|
||||
# 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 2015
|
||||
TOOLSET: msvc-9.0
|
||||
ADDRMD: 32
|
||||
CXXSTD: latest # fake
|
||||
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
# TOOLSET: msvc # TODO: clang-win ???
|
||||
# ADDRMD: 32,64
|
||||
# CXXSTD: 17,latest
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
|
||||
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:
|
||||
22
test/config/Jamfile.v2
Normal file
22
test/config/Jamfile.v2
Normal file
@@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2023 Denis Mikhailov
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
import python ;
|
||||
import testing ;
|
||||
import ../../config/checks/config : requires ;
|
||||
|
||||
project
|
||||
: source-location .
|
||||
: requirements
|
||||
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
|
||||
;
|
||||
|
||||
|
||||
test-suite pfr_tests
|
||||
:
|
||||
[ run print_config.cpp : : : <test-info>always_show_run_output : auto_engine_config ]
|
||||
;
|
||||
45
test/config/print_config.cpp
Normal file
45
test/config/print_config.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/config.hpp>
|
||||
#if BOOST_PFR_ENABLED
|
||||
#include <boost/pfr.hpp>
|
||||
#endif
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Platform info:" << '\n'
|
||||
<< "BOOST_PFR_USE_CPP17 == " << BOOST_PFR_USE_CPP17 << '\n'
|
||||
<< "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n'
|
||||
<< "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n'
|
||||
<< "BOOST_PFR_HAS_GUARANTEED_COPY_ELISION == " << BOOST_PFR_HAS_GUARANTEED_COPY_ELISION << '\n'
|
||||
<< "BOOST_PFR_ENABLE_IMPLICIT_REFLECTION == " << BOOST_PFR_ENABLE_IMPLICIT_REFLECTION << '\n'
|
||||
<< "BOOST_PFR_CORE_NAME_ENABLED == " << BOOST_PFR_CORE_NAME_ENABLED << '\n'
|
||||
<< "BOOST_PFR_FUNCTION_SIGNATURE == " << BOOST_PP_STRINGIZE(BOOST_PFR_FUNCTION_SIGNATURE) << '\n'
|
||||
<< "BOOST_PFR_CORE_NAME_PARSING == " << BOOST_PP_STRINGIZE(BOOST_PFR_CORE_NAME_PARSING) << '\n'
|
||||
<< "BOOST_PFR_ENABLED == " << BOOST_PFR_ENABLED << '\n'
|
||||
<< "__cplusplus == " << __cplusplus << '\n'
|
||||
#ifdef __cpp_structured_bindings
|
||||
<< "__cpp_structured_bindings == " << __cpp_structured_bindings << '\n'
|
||||
#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
|
||||
;
|
||||
}
|
||||
709
test/core.cpp
709
test/core.cpp
@@ -1,709 +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)
|
||||
|
||||
//#define BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
//#include <boost/type_index.hpp> // for debugging
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
#include <cstring>
|
||||
|
||||
using namespace boost::pfr;
|
||||
|
||||
template <std::size_t I, class T>
|
||||
void print(T& f) {
|
||||
std::cout << flat_get<I>(f) << "\t\t"
|
||||
<< typeid(flat_tuple_element_t<I, T>).name()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
struct make_my_life_harder { int a0; short a1; };
|
||||
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
|
||||
struct foo {
|
||||
unsigned char v0;
|
||||
unsigned int v1;
|
||||
unsigned short v2;
|
||||
unsigned long long v3;
|
||||
unsigned char v4and5[2];
|
||||
int v6;
|
||||
std::size_t v7;
|
||||
int* v8;
|
||||
const void* v9;
|
||||
int const**const volatile**volatile** v10;
|
||||
const double v11;
|
||||
make_my_life_harder v12and13;
|
||||
make_my_life_even_more_harder v14and15andv16and17;
|
||||
};
|
||||
|
||||
void test_print() {
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
print<0>(f); print<1>(f); print<2>(f);
|
||||
print<3>(f); print<4>(f); print<5>(f);
|
||||
print<6>(f); print<7>(f); print<8>(f);
|
||||
print<9>(f); print<10>(f); print<11>(f);
|
||||
print<12>(f); print<13>(f); print<14>(f);
|
||||
print<15>(f); print<16>(f); print<17>(f);
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
|
||||
int a[] = {0, 1, 2, 3};
|
||||
std::cout << '\n' << flat_get<1>(a) << std::endl;
|
||||
|
||||
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
|
||||
std::cout << flat_get<4>(b) << std::endl;
|
||||
|
||||
int i = 777;
|
||||
std::cout << flat_get<0>(i) << std::endl;
|
||||
}
|
||||
|
||||
void test_runtime(const foo& f) {
|
||||
BOOST_TEST_EQ( flat_get<0>(f), f.v0);
|
||||
BOOST_TEST_EQ( flat_get<1>(f), f.v1);
|
||||
BOOST_TEST_EQ( flat_get<2>(f), f.v2);
|
||||
BOOST_TEST_EQ( flat_get<3>(f), f.v3);
|
||||
BOOST_TEST_EQ( flat_get<4>(f), f.v4and5[0]);
|
||||
BOOST_TEST_EQ( flat_get<5>(f), f.v4and5[1]);
|
||||
BOOST_TEST_EQ( flat_get<6>(f), f.v6);
|
||||
BOOST_TEST_EQ( flat_get<7>(f), f.v7);
|
||||
BOOST_TEST_EQ( flat_get<8>(f), f.v8);
|
||||
BOOST_TEST_EQ( flat_get<9>(f), f.v9);
|
||||
BOOST_TEST_EQ( flat_get<10>(f), f.v10);
|
||||
BOOST_TEST( flat_get<11>(f) < f.v11 + 0.001); BOOST_TEST( flat_get<11>(f) > f.v11 - 0.001);
|
||||
BOOST_TEST_EQ( flat_get<12>(f), f.v12and13.a0);
|
||||
BOOST_TEST_EQ( flat_get<13>(f), f.v12and13.a1);
|
||||
BOOST_TEST_EQ( flat_get<14>(f), f.v14and15andv16and17.b0);
|
||||
BOOST_TEST_EQ( flat_get<15>(f), f.v14and15andv16and17.b1);
|
||||
BOOST_TEST_EQ( flat_get<16>(f), f.v14and15andv16and17.cr.a0);
|
||||
BOOST_TEST_EQ( flat_get<17>(f), f.v14and15andv16and17.cr.a1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_compiletime() {
|
||||
constexpr T f{};
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void test_compiletime_array() {
|
||||
{
|
||||
constexpr T f[20] = {0};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][10] = {{0}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][5][2] = {{{0}}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
}
|
||||
|
||||
void test_with_enums() {
|
||||
enum class my_enum: unsigned {
|
||||
VALUE1 = 17, VALUE2, VALUE3
|
||||
};
|
||||
struct my_struct { my_enum e; int i; short s; };
|
||||
my_struct s {my_enum::VALUE1, 10, 11};
|
||||
std::tuple<unsigned, int, short> t = flat_structure_to_tuple(s);
|
||||
BOOST_TEST_EQ(std::get<0>(t), 17u);
|
||||
BOOST_TEST_EQ(std::get<1>(t), 10);
|
||||
BOOST_TEST_EQ(std::get<2>(t), 11);
|
||||
|
||||
flat_get<1>(s) = 101;
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 101);
|
||||
flat_get<2>(s) = 111;
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 111);
|
||||
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_tie(s));
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_to_tuple(s));
|
||||
BOOST_TEST(flat_structure_tie(s) != t);
|
||||
flat_structure_tie(s) = t;
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 17u);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 10);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 11);
|
||||
|
||||
static_assert(std::is_same<
|
||||
int, flat_tuple_element_t<1, my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
short, flat_tuple_element_t<2, my_struct>
|
||||
>::value, "");
|
||||
|
||||
|
||||
static_assert(std::is_same<
|
||||
const int, flat_tuple_element_t<1, const my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
volatile short, flat_tuple_element_t<2, volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(
|
||||
3 == flat_tuple_size_v<const volatile my_struct>,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
using namespace flat_ops;
|
||||
|
||||
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST(s1 == s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
BOOST_TEST(!(s1 != s2));
|
||||
BOOST_TEST(!(s1 == s3));
|
||||
BOOST_TEST(s1 != s3);
|
||||
BOOST_TEST(s1 < s3);
|
||||
BOOST_TEST(s3 > s2);
|
||||
BOOST_TEST(s1 <= s3);
|
||||
BOOST_TEST(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
BOOST_TEST(s1 == s4);
|
||||
int i = 1, j = 2;
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
using namespace flat_ops;
|
||||
|
||||
std::cout << empty{} << std::endl;
|
||||
|
||||
BOOST_TEST(empty{} == empty{});
|
||||
}
|
||||
|
||||
|
||||
void test_pods_with_int_operators() {
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::is_pod<int>{};
|
||||
int i = 0;
|
||||
ss >> i;
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
std::cout << i << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void test_struct_with_single_field() {
|
||||
struct f1 { int i; };
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << f1{ 777 };
|
||||
f1 var{};
|
||||
ss >> var;
|
||||
BOOST_TEST_EQ(var.i, 777);
|
||||
BOOST_TEST(var == f1{ 777 });
|
||||
BOOST_TEST(var != f1{ 778 });
|
||||
|
||||
BOOST_TEST(var <= f1{ 777 });
|
||||
BOOST_TEST(var <= f1{ 778 });
|
||||
BOOST_TEST(var < f1{ 778 });
|
||||
|
||||
BOOST_TEST(var >= f1{ 777 });
|
||||
BOOST_TEST(var >= f1{ 776 });
|
||||
BOOST_TEST(var > f1{ 776 });
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void test_with_contatiners() {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
struct testing2 { bool b1, b2; int i; };
|
||||
std::set<testing, Comparator > t{
|
||||
{true, true, 100},
|
||||
{false, true, 100},
|
||||
{true, false, 100},
|
||||
{true, true, 101}
|
||||
};
|
||||
|
||||
BOOST_TEST(t.find({true, true, 100}) != t.end());
|
||||
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
|
||||
BOOST_TEST(t.find(testing2{true, true, 100}) != t.end());
|
||||
|
||||
std::set<testing2, Comparator > t2{
|
||||
{true, true, 101},
|
||||
{true, true, 100},
|
||||
{true, false, 100},
|
||||
{false, true, 100}
|
||||
};
|
||||
|
||||
BOOST_TEST(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
|
||||
BOOST_TEST(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
|
||||
|
||||
std::vector<testing> res;
|
||||
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
|
||||
std::back_inserter(res), Comparator{});
|
||||
|
||||
BOOST_TEST_EQ(res.size(), 4u);
|
||||
}
|
||||
|
||||
void test_with_user_defined_constructor() {
|
||||
struct pr {
|
||||
int i;
|
||||
short s;
|
||||
|
||||
pr() = default;
|
||||
pr(const pr&) = default;
|
||||
pr(pr&&) = default;
|
||||
pr(int ii, short is) noexcept
|
||||
: i(ii), s(is)
|
||||
{}
|
||||
};
|
||||
|
||||
pr p{1, 2};
|
||||
|
||||
//assert(flat_get<1>(p) == 2); // Compilation error
|
||||
}
|
||||
|
||||
void test_hash() {
|
||||
struct almost_pair { int i; short s; };
|
||||
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
|
||||
s.insert({0, 1});
|
||||
s.insert({1, 0});
|
||||
s.insert({1, 1});
|
||||
|
||||
BOOST_TEST_EQ(s.size(), 3u);
|
||||
flat_hash<almost_pair> hs;
|
||||
BOOST_TEST_NE(hs({0, 1}), hs({1, 0}));
|
||||
BOOST_TEST_EQ(hs({0, 1}), hs({0, 1}));
|
||||
BOOST_TEST_EQ(hs({1, 1}), hs({1, 1}));
|
||||
BOOST_TEST_NE(hs({0, 0}), hs({1, 1}));
|
||||
|
||||
struct single_field { int i; };
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({1}), std::hash<int>()(1));
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({199}), std::hash<int>()(199));
|
||||
}
|
||||
|
||||
// Test case by Lisa Lippincott
|
||||
void test_alignment_with_nested_structure() {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
B0 test_struct;
|
||||
std::memset(&test_struct, 0, sizeof(test_struct));
|
||||
test_struct.a.s = 0;
|
||||
test_struct.a.c = '1';
|
||||
test_struct.c1 = '2';
|
||||
test_struct.c2 = '3';
|
||||
BOOST_TEST_EQ(flat_get<0>(test_struct), 0);
|
||||
BOOST_TEST_EQ(flat_get<1>(test_struct), '1');
|
||||
BOOST_TEST_EQ(flat_get<2>(test_struct), '2');
|
||||
BOOST_TEST_EQ(flat_get<3>(test_struct), '3');
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t... I>
|
||||
void test_and_debug_internals(std::index_sequence<I...>) {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
A0 a0 { 3, '4' };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(a0), 3);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(a0), '4');
|
||||
|
||||
struct A1 {
|
||||
int i;
|
||||
};
|
||||
|
||||
struct B1 {
|
||||
A1 a;
|
||||
int j;
|
||||
};
|
||||
|
||||
B1 b1 { {5}, 6 };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(b1), 5);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(b1), 6);
|
||||
/*
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
typedef B0 type;
|
||||
typedef B0 T;
|
||||
|
||||
using namespace boost::pfr::detail;
|
||||
constexpr auto a = flat_array_of_type_ids<T>();
|
||||
(void)a; // `a` is unused if T is an empty type
|
||||
|
||||
constexpr size_array<a.size()> skips_in_subtuples {{
|
||||
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
|
||||
}};
|
||||
|
||||
constexpr size_array<sizeof...(I) + 1> indexes_in_subtuples_uncleanuped {{ 1, 1 + I...}};
|
||||
constexpr auto indexes_plus_1_and_zeros_as_skips = remove_skips(indexes_in_subtuples_uncleanuped, skips_in_subtuples);
|
||||
constexpr auto new_size = size_t_<indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
|
||||
constexpr auto indexes = resize_dropping_zeros_and_decrementing(new_size, indexes_plus_1_and_zeros_as_skips);
|
||||
static_assert(indexes.data[0] == 0, "");
|
||||
static_assert(indexes.data[1] == 4, "");
|
||||
static_assert(indexes.data[2] == 5, "");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
decltype(boost::pfr::detail::as_flat_tuple_impl<type>(
|
||||
std::make_index_sequence< decltype(boost::pfr::detail::flat_array_of_type_ids<type>())::size() >()
|
||||
)),
|
||||
boost::pfr::detail::sequence_tuple::tuple<boost::pfr::detail::sequence_tuple::tuple<short, char>, char, char>
|
||||
>::value,
|
||||
""
|
||||
);
|
||||
|
||||
constexpr auto res = as_flat_tuple_impl<foo>(
|
||||
std::make_index_sequence< decltype(flat_array_of_type_ids<foo>())::size() >()
|
||||
);
|
||||
auto afoo = flat_array_of_type_ids<foo>();
|
||||
std::cerr << "\n\n";
|
||||
for (std::size_t i = 0; i < afoo.size(); ++i) {
|
||||
std::cerr << afoo.data[i] << ' ';
|
||||
}
|
||||
|
||||
std::cerr << boost::typeindex::type_id<decltype(res)>() << "\n\n";*/
|
||||
}
|
||||
|
||||
|
||||
// test by Alexey Moiseytsev
|
||||
void another_test_with_unusual_alignment() {
|
||||
struct nested {
|
||||
char c0;
|
||||
char c1;
|
||||
int i0;
|
||||
short s0;
|
||||
char c2;
|
||||
};
|
||||
|
||||
struct pair {
|
||||
nested n0;
|
||||
nested n1;
|
||||
};
|
||||
|
||||
// layout:
|
||||
// offset struct tuple
|
||||
// 0 n0.c0 n0.c0
|
||||
// 1 n0.c1 n0.c1
|
||||
// 2 padding padding
|
||||
// 3 padding padding
|
||||
// 4 n0.i0 n0.i0
|
||||
// 5 n0.i0 n0.i0
|
||||
// 6 n0.i0 n0.i0
|
||||
// 7 n0.i0 n0.i0
|
||||
// 8 n0.s0 n0.s0
|
||||
// 9 n0.s0 n0.s0
|
||||
// 10 n0.c2 n0.c2
|
||||
// 11 padding n1.c0 !!!
|
||||
// 12 n1.c0 n1.c1 !!!
|
||||
// 13 n1.c1 padding !!!
|
||||
// 14 padding padding
|
||||
// 15 padding padding
|
||||
// 16 n1.i0 n1.i0
|
||||
// 17 n1.i0 n1.i0
|
||||
// 18 n1.i0 n1.i0
|
||||
// 19 n1.i0 n1.i0
|
||||
// 20 n1.s0 n1.s0
|
||||
// 21 n1.s0 n1.s0
|
||||
// 22 n1.c2 n1.c2
|
||||
// 23 padding padding
|
||||
|
||||
pair s{{'q', 'w', 12, 32, 'e'}, {'a', 's', 24, 64, 'd'}};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 'q');
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 'w');
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 12);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 32);
|
||||
BOOST_TEST_EQ(flat_get<4>(s), 'e');
|
||||
|
||||
BOOST_TEST_EQ(flat_get<5>(s), 'a');
|
||||
BOOST_TEST_EQ(flat_get<6>(s), 's');
|
||||
BOOST_TEST_EQ(flat_get<7>(s), 24);
|
||||
BOOST_TEST_EQ(flat_get<8>(s), 64);
|
||||
BOOST_TEST_EQ(flat_get<9>(s), 'd');
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_default_values() {
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
};
|
||||
|
||||
test_me s;
|
||||
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_st_layout_structure_with_non_constexpr_type() {
|
||||
/* TODO: fixme
|
||||
struct non_literal_structure {
|
||||
int i1 = 3;
|
||||
short s1 = 15;
|
||||
|
||||
non_literal_structure() = delete;
|
||||
non_literal_structure(const non_literal_structure&) = delete;
|
||||
non_literal_structure(non_literal_structure&&) = default;
|
||||
non_literal_structure& operator=(const non_literal_structure&) = delete;
|
||||
non_literal_structure& operator=(non_literal_structure&&) = delete;
|
||||
};
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
non_literal_structure nonlit{};
|
||||
};
|
||||
|
||||
BOOST_TEST_EQ(tuple_size_v<test_me>, 3);
|
||||
|
||||
test_me s{};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 3);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 15);*/
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_user_provided_default_constructor() {
|
||||
struct test_me {
|
||||
short s = 2;
|
||||
constexpr test_me(short){}
|
||||
};
|
||||
|
||||
test_me s{0};
|
||||
(void)s;
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2); // TODO: fix compile time error message
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
void test_copy_only_pod() {
|
||||
struct copy_only_pod {
|
||||
int i1;
|
||||
short s1;
|
||||
|
||||
copy_only_pod() = delete;
|
||||
copy_only_pod(copy_only_pod&&) = delete;
|
||||
|
||||
copy_only_pod(const copy_only_pod&) = default;
|
||||
copy_only_pod& operator=(const copy_only_pod&) = delete;
|
||||
copy_only_pod& operator=(copy_only_pod&&) = delete;
|
||||
};
|
||||
|
||||
copy_only_pod s{2, 14};
|
||||
BOOST_TEST_EQ(tuple_size_v<copy_only_pod>, 2u);
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
|
||||
|
||||
struct with_reference {
|
||||
int& i;
|
||||
int* p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
|
||||
|
||||
|
||||
struct with_nested_copy_only_pod {
|
||||
int i;
|
||||
copy_only_pod p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_nested_copy_only_pod>, 2u);
|
||||
|
||||
with_nested_copy_only_pod np{2, {3, 4}};
|
||||
BOOST_TEST_EQ(flat_get<0>(np), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(np), 3);
|
||||
BOOST_TEST_EQ(flat_get<2>(np), 4);
|
||||
} // */
|
||||
/* // TODO: think of something with it!
|
||||
void test_move_only_pod() {
|
||||
struct move_only_pod {
|
||||
int i1;
|
||||
short s1;
|
||||
|
||||
move_only_pod() = delete;
|
||||
//move_only_pod(move_only_pod&&) = delete;
|
||||
|
||||
move_only_pod(const move_only_pod&) = delete;
|
||||
move_only_pod(move_only_pod&&) = default;
|
||||
move_only_pod& operator=(const move_only_pod&) = delete;
|
||||
move_only_pod& operator=(move_only_pod&&) = delete;
|
||||
};
|
||||
|
||||
move_only_pod s{2, 14};
|
||||
BOOST_TEST_EQ(tuple_size_v<move_only_pod>, 2u);
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
|
||||
|
||||
struct with_reference {
|
||||
int& i;
|
||||
int* p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
|
||||
|
||||
|
||||
struct with_nested_move_only_pod {
|
||||
int i;
|
||||
short s;
|
||||
move_only_pod p;
|
||||
char c;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_nested_move_only_pod>, 4u);
|
||||
|
||||
// with_nested_move_only_pod np{2, {3, 4}};
|
||||
// BOOST_TEST_EQ(flat_get<0>(np), 2);
|
||||
// BOOST_TEST_EQ(flat_get<1>(np), 3);
|
||||
// BOOST_TEST_EQ(flat_get<2>(np), 4);
|
||||
} // */
|
||||
|
||||
int main() {
|
||||
test_compiletime<foo>();
|
||||
test_compiletime_array<int>();
|
||||
test_compiletime_array<void*>();
|
||||
test_compiletime_array<const void*>();
|
||||
test_compiletime_array<char>();
|
||||
test_compiletime_array<char const volatile*>();
|
||||
{
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
{
|
||||
foo f {
|
||||
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
|
||||
, {-18, -19}
|
||||
, {656565, 65535, {-22, -23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
|
||||
test_with_enums();
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_pods_with_int_operators();
|
||||
test_struct_with_single_field();
|
||||
|
||||
test_with_contatiners<flat_less<>>();
|
||||
test_with_contatiners<flat_greater<>>();
|
||||
|
||||
test_print();
|
||||
|
||||
test_with_user_defined_constructor();
|
||||
test_hash();
|
||||
|
||||
struct non_pod1 {
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod1>::value == 4, "Must not be a compile error");
|
||||
|
||||
|
||||
struct non_pod2 {
|
||||
unsigned ui1: 1;
|
||||
unsigned ui2: 2;
|
||||
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod2>::value == 6, "Must not be a compile error even with bitfields");
|
||||
|
||||
int i_2dimens[2][2] = {{10, 11}, {12, 13} };
|
||||
static_assert(tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
static_assert(flat_tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
|
||||
test_and_debug_internals(std::make_index_sequence<6>{});
|
||||
test_alignment_with_nested_structure();
|
||||
another_test_with_unusual_alignment();
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
test_structure_with_default_values();
|
||||
test_st_layout_structure_with_non_constexpr_type();
|
||||
test_structure_with_user_provided_default_constructor();
|
||||
#endif
|
||||
|
||||
//test_copy_only_pod();
|
||||
//test_move_only_pod();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,659 +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)
|
||||
|
||||
//#define BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
//#include <boost/type_index.hpp> // for debugging
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
#include <cstring>
|
||||
|
||||
using namespace boost::pfr;
|
||||
|
||||
template <std::size_t I, class T>
|
||||
void print(T& f) {
|
||||
std::cout << flat_get<I>(f) << "\t\t"
|
||||
<< typeid(flat_tuple_element_t<I, T>).name()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
struct make_my_life_harder { int a0; short a1; };
|
||||
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
|
||||
struct foo {
|
||||
unsigned char v0;
|
||||
unsigned int v1;
|
||||
unsigned short v2;
|
||||
unsigned long long v3;
|
||||
unsigned char v4and5[2];
|
||||
int v6;
|
||||
std::size_t v7;
|
||||
int* v8;
|
||||
const void* v9;
|
||||
int const**const volatile**volatile** v10;
|
||||
const double v11;
|
||||
make_my_life_harder v12and13;
|
||||
make_my_life_even_more_harder v14and15andv16and17;
|
||||
};
|
||||
|
||||
void test_print() {
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
print<0>(f); print<1>(f); print<2>(f);
|
||||
print<3>(f); print<4>(f); print<5>(f);
|
||||
print<6>(f); print<7>(f); print<8>(f);
|
||||
print<9>(f); print<10>(f); print<11>(f);
|
||||
print<12>(f); print<13>(f); print<14>(f);
|
||||
print<15>(f); print<16>(f); print<17>(f);
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
|
||||
int a[] = {0, 1, 2, 3};
|
||||
std::cout << '\n' << flat_get<1>(a) << std::endl;
|
||||
|
||||
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
|
||||
std::cout << flat_get<4>(b) << std::endl;
|
||||
|
||||
int i = 777;
|
||||
std::cout << flat_get<0>(i) << std::endl;
|
||||
}
|
||||
|
||||
void test_runtime(const foo& f) {
|
||||
BOOST_TEST_EQ( flat_get<0>(f), f.v0);
|
||||
BOOST_TEST_EQ( flat_get<1>(f), f.v1);
|
||||
BOOST_TEST_EQ( flat_get<2>(f), f.v2);
|
||||
BOOST_TEST_EQ( flat_get<3>(f), f.v3);
|
||||
BOOST_TEST_EQ( flat_get<4>(f), f.v4and5[0]);
|
||||
BOOST_TEST_EQ( flat_get<5>(f), f.v4and5[1]);
|
||||
BOOST_TEST_EQ( flat_get<6>(f), f.v6);
|
||||
BOOST_TEST_EQ( flat_get<7>(f), f.v7);
|
||||
BOOST_TEST_EQ( flat_get<8>(f), f.v8);
|
||||
BOOST_TEST_EQ( flat_get<9>(f), f.v9);
|
||||
BOOST_TEST_EQ( flat_get<10>(f), f.v10);
|
||||
BOOST_TEST( flat_get<11>(f) < f.v11 + 0.001); BOOST_TEST( flat_get<11>(f) > f.v11 - 0.001);
|
||||
BOOST_TEST_EQ( flat_get<12>(f), f.v12and13.a0);
|
||||
BOOST_TEST_EQ( flat_get<13>(f), f.v12and13.a1);
|
||||
BOOST_TEST_EQ( flat_get<14>(f), f.v14and15andv16and17.b0);
|
||||
BOOST_TEST_EQ( flat_get<15>(f), f.v14and15andv16and17.b1);
|
||||
BOOST_TEST_EQ( flat_get<16>(f), f.v14and15andv16and17.cr.a0);
|
||||
BOOST_TEST_EQ( flat_get<17>(f), f.v14and15andv16and17.cr.a1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_compiletime() {
|
||||
constexpr T f{};
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void test_compiletime_array() {
|
||||
{
|
||||
constexpr T f[20] = {0};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][10] = {{0}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][5][2] = {{{0}}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
}
|
||||
|
||||
void test_with_enums() {
|
||||
enum class my_enum: unsigned {
|
||||
VALUE1 = 17, VALUE2, VALUE3
|
||||
};
|
||||
struct my_struct { my_enum e; int i; short s; };
|
||||
my_struct s {my_enum::VALUE1, 10, 11};
|
||||
std::tuple<unsigned, int, short> t = flat_structure_to_tuple(s);
|
||||
BOOST_TEST_EQ(std::get<0>(t), 17u);
|
||||
BOOST_TEST_EQ(std::get<1>(t), 10);
|
||||
BOOST_TEST_EQ(std::get<2>(t), 11);
|
||||
|
||||
flat_get<1>(s) = 101;
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 101);
|
||||
flat_get<2>(s) = 111;
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 111);
|
||||
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_tie(s));
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_to_tuple(s));
|
||||
BOOST_TEST(flat_structure_tie(s) != t);
|
||||
flat_structure_tie(s) = t;
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 17u);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 10);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 11);
|
||||
|
||||
static_assert(std::is_same<
|
||||
int, flat_tuple_element_t<1, my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
short, flat_tuple_element_t<2, my_struct>
|
||||
>::value, "");
|
||||
|
||||
|
||||
static_assert(std::is_same<
|
||||
const int, flat_tuple_element_t<1, const my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
volatile short, flat_tuple_element_t<2, volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(
|
||||
3 == flat_tuple_size_v<const volatile my_struct>,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
using namespace flat_ops;
|
||||
|
||||
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST(s1 == s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
BOOST_TEST(!(s1 != s2));
|
||||
BOOST_TEST(!(s1 == s3));
|
||||
BOOST_TEST(s1 != s3);
|
||||
BOOST_TEST(s1 < s3);
|
||||
BOOST_TEST(s3 > s2);
|
||||
BOOST_TEST(s1 <= s3);
|
||||
BOOST_TEST(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
BOOST_TEST(s1 == s4);
|
||||
int i = 1, j = 2;
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
using namespace flat_ops;
|
||||
|
||||
std::cout << empty{} << std::endl;
|
||||
|
||||
BOOST_TEST(empty{} == empty{});
|
||||
}
|
||||
|
||||
|
||||
void test_pods_with_int_operators() {
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::is_pod<int>{};
|
||||
int i = 0;
|
||||
ss >> i;
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
std::cout << i << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void test_struct_with_single_field() {
|
||||
struct f1 { int i; };
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << f1{ 777 };
|
||||
f1 var{};
|
||||
ss >> var;
|
||||
BOOST_TEST_EQ(var.i, 777);
|
||||
BOOST_TEST(var == f1{ 777 });
|
||||
BOOST_TEST(var != f1{ 778 });
|
||||
|
||||
BOOST_TEST(var <= f1{ 777 });
|
||||
BOOST_TEST(var <= f1{ 778 });
|
||||
BOOST_TEST(var < f1{ 778 });
|
||||
|
||||
BOOST_TEST(var >= f1{ 777 });
|
||||
BOOST_TEST(var >= f1{ 776 });
|
||||
BOOST_TEST(var > f1{ 776 });
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void test_with_contatiners() {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
struct testing2 { bool b1, b2; int i; };
|
||||
std::set<testing, Comparator > t{
|
||||
{true, true, 100},
|
||||
{false, true, 100},
|
||||
{true, false, 100},
|
||||
{true, true, 101}
|
||||
};
|
||||
|
||||
BOOST_TEST(t.find({true, true, 100}) != t.end());
|
||||
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
|
||||
BOOST_TEST(t.find(testing2{true, true, 100}) != t.end());
|
||||
|
||||
std::set<testing2, Comparator > t2{
|
||||
{true, true, 101},
|
||||
{true, true, 100},
|
||||
{true, false, 100},
|
||||
{false, true, 100}
|
||||
};
|
||||
|
||||
BOOST_TEST(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
|
||||
BOOST_TEST(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
|
||||
|
||||
std::vector<testing> res;
|
||||
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
|
||||
std::back_inserter(res), Comparator{});
|
||||
|
||||
BOOST_TEST_EQ(res.size(), 4u);
|
||||
}
|
||||
|
||||
void test_with_user_defined_constructor() {
|
||||
struct pr {
|
||||
int i;
|
||||
short s;
|
||||
|
||||
pr() = default;
|
||||
pr(const pr&) = default;
|
||||
pr(pr&&) = default;
|
||||
pr(int ii, short is) noexcept
|
||||
: i(ii), s(is)
|
||||
{}
|
||||
};
|
||||
|
||||
pr p{1, 2};
|
||||
|
||||
//assert(flat_get<1>(p) == 2); // Compilation error
|
||||
}
|
||||
|
||||
void test_hash() {
|
||||
struct almost_pair { int i; short s; };
|
||||
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
|
||||
s.insert({0, 1});
|
||||
s.insert({1, 0});
|
||||
s.insert({1, 1});
|
||||
|
||||
BOOST_TEST_EQ(s.size(), 3u);
|
||||
flat_hash<almost_pair> hs;
|
||||
BOOST_TEST_NE(hs({0, 1}), hs({1, 0}));
|
||||
BOOST_TEST_EQ(hs({0, 1}), hs({0, 1}));
|
||||
BOOST_TEST_EQ(hs({1, 1}), hs({1, 1}));
|
||||
BOOST_TEST_NE(hs({0, 0}), hs({1, 1}));
|
||||
|
||||
struct single_field { int i; };
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({1}), std::hash<int>()(1));
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({199}), std::hash<int>()(199));
|
||||
}
|
||||
|
||||
// Test case by Lisa Lippincott
|
||||
void test_alignment_with_neted_structure() {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
B0 test_struct;
|
||||
std::memset(&test_struct, 0, sizeof(test_struct));
|
||||
test_struct.a.s = 0;
|
||||
test_struct.a.c = '1';
|
||||
test_struct.c1 = '2';
|
||||
test_struct.c2 = '3';
|
||||
BOOST_TEST_EQ(flat_get<0>(test_struct), 0);
|
||||
BOOST_TEST_EQ(flat_get<1>(test_struct), '1');
|
||||
BOOST_TEST_EQ(flat_get<2>(test_struct), '2');
|
||||
BOOST_TEST_EQ(flat_get<3>(test_struct), '3');
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t... I>
|
||||
void test_and_debug_internals(std::index_sequence<I...>) {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
A0 a0 { 3, '4' };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(a0), 3);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(a0), '4');
|
||||
|
||||
struct A1 {
|
||||
int i;
|
||||
};
|
||||
|
||||
struct B1 {
|
||||
A1 a;
|
||||
int j;
|
||||
};
|
||||
|
||||
B1 b1 { {5}, 6 };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(b1), 5);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(b1), 6);
|
||||
/*
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
typedef B0 type;
|
||||
typedef B0 T;
|
||||
|
||||
using namespace boost::pfr::detail;
|
||||
constexpr auto a = flat_array_of_type_ids<T>();
|
||||
(void)a; // `a` is unused if T is an empty type
|
||||
|
||||
constexpr size_array<a.size()> skips_in_subtuples {{
|
||||
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
|
||||
}};
|
||||
|
||||
constexpr size_array<sizeof...(I) + 1> indexes_in_subtuples_uncleanuped {{ 1, 1 + I...}};
|
||||
constexpr auto indexes_plus_1_and_zeros_as_skips = remove_skips(indexes_in_subtuples_uncleanuped, skips_in_subtuples);
|
||||
constexpr auto new_size = size_t_<indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
|
||||
constexpr auto indexes = resize_dropping_zeros_and_decrementing(new_size, indexes_plus_1_and_zeros_as_skips);
|
||||
static_assert(indexes.data[0] == 0, "");
|
||||
static_assert(indexes.data[1] == 4, "");
|
||||
static_assert(indexes.data[2] == 5, "");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
decltype(boost::pfr::detail::as_flat_tuple_impl<type>(
|
||||
std::make_index_sequence< decltype(boost::pfr::detail::flat_array_of_type_ids<type>())::size() >()
|
||||
)),
|
||||
boost::pfr::detail::sequence_tuple::tuple<boost::pfr::detail::sequence_tuple::tuple<short, char>, char, char>
|
||||
>::value,
|
||||
""
|
||||
);
|
||||
|
||||
constexpr auto res = as_flat_tuple_impl<foo>(
|
||||
std::make_index_sequence< decltype(flat_array_of_type_ids<foo>())::size() >()
|
||||
);
|
||||
auto afoo = flat_array_of_type_ids<foo>();
|
||||
std::cerr << "\n\n";
|
||||
for (std::size_t i = 0; i < afoo.size(); ++i) {
|
||||
std::cerr << afoo.data[i] << ' ';
|
||||
}
|
||||
|
||||
std::cerr << boost::typeindex::type_id<decltype(res)>() << "\n\n";*/
|
||||
}
|
||||
|
||||
|
||||
// test by Alexey Moiseytsev
|
||||
void another_test_with_unusual_alignment() {
|
||||
struct nested {
|
||||
char c0;
|
||||
char c1;
|
||||
int i0;
|
||||
short s0;
|
||||
char c2;
|
||||
};
|
||||
|
||||
struct pair {
|
||||
nested n0;
|
||||
nested n1;
|
||||
};
|
||||
|
||||
// layout:
|
||||
// offset struct tuple
|
||||
// 0 n0.c0 n0.c0
|
||||
// 1 n0.c1 n0.c1
|
||||
// 2 padding padding
|
||||
// 3 padding padding
|
||||
// 4 n0.i0 n0.i0
|
||||
// 5 n0.i0 n0.i0
|
||||
// 6 n0.i0 n0.i0
|
||||
// 7 n0.i0 n0.i0
|
||||
// 8 n0.s0 n0.s0
|
||||
// 9 n0.s0 n0.s0
|
||||
// 10 n0.c2 n0.c2
|
||||
// 11 padding n1.c0 !!!
|
||||
// 12 n1.c0 n1.c1 !!!
|
||||
// 13 n1.c1 padding !!!
|
||||
// 14 padding padding
|
||||
// 15 padding padding
|
||||
// 16 n1.i0 n1.i0
|
||||
// 17 n1.i0 n1.i0
|
||||
// 18 n1.i0 n1.i0
|
||||
// 19 n1.i0 n1.i0
|
||||
// 20 n1.s0 n1.s0
|
||||
// 21 n1.s0 n1.s0
|
||||
// 22 n1.c2 n1.c2
|
||||
// 23 padding padding
|
||||
|
||||
pair s{{'q', 'w', 12, 32, 'e'}, {'a', 's', 24, 64, 'd'}};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 'q');
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 'w');
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 12);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 32);
|
||||
BOOST_TEST_EQ(flat_get<4>(s), 'e');
|
||||
|
||||
BOOST_TEST_EQ(flat_get<5>(s), 'a');
|
||||
BOOST_TEST_EQ(flat_get<6>(s), 's');
|
||||
BOOST_TEST_EQ(flat_get<7>(s), 24);
|
||||
BOOST_TEST_EQ(flat_get<8>(s), 64);
|
||||
BOOST_TEST_EQ(flat_get<9>(s), 'd');
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_default_values() {
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
};
|
||||
|
||||
test_me s;
|
||||
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_st_layout_structure_with_non_constexpr_type() {
|
||||
struct non_literal_structure {
|
||||
int i1 = 3;
|
||||
short s1 = 15;
|
||||
|
||||
non_literal_structure() = delete;
|
||||
non_literal_structure(const non_literal_structure&) = delete;
|
||||
non_literal_structure(non_literal_structure&&) = default;
|
||||
non_literal_structure& operator=(const non_literal_structure&) = delete;
|
||||
non_literal_structure& operator=(non_literal_structure&&) = delete;
|
||||
};
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
non_literal_structure nonlit{};
|
||||
};
|
||||
|
||||
BOOST_TEST_EQ(tuple_size_v<test_me>, 3);
|
||||
|
||||
test_me s{};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 3);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 15);
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_user_provided_default_constructor() {
|
||||
struct test_me {
|
||||
short s = 2;
|
||||
constexpr test_me(short){}
|
||||
};
|
||||
|
||||
test_me s{0};
|
||||
(void)s;
|
||||
//BOOST_TEST_EQ(flat_get<0>(s), 2); // TODO: fix compile time error message2
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_move_only_pod() {
|
||||
struct move_only_pod {
|
||||
int i1;
|
||||
short s1;
|
||||
|
||||
move_only_pod() = delete;
|
||||
//move_only_pod(move_only_pod&&) = delete;
|
||||
|
||||
move_only_pod(const move_only_pod&) = delete;
|
||||
move_only_pod(move_only_pod&&) = default;
|
||||
move_only_pod& operator=(const move_only_pod&) = delete;
|
||||
move_only_pod& operator=(move_only_pod&&) = delete;
|
||||
};
|
||||
|
||||
move_only_pod s{2, 14};
|
||||
BOOST_TEST_EQ(tuple_size_v<move_only_pod>, 2u);
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
/* // TODO: fix me!
|
||||
struct with_nested_move_only_pod {
|
||||
int i;
|
||||
move_only_pod p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_nested_move_only_pod>, 2u); */
|
||||
/* // TODO: fix me!
|
||||
with_nested_move_only_pod np{2, {3, 4}};
|
||||
BOOST_TEST_EQ(flat_get<0>(np), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(np), 3);
|
||||
BOOST_TEST_EQ(flat_get<2>(np), 4);*/
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_compiletime<foo>();
|
||||
test_compiletime_array<int>();
|
||||
test_compiletime_array<void*>();
|
||||
test_compiletime_array<const void*>();
|
||||
test_compiletime_array<char>();
|
||||
test_compiletime_array<char const volatile*>();
|
||||
{
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
{
|
||||
foo f {
|
||||
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
|
||||
, {-18, -19}
|
||||
, {656565, 65535, {-22, -23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
|
||||
test_with_enums();
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_pods_with_int_operators();
|
||||
test_struct_with_single_field();
|
||||
|
||||
test_with_contatiners<flat_less<>>();
|
||||
test_with_contatiners<flat_greater<>>();
|
||||
|
||||
test_print();
|
||||
|
||||
test_with_user_defined_constructor();
|
||||
test_hash();
|
||||
|
||||
struct non_pod1 {
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod1>::value == 4, "Must not be a compile error");
|
||||
|
||||
|
||||
struct non_pod2 {
|
||||
unsigned ui1: 1;
|
||||
unsigned ui2: 2;
|
||||
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod2>::value == 6, "Must not be a compile error even with bitfields");
|
||||
|
||||
int i_2dimens[2][2] = {{10, 11}, {12, 13} };
|
||||
static_assert(tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
static_assert(flat_tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
|
||||
test_and_debug_internals(std::make_index_sequence<6>{});
|
||||
test_alignment_with_neted_structure();
|
||||
another_test_with_unusual_alignment();
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
test_structure_with_default_values();
|
||||
test_st_layout_structure_with_non_constexpr_type();
|
||||
test_structure_with_user_provided_default_constructor();
|
||||
#endif
|
||||
|
||||
test_move_only_pod();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
133
test/core/Jamfile.v2
Normal file
133
test/core/Jamfile.v2
Normal file
@@ -0,0 +1,133 @@
|
||||
# Copyright (C) 2016-2024 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
|
||||
<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 ../core//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 offset_based_getter.cpp ]
|
||||
|
||||
[ run can_be_as_fallback_in_the_fusion.cpp ]
|
||||
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ]
|
||||
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ]
|
||||
[ 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 ;
|
||||
}
|
||||
37
test/core/can_be_as_fallback_in_the_fusion.cpp
Normal file
37
test/core/can_be_as_fallback_in_the_fusion.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
struct Aggregate {};
|
||||
using NonAggregate = int;
|
||||
|
||||
template<class T>
|
||||
struct is_implicitly_reflectable : std::false_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_implicitly_reflectable<Aggregate> : std::true_type
|
||||
{};
|
||||
|
||||
template<class T, class E=void>
|
||||
struct tag_of_fallback {
|
||||
using type = int; // unknown
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct tag_of_fallback<T, std::enable_if_t<std::is_same<T,T>::value>>
|
||||
{
|
||||
using type = std::conditional_t<
|
||||
is_implicitly_reflectable<T>::value
|
||||
, std::true_type
|
||||
, std::false_type
|
||||
>;
|
||||
};
|
||||
|
||||
static_assert(tag_of_fallback<Aggregate>::type::value == true, "");
|
||||
static_assert(tag_of_fallback<NonAggregate>::type::value == false, "");
|
||||
|
||||
int main() { }
|
||||
@@ -1,12 +1,10 @@
|
||||
// Copyright (c) 2016 Antony Polukhin
|
||||
// Copyright (c) 2022 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_PFR_ENABLED 0
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
int main() {
|
||||
struct foo { int i; char c;};
|
||||
static_assert(boost::pfr::flat_tuple_size_v<foo> == 2, "");
|
||||
}
|
||||
int main() { }
|
||||
|
||||
15
test/core/compile-fail/fields_count_on_reference.cpp
Normal file
15
test/core/compile-fail/fields_count_on_reference.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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&>());
|
||||
}
|
||||
21
test/core/compile-fail/inherited.cpp
Normal file
21
test/core/compile-fail/inherited.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2021 Denis Mikhailov
|
||||
// Copyright (c) 2021 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
struct A
|
||||
{};
|
||||
|
||||
struct B : A
|
||||
{
|
||||
int one;
|
||||
int two;
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<B>::value; // Must be a compile time error
|
||||
}
|
||||
|
||||
20
test/core/compile-fail/inherited_nonempty.cpp
Normal file
20
test/core/compile-fail/inherited_nonempty.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2021 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
struct A {
|
||||
int zero;
|
||||
};
|
||||
|
||||
struct B : public A {
|
||||
int one;
|
||||
int two;
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<B>::value; // Must be a compile time error
|
||||
}
|
||||
|
||||
25
test/core/compile-fail/movable_and_lvalue_references.cpp
Normal file
25
test/core/compile-fail/movable_and_lvalue_references.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016 Antony Polukhin
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
18
test/core/compile-fail/ops_on_union.cpp
Normal file
18
test/core/compile-fail/ops_on_union.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/compile-fail/ops_unions.cpp
Normal file
22
test/core/compile-fail/ops_unions.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/compile-fail/ops_unrestricted_unions.cpp
Normal file
28
test/core/compile-fail/ops_unrestricted_unions.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/compile-fail/pfr_review_test2.cpp
Normal file
39
test/core/compile-fail/pfr_review_test2.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2020-2024 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/core/compile-fail/private_fields.cpp
Normal file
30
test/core/compile-fail/private_fields.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/compile-fail/protected_fields.cpp
Normal file
26
test/core/compile-fail/protected_fields.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/compile-fail/rvalue_tie.cpp
Normal file
17
test/core/compile-fail/rvalue_tie.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2020-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/compile-fail/virtual_functions.cpp
Normal file
20
test/core/compile-fail/virtual_functions.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/loophole_detection.cpp
Normal file
29
test/core/loophole_detection.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2020-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/offset_based_getter.cpp
Normal file
37
test/core/offset_based_getter.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2019 Ilya Kiselev
|
||||
// Copyright (c) 2019-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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();
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) 2016 Antony Polukhin
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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 <boost/pfr/tuple_size.hpp>
|
||||
|
||||
struct bf {
|
||||
unsigned int i1: 1;
|
||||
@@ -16,8 +15,7 @@ struct bf {
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::flat_tuple_size<bf>::value; // Must be a compile time error
|
||||
return boost::report_errors();
|
||||
static_assert(boost::pfr::tuple_size<bf>::value == 6, "");
|
||||
}
|
||||
|
||||
|
||||
81
test/core/run/constexpr_ops.cpp
Normal file
81
test/core/run/constexpr_ops.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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();
|
||||
}
|
||||
|
||||
|
||||
125
test/core/run/core17_generated.cpp
Normal file
125
test/core/run/core17_generated.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2023 Denis Mikhailov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
#include <type_traits> // for std::is_same
|
||||
|
||||
struct A {
|
||||
const volatile int cv_value = 0;
|
||||
volatile int v_value = 0;
|
||||
const int c_value = 0;
|
||||
int value = 0;
|
||||
|
||||
const volatile int& cv_ref;
|
||||
volatile int& v_ref;
|
||||
const int& c_ref;
|
||||
int& ref;
|
||||
|
||||
const volatile int&& cv_rref;
|
||||
volatile int&& v_rref;
|
||||
const int&& c_rref;
|
||||
int&& rref;
|
||||
};
|
||||
|
||||
int main() {
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
const volatile int cv_value = 0;
|
||||
volatile int v_value = 0;
|
||||
const int c_value = 0;
|
||||
int value = 0;
|
||||
|
||||
typedef boost::pfr::detail::size_t_<12> fields_count_tag;
|
||||
|
||||
{
|
||||
A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
const A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
volatile A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
const volatile A a {cv_value, v_value, c_value, value,
|
||||
cv_value, v_value, c_value, value,
|
||||
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
|
||||
|
||||
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
|
||||
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
|
||||
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
|
||||
// FIXME implement rvalue references as a field support
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
|
||||
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
60
test/core/run/destructuring_tie.cpp
Normal file
60
test/core/run/destructuring_tie.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
|
||||
// Copyright (c) 2019-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/core/run/error_pfr_c1202.cpp
Normal file
101
test/core/run/error_pfr_c1202.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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/boostorg/pfr/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/core/run/fields_count_on_const.cpp
Normal file
15
test/core/run/fields_count_on_const.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2018-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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, "");
|
||||
}
|
||||
137
test/core/run/for_each_field.cpp
Normal file
137
test/core/run/for_each_field.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the 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;
|
||||
};
|
||||
|
||||
struct empty{};
|
||||
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
constexpr std::size_t get_field_count_through_for_each_field() {
|
||||
std::size_t counter = 0;
|
||||
boost::pfr::for_each_field(simple{}, [&counter](auto&& /*val*/, std::size_t /*i*/) {
|
||||
++ counter;
|
||||
});
|
||||
return counter;
|
||||
}
|
||||
|
||||
// MSVC-14.1 fails to compile the following code
|
||||
#if !defined(_MSC_VER) || _MSC_VER > 1916
|
||||
static_assert(3 == get_field_count_through_for_each_field());
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
int main () {
|
||||
std::size_t control = 0;
|
||||
|
||||
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());
|
||||
ss.str("");
|
||||
|
||||
boost::pfr::for_each_field(empty{}, [&ss](auto&& val) {
|
||||
ss << val << ' ';
|
||||
});
|
||||
BOOST_TEST_EQ("", ss.str());
|
||||
ss.str("");
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright (c) 2016 Antony Polukhin
|
||||
// Copyright (c) 2016-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/flat_functions_for.hpp>
|
||||
#include <boost/pfr/functions_for.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
@@ -25,15 +26,16 @@ struct adl_hash {
|
||||
};
|
||||
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
int i; short s; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
|
||||
BOOST_PFR_FLAT_FUNCTIONS_FOR(comparable_struct)
|
||||
BOOST_PFR_FUNCTIONS_FOR(comparable_struct)
|
||||
|
||||
void test_comparable_struct() {
|
||||
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};
|
||||
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);
|
||||
@@ -47,7 +49,7 @@ void test_comparable_struct() {
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
Struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
@@ -58,8 +60,12 @@ void test_comparable_struct() {
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
test_some_comparable_struct<comparable_struct>();
|
||||
}
|
||||
|
||||
struct empty { operator std::string() { return "empty{}"; } };
|
||||
BOOST_PFR_FLAT_FUNCTIONS_FOR(empty)
|
||||
BOOST_PFR_FUNCTIONS_FOR(empty)
|
||||
|
||||
void test_empty_struct() {
|
||||
BOOST_TEST_EQ(empty{}, empty{});
|
||||
@@ -67,7 +73,7 @@ void test_empty_struct() {
|
||||
|
||||
namespace foo {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
BOOST_PFR_FLAT_FUNCTIONS_FOR(testing);
|
||||
BOOST_PFR_FUNCTIONS_FOR(testing)
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
@@ -93,7 +99,51 @@ void test_implicit_conversions() {
|
||||
|
||||
ss.str("");
|
||||
ss << empty{};
|
||||
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_FLAT_FUNCTIONS_FOR
|
||||
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() {
|
||||
@@ -102,6 +152,8 @@ int main() {
|
||||
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();
|
||||
}
|
||||
|
||||
67
test/core/run/get_by_type.cpp
Normal file
67
test/core/run/get_by_type.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2020-2024 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Aggregate {
|
||||
int a;
|
||||
const int b;
|
||||
double c;
|
||||
double d;
|
||||
short e;
|
||||
};
|
||||
|
||||
void test_get_by_type() {
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
Aggregate t{1, 2, 3.4, 5.6, 7};
|
||||
|
||||
BOOST_TEST_EQ(boost::pfr::get<int>(t), 1);
|
||||
BOOST_TEST_EQ(boost::pfr::get<const int>(t), 2);
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(t), 7);
|
||||
|
||||
boost::pfr::get<int>(t) = 11;
|
||||
boost::pfr::get<short>(t) = 77;
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_const_get_by_type() {
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
const Aggregate t{1, 2, 3.4, 5.6, 7};
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(t), 7);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_get_by_type_pod() {
|
||||
struct PodAggregate {
|
||||
int i;
|
||||
short s;
|
||||
};
|
||||
|
||||
PodAggregate pod{1, 2};
|
||||
BOOST_TEST_EQ(boost::pfr::get<int>(pod), 1);
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(pod), 2);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_get_by_type();
|
||||
testing::test_const_get_by_type();
|
||||
testing::test_get_by_type_pod();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user