Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
021e5da2fe | ||
|
|
49fbbed8e2 | ||
|
|
1bce4362db | ||
|
|
797239531b | ||
|
|
0db8d115bf | ||
|
|
4b466f4f80 | ||
|
|
aafd7702bd | ||
|
|
fedddc5a1b | ||
|
|
6c7c93edfa | ||
|
|
7fcfa29353 | ||
|
|
6ccd33fe37 | ||
|
|
33224f4660 | ||
|
|
62034cbe26 | ||
|
|
8195d35fbc | ||
|
|
f64864fa74 | ||
|
|
946b568bf7 | ||
|
|
0399962807 | ||
|
|
e50424c9fa | ||
|
|
bd766fe0bd | ||
|
|
3452ab4244 | ||
|
|
b37ff23566 | ||
|
|
d5f531fd5c | ||
|
|
df16f32fa7 | ||
|
|
36ab0c1f89 | ||
|
|
cfbb7b0f25 | ||
|
|
182876d4a3 | ||
|
|
afe6ab9883 | ||
|
|
8475382ad5 | ||
|
|
d16feb9de8 | ||
|
|
96b34c2e71 | ||
|
|
319ce5f5ee | ||
|
|
9ccfaa0bea | ||
|
|
3d5d20d1d8 | ||
|
|
78b88cc314 | ||
|
|
b883b47a65 | ||
|
|
e6dc5d37cb | ||
|
|
487c3375e1 | ||
|
|
3d4fea5bdb | ||
|
|
0a7a989763 | ||
|
|
16378d5847 | ||
|
|
0cf8150bc4 | ||
|
|
9aa7f390c4 | ||
|
|
009e383cf3 | ||
|
|
ae57c6271b | ||
|
|
f36e2d1c79 | ||
|
|
1bf8c629b1 | ||
|
|
02724b9a39 | ||
|
|
3f205c28e2 | ||
|
|
dc9e573dfb | ||
|
|
13d1d36cae | ||
|
|
ae7529c211 | ||
|
|
a88e1c7dfd | ||
|
|
7cf1cba5f1 | ||
|
|
e9234e3fb6 | ||
|
|
e9551c9942 | ||
|
|
f094ba78ec | ||
|
|
83df216451 | ||
|
|
6a2826150f | ||
|
|
53441ea669 | ||
|
|
0d96673536 | ||
|
|
322fb95a5d | ||
|
|
0d3edb8c29 | ||
|
|
65adc87c7c | ||
|
|
e519567cd2 | ||
|
|
0f61bc8a38 | ||
|
|
59621d6023 | ||
|
|
f158a44a32 | ||
|
|
0cef0b7073 | ||
|
|
ed49c96c80 | ||
|
|
84a6c4b063 | ||
|
|
05c0cb0521 | ||
|
|
c37d44fd7e | ||
|
|
54b2fe12b5 | ||
|
|
9323fc0af7 | ||
|
|
11882b6261 | ||
|
|
f5a9404503 | ||
|
|
c0f2e28719 | ||
|
|
bcd69859c0 | ||
|
|
ca75f4b53e | ||
|
|
cb78660421 | ||
|
|
f7baa90c23 | ||
|
|
7292a605dd | ||
|
|
01dd76f515 | ||
|
|
f698f33ca0 | ||
|
|
8859e1f9f0 | ||
|
|
baeb6d8b0e | ||
|
|
ebbf3a6768 | ||
|
|
0adf9e6865 | ||
|
|
85b5f73252 | ||
|
|
a4edd60629 | ||
|
|
72c83d9b04 | ||
|
|
efcfb95e9f | ||
|
|
9b1dd1673d | ||
|
|
dbb16b1942 | ||
|
|
96442fff9e | ||
|
|
ba559a23ed | ||
|
|
9b1fe1efa5 | ||
|
|
7fd9136f8d | ||
|
|
4e79985fb9 | ||
|
|
c76d02cbfe | ||
|
|
7c65494566 | ||
|
|
123eeb55d6 | ||
|
|
43077e7f03 | ||
|
|
d5b212629f | ||
|
|
c3eda13e9e | ||
|
|
e84a6735bd | ||
|
|
ca5cd7eece | ||
|
|
0481881be2 | ||
|
|
673add1212 | ||
|
|
015ed43eed | ||
|
|
70754e2cab | ||
|
|
1947a96308 | ||
|
|
8e25c2bb7e | ||
|
|
ae9b1063f0 | ||
|
|
508b02047f | ||
|
|
63eee8104f | ||
|
|
aa891a42d7 | ||
|
|
fcef0da01a | ||
|
|
950aca4523 | ||
|
|
35a36afb97 | ||
|
|
ad905576d2 | ||
|
|
f031131130 | ||
|
|
c4dcc8d5de | ||
|
|
52b03d58c5 | ||
|
|
2ab15f7540 | ||
|
|
7723503fcc | ||
|
|
68f56eed92 | ||
|
|
676d329d81 | ||
|
|
546fd9b896 | ||
|
|
8b8f5814e2 | ||
|
|
51cbda5f30 | ||
|
|
e38d6fecc1 | ||
|
|
70c4420632 | ||
|
|
2590f219a2 | ||
|
|
a91737466f | ||
|
|
ee17db59c8 | ||
|
|
b827b955f9 | ||
|
|
f577fc4ce4 | ||
|
|
fb6606dbb8 | ||
|
|
a2d5a15b67 | ||
|
|
e4d543d0b4 | ||
|
|
2261feea2f | ||
|
|
4ff4db8532 | ||
|
|
655696ad81 | ||
|
|
df44243bad | ||
|
|
0a908bc8c8 | ||
|
|
4a92e2930e | ||
|
|
a8e99636f5 | ||
|
|
75e50ee1e6 | ||
|
|
507f97d3ad | ||
|
|
f69ad7cd9e | ||
|
|
d21b0c0ab6 | ||
|
|
e63f08f4d7 | ||
|
|
29829c167e | ||
|
|
ad927466b5 | ||
|
|
9978e0c03f | ||
|
|
1edc5c6f6d | ||
|
|
6086234740 | ||
|
|
6e717666f3 | ||
|
|
2e96b9915e | ||
|
|
9376ca6055 | ||
|
|
72d79364c9 | ||
|
|
1d67d44024 | ||
|
|
66528b68be | ||
|
|
978b3b56b4 | ||
|
|
13ae5609df | ||
|
|
07818f4527 | ||
|
|
b5e500d3b2 | ||
|
|
a6e59d7e06 | ||
|
|
cd46374df8 | ||
|
|
38e15480c0 | ||
|
|
15c73394a9 | ||
|
|
928cd36335 | ||
|
|
0a262ece48 | ||
|
|
671999e4ea | ||
|
|
195c0bf229 | ||
|
|
34bb0d9494 | ||
|
|
e597e03f8a | ||
|
|
d27cc338d2 | ||
|
|
74030ce9e2 | ||
|
|
bf0f9aee1c | ||
|
|
fc57d93847 | ||
|
|
8c1517d1b0 | ||
|
|
96deb7e9d3 | ||
|
|
74e0b1b698 | ||
|
|
500e7a0188 | ||
|
|
e715149f4d | ||
|
|
f4ae56a19b | ||
|
|
383cea57eb | ||
|
|
e080c31867 | ||
|
|
3541f6588c | ||
|
|
c51095f9d3 | ||
|
|
4854ed5380 | ||
|
|
80c518bcfc | ||
|
|
f414a41a76 | ||
|
|
c7b33a5a9c | ||
|
|
c99294ea91 | ||
|
|
e694a6311a | ||
|
|
a06680868e | ||
|
|
3fb59dbe6c | ||
|
|
3d5a77d2c3 | ||
|
|
adea360c7a | ||
|
|
b8d9acc502 | ||
|
|
b9c424e06a | ||
|
|
c83a7f99e6 | ||
|
|
cd37b64b78 | ||
|
|
d16f88da40 | ||
|
|
bd839ccb47 | ||
|
|
1e5e648918 | ||
|
|
0bfa9adf27 | ||
|
|
f053576858 | ||
|
|
6ff90841a5 | ||
|
|
fb7fd75954 | ||
|
|
869a132f1b | ||
|
|
eb5f8fb4cd | ||
|
|
39d1b45dfc | ||
|
|
d7f96ac80e | ||
|
|
73b2f8b1ec | ||
|
|
42a45b6e15 | ||
|
|
58d244edb7 | ||
|
|
0645af74f9 | ||
|
|
a8bd7f3368 | ||
|
|
6d8bdd8818 | ||
|
|
ac07952e40 | ||
|
|
74da9b6b2a | ||
|
|
c330000cb4 | ||
|
|
4379729f78 | ||
|
|
62c92138a2 | ||
|
|
3bc3c2adb0 | ||
|
|
a1e259ed84 | ||
|
|
8401da04af | ||
|
|
8559c68b1b | ||
|
|
037cf4fe94 | ||
|
|
a95551b0ac | ||
|
|
db6586e93a | ||
|
|
0235975d89 | ||
|
|
77e1e0be74 | ||
|
|
1e64528310 | ||
|
|
f73c95b604 | ||
|
|
2a0e67a780 | ||
|
|
974bbc28f1 | ||
|
|
e5911ad79e | ||
|
|
e79526ce13 | ||
|
|
2f1725a79d | ||
|
|
fe37e5f9c9 | ||
|
|
aaf1ef185e | ||
|
|
7409da1fb4 | ||
|
|
677e7e6c8e | ||
|
|
4fdc15ed82 | ||
|
|
8ab5c1cfe5 | ||
|
|
d2bfaa93f0 | ||
|
|
317482bea2 | ||
|
|
10b967c74b | ||
|
|
8db68d25bd | ||
|
|
4c9286ec5b | ||
|
|
61c8e148f6 | ||
|
|
7ea8da1a27 | ||
|
|
08891efaa9 | ||
|
|
404f3597ff | ||
|
|
c5a47be1e3 | ||
|
|
aaed50c767 | ||
|
|
e9d33b0a1f | ||
|
|
6c1b3f7602 | ||
|
|
0f8e40ef97 | ||
|
|
6a7bffb34d | ||
|
|
27e4172f0b | ||
|
|
d612b9fc65 | ||
|
|
7f3e3b59b1 | ||
|
|
977062eeb1 | ||
|
|
742a585626 | ||
|
|
fc17bd94e6 | ||
|
|
f367de1147 | ||
|
|
f6d0308a0b | ||
|
|
72d7a6301c | ||
|
|
20778fe4b8 | ||
|
|
1ef6415f15 | ||
|
|
7b10a08836 | ||
|
|
68f75089a9 | ||
|
|
33556de79f | ||
|
|
05afe09737 | ||
|
|
61d610db27 | ||
|
|
5a906d1c41 | ||
|
|
33e421cb32 | ||
|
|
3f055ae24c | ||
|
|
37380fa6ff | ||
|
|
480de61173 | ||
|
|
ba561c067f | ||
|
|
e9a71acb07 | ||
|
|
ecb44372e5 | ||
|
|
61429d2292 | ||
|
|
7a3933ff0f | ||
|
|
1d50761ece | ||
|
|
bdd766d474 | ||
|
|
5008bddcb9 | ||
|
|
de1011152e | ||
|
|
3184b468bc | ||
|
|
f2ccfea1f8 | ||
|
|
cd7346ff3d | ||
|
|
1479f8e635 | ||
|
|
2c0451d647 | ||
|
|
608d48d7b8 | ||
|
|
8fefa0cd77 | ||
|
|
f54f9e89fd | ||
|
|
0ff685ce4d | ||
|
|
f45109083f | ||
|
|
6da711b843 | ||
|
|
23053232d4 | ||
|
|
99d8f0a77d | ||
|
|
df33ae5c4d | ||
|
|
447bdc7399 | ||
|
|
b849a39950 | ||
|
|
db6aaffb69 | ||
|
|
d350c81947 | ||
|
|
207c085a26 | ||
|
|
84e2f8edda | ||
|
|
69fbcb556f | ||
|
|
f3d7206bb2 | ||
|
|
2f9471bc40 | ||
|
|
774fe618cb | ||
|
|
676ebf76fa | ||
|
|
4b1b70b302 | ||
|
|
7ae8d0dda4 | ||
|
|
15d4e9f10e | ||
|
|
839ae30cc0 | ||
|
|
7e1d32f1d5 | ||
|
|
5d541d33cd | ||
|
|
005d628652 | ||
|
|
a248e3a55d | ||
|
|
94d49c42ac | ||
|
|
b385b3958a | ||
|
|
aad1e371c7 | ||
|
|
14bc429d9a | ||
|
|
16084f734a | ||
|
|
0d8cebe6f3 | ||
|
|
4f1dc224e6 | ||
|
|
9c9ca54829 | ||
|
|
81ec2714ea | ||
|
|
c6b899ef1f | ||
|
|
50bb286b78 | ||
|
|
d99beeb6d8 | ||
|
|
93e075f008 | ||
|
|
f9f7ac0943 | ||
|
|
a5634de53e | ||
|
|
af9454b2e8 | ||
|
|
7e491356e3 | ||
|
|
c9fa441d7d | ||
|
|
4cd441e3a6 | ||
|
|
3c330b7507 | ||
|
|
994aceeec0 | ||
|
|
b524b60ddf | ||
|
|
1e4398c5b2 | ||
|
|
6e41ed80b8 | ||
|
|
419343a0c5 | ||
|
|
c2f881de5b | ||
|
|
5dc59708ca | ||
|
|
724112cccb | ||
|
|
418271f219 | ||
|
|
9fb72cf6c4 | ||
|
|
3f4358d61a | ||
|
|
00f47ed3b9 | ||
|
|
0626809bac | ||
|
|
1a963d06c3 | ||
|
|
56e20c93bf | ||
|
|
330e53f3a1 | ||
|
|
f4290726af | ||
|
|
871436a9c6 | ||
|
|
f7ec6cfcc3 | ||
|
|
c1c604876e | ||
|
|
58d1675fe0 | ||
|
|
a790351bef | ||
|
|
3d6cd67fe7 | ||
|
|
036e00c6ca | ||
|
|
72cb6e3c00 | ||
|
|
cc5a7359c5 | ||
|
|
27ce5592f3 | ||
|
|
292f9760bd | ||
|
|
e4aef13d75 | ||
|
|
acc33b3a9b | ||
|
|
93b5073c62 | ||
|
|
3189f037b7 | ||
|
|
53aa47fd0d | ||
|
|
9addb12616 | ||
|
|
929cfe6217 | ||
|
|
5dfd60063f | ||
|
|
84fa7cd39f | ||
|
|
1e3190d444 | ||
|
|
dfa871d5d8 | ||
|
|
d4d433daca | ||
|
|
e054ec1b10 | ||
|
|
901489593f | ||
|
|
97fa66f34e | ||
|
|
5715d7ad01 | ||
|
|
ed755a6fc5 | ||
|
|
669378d93b | ||
|
|
7b51126bd3 | ||
|
|
43da02ddcf | ||
|
|
851e72bd1a | ||
|
|
3dba7636ba | ||
|
|
2edc936e50 | ||
|
|
bbfd418013 | ||
|
|
948a869a08 | ||
|
|
06d9fc4f8a | ||
|
|
28f9841fdb | ||
|
|
e6cb01e89a | ||
|
|
2b8bbab316 | ||
|
|
fdb822f4fd | ||
|
|
652e9b7f34 | ||
|
|
2e1737ec1f | ||
|
|
2efa919b53 | ||
|
|
13b0c7edb5 | ||
|
|
f6f2972cb8 | ||
|
|
8efbc0c6f5 | ||
|
|
9a5a7134db | ||
|
|
ba63d4a093 | ||
|
|
0163d6cdd6 | ||
|
|
a295a3635b | ||
|
|
f8a871c7ff | ||
|
|
c068ba2405 | ||
|
|
3781ab3d49 | ||
|
|
b405737fbf | ||
|
|
869b2b2cda | ||
|
|
16bf75dedf | ||
|
|
b0d45bd565 | ||
|
|
e423228dde | ||
|
|
ea007dafd8 | ||
|
|
f067ba6905 | ||
|
|
5305078096 | ||
|
|
6d738d7171 | ||
|
|
8785741f41 | ||
|
|
4ed9ef9e83 | ||
|
|
4a0b06ec97 | ||
|
|
2e82e36f60 | ||
|
|
bbcc6f5aa9 | ||
|
|
bf1bb9dc58 | ||
|
|
876efe9f49 | ||
|
|
d85d8136e1 | ||
|
|
b4e7d222de | ||
|
|
dc80eabbbf | ||
|
|
fd73e8066f | ||
|
|
1d8deb2521 | ||
|
|
fe4b72314f | ||
|
|
d4704dedb3 | ||
|
|
e6a3da0f87 | ||
|
|
2056257177 | ||
|
|
b957321659 | ||
|
|
7121e91e6a | ||
|
|
8217d7ecf6 | ||
|
|
5114eaaf25 | ||
|
|
6f24fac7d5 | ||
|
|
d974f3e5b1 | ||
|
|
99be96876a | ||
|
|
0022152a85 | ||
|
|
83abae0906 | ||
|
|
a2d3b3c9e6 | ||
|
|
b2730c6351 | ||
|
|
00abd7a068 | ||
|
|
f6d01d5b07 | ||
|
|
2b2e80cda1 | ||
|
|
6824a6f46f | ||
|
|
da79a37a48 | ||
|
|
631aace6cf | ||
|
|
f56a51b2f1 | ||
|
|
798a598f48 | ||
|
|
8230f54bb4 | ||
|
|
8934f65578 | ||
|
|
0001a31100 | ||
|
|
57fe08f7df | ||
|
|
d5f9a8a22b | ||
|
|
a8b106d33c | ||
|
|
1dab31e215 | ||
|
|
3bbe6bde37 | ||
|
|
5a8e3ce934 | ||
|
|
b6026f6e32 | ||
|
|
66542bffb6 | ||
|
|
2c661a3cfe | ||
|
|
06b4f467c1 | ||
|
|
721c75c931 | ||
|
|
5d31ec2ee1 | ||
|
|
d1310e4459 | ||
|
|
26d31872e3 | ||
|
|
074ab07bfe | ||
|
|
4bc8dada80 | ||
|
|
a088095518 | ||
|
|
4fb9e3bf73 | ||
|
|
60e207faaa | ||
|
|
348d2d763d | ||
|
|
41082f702d | ||
|
|
8abfa583b0 | ||
|
|
0423779b94 | ||
|
|
738da2bedb | ||
|
|
267d489a03 | ||
|
|
084532fe53 | ||
|
|
b915326877 | ||
|
|
12a70b1336 | ||
|
|
d0d23980d5 | ||
|
|
e4429f0df4 | ||
|
|
3a35be8ffc | ||
|
|
e6c3192b18 | ||
|
|
e7928a7c8d | ||
|
|
cda37514d4 | ||
|
|
6c5e776efb | ||
|
|
02517c27f9 | ||
|
|
e7f7692d6a | ||
|
|
db8b0919a0 | ||
|
|
f51145c906 | ||
|
|
5116ced7ba | ||
|
|
454d3ca438 | ||
|
|
dd6cf4c3cf | ||
|
|
5c87e68cb9 | ||
|
|
22f0070a83 | ||
|
|
2225fcaf91 | ||
|
|
be617d0a62 | ||
|
|
88d76b3866 | ||
|
|
953090e645 | ||
|
|
5f3e9fb9f1 | ||
|
|
ab5a89a16f | ||
|
|
33180eac14 | ||
|
|
fd02187150 | ||
|
|
8acd3dc767 | ||
|
|
c8b6e2444a | ||
|
|
5a303d33e2 | ||
|
|
1364e5faa9 | ||
|
|
7622deef3c | ||
|
|
ae3a27510f | ||
|
|
2090646c47 | ||
|
|
2a0510506c | ||
|
|
b7fd587b9e | ||
|
|
afdeede5b0 | ||
|
|
98959ab40a | ||
|
|
f6c311fb7c | ||
|
|
5323a1dbaa | ||
|
|
03492153df | ||
|
|
e68c963f1f | ||
|
|
e97ce47048 | ||
|
|
52504494a2 | ||
|
|
34051cb612 | ||
|
|
2f65458ddf | ||
|
|
13ec02cc5d | ||
|
|
f827b5e28e | ||
|
|
b69ab4c0e0 | ||
|
|
9fe5c00d4a | ||
|
|
27d47edd3d | ||
|
|
1fba852953 | ||
|
|
dbf6a61d19 | ||
|
|
06255cef01 | ||
|
|
cf7a106515 | ||
|
|
43855f2e5c | ||
|
|
a6e144a5a2 | ||
|
|
a9d711060b | ||
|
|
9bd06b6118 | ||
|
|
ba2ca7c94d | ||
|
|
869c543eaa | ||
|
|
d2bdaf3aab | ||
|
|
94cb6d3ba8 | ||
|
|
c70f776ee5 | ||
|
|
019d795685 | ||
|
|
6b6f1fe383 | ||
|
|
3e1f9cb027 | ||
|
|
9ca38dba65 | ||
|
|
44eb532548 | ||
|
|
970aa9f07d | ||
|
|
196822ef9f | ||
|
|
22460f6c7f | ||
|
|
6b13c93a47 | ||
|
|
a7a8578d51 | ||
|
|
7cd0c3e565 | ||
|
|
bd94cfbcf4 | ||
|
|
fb9239bf3b | ||
|
|
5ae926461f | ||
|
|
048e95d966 | ||
|
|
0d83f14fa3 | ||
|
|
923c3722eb | ||
|
|
89bcdc1404 | ||
|
|
2095c71e94 | ||
|
|
30a22fec28 | ||
|
|
4a3c2859e6 | ||
|
|
8fd965819c | ||
|
|
542406fba1 | ||
|
|
353252d7f9 | ||
|
|
e9bff3a493 | ||
|
|
24ce678c74 | ||
|
|
cde2d2954d | ||
|
|
d89c94d7bb | ||
|
|
2c618bb6d4 | ||
|
|
3447e059a4 | ||
|
|
6bb2f28908 | ||
|
|
29578c8c48 | ||
|
|
6c163a54eb | ||
|
|
32c423c16d | ||
|
|
481c2002ff | ||
|
|
10df6c4c0c | ||
|
|
f0f336d15f | ||
|
|
f8ec6251f0 | ||
|
|
942873c5a1 | ||
|
|
2b25a7b3d6 | ||
|
|
6f7ca3ea99 | ||
|
|
9d4f51ee10 | ||
|
|
00b18c4d6a | ||
|
|
3a92f0bb34 | ||
|
|
be4ec7df10 | ||
|
|
d5e813aa56 | ||
|
|
ce009d9c9a | ||
|
|
253c3274fe | ||
|
|
0c5846fe93 | ||
|
|
30836ce2bf | ||
|
|
4de892eaf8 | ||
|
|
06185def6b | ||
|
|
b3527ffd0f | ||
|
|
436a0a275c | ||
|
|
456122cfd0 | ||
|
|
046eefa4af | ||
|
|
402ff90c4e | ||
|
|
89baf45371 | ||
|
|
8e5fa8ef33 | ||
|
|
9085b6dc79 | ||
|
|
7ef5a9311b | ||
|
|
f9b3eb5bd6 | ||
|
|
10b7f7a00f | ||
|
|
f27eb02caf | ||
|
|
16b6e791a4 | ||
|
|
cc9c4ac2b2 | ||
|
|
59f066f974 | ||
|
|
c98a232fb1 | ||
|
|
4a698e9e76 | ||
|
|
b85a2ad7bb | ||
|
|
b5e1f3af26 | ||
|
|
a4b438e59e | ||
|
|
f178572e77 | ||
|
|
087a64298e | ||
|
|
6246b652a5 | ||
|
|
d6bfabe7cc | ||
|
|
6dcef8370b | ||
|
|
9a3b1a339c | ||
|
|
d30c21e5f8 | ||
|
|
e64ad60b4a | ||
|
|
2c15ff7103 | ||
|
|
646d35222a | ||
|
|
cf64c03335 | ||
|
|
61315b09ec | ||
|
|
3411b0f3a8 | ||
|
|
a5641c5421 | ||
|
|
b733fe6f46 | ||
|
|
855002604b | ||
|
|
7bd5dffff9 | ||
|
|
279d60c008 | ||
|
|
400b72ecfc | ||
|
|
54d02ab16a | ||
|
|
4e7ec310b3 | ||
|
|
8b170b1651 | ||
|
|
767c9ee06f | ||
|
|
83e06bdc7f | ||
|
|
112cb47c62 | ||
|
|
3fccebb030 | ||
|
|
db0f1cf47f | ||
|
|
7137314e58 | ||
|
|
7f857a2f42 | ||
|
|
92559772f1 | ||
|
|
04430f32ba | ||
|
|
0a35bd3dc8 | ||
|
|
c6b485ea69 | ||
|
|
373594e5a3 | ||
|
|
ba3505536d | ||
|
|
c2a47f51b5 | ||
|
|
b48f57c23b | ||
|
|
fdf23030c2 | ||
|
|
845d53e594 | ||
|
|
de137bbc70 | ||
|
|
9e7dee7ad4 | ||
|
|
2d543a45e2 | ||
|
|
da03627ff1 | ||
|
|
66c9bc3647 | ||
|
|
c1bbf97b2e | ||
|
|
71fccb0b52 | ||
|
|
9ee407b1ab | ||
|
|
06f675743c | ||
|
|
fa9312534d | ||
|
|
bc3d236031 | ||
|
|
bdc16278fc | ||
|
|
4deef5c544 | ||
|
|
2c522cb0db | ||
|
|
d0809b6601 | ||
|
|
7e2d30a244 | ||
|
|
d326aad555 | ||
|
|
67c3370ab9 | ||
|
|
b562762291 | ||
|
|
e00a74ccfc | ||
|
|
e9bf7d5f1c | ||
|
|
f2dd043daa |
+27
-4
@@ -12,17 +12,40 @@
|
||||
*.la
|
||||
*.a
|
||||
|
||||
# Visual studio cruft
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.suo
|
||||
*.user
|
||||
*/x64
|
||||
*\Debug*
|
||||
*\Release*
|
||||
*.log
|
||||
*.tlog*
|
||||
*.obj
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
*.pdb
|
||||
*.idb
|
||||
*\build_*
|
||||
|
||||
# misc files mostly used for testing
|
||||
out.txt
|
||||
ptr.txt
|
||||
test.txt
|
||||
unittests
|
||||
boost_serialize
|
||||
arr.txt
|
||||
performance
|
||||
sandbox
|
||||
sandbox_rtti
|
||||
sandbox_json
|
||||
include_renamed
|
||||
.ycm_extra_conf.py*
|
||||
doc/html
|
||||
rtti.txt
|
||||
doc/latex
|
||||
portability64
|
||||
portability32
|
||||
file.json
|
||||
out.xml
|
||||
cereal_version.out
|
||||
xml_ordering.out
|
||||
build
|
||||
/out/
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
# Portions of this file based on https://github.com/Microsoft/GSL/blob/master/.travis.yml
|
||||
|
||||
language: cpp
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
group: beta
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources: &default_sources
|
||||
- ubuntu-toolchain-r-test
|
||||
- libboost-latest
|
||||
packages: &default_packages
|
||||
- libboost-serialization-dev
|
||||
- libboost-dev
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# |---------- LINUX GCC ----------|
|
||||
- compiler: g++-4.7
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=g++-4.7"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['g++-4.7', *default_packages]
|
||||
|
||||
- compiler: g++-4.8
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=g++-4.8"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['g++-4.8', *default_packages]
|
||||
|
||||
- compiler: g++-4.9
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=g++-4.9"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['g++-4.9', *default_packages]
|
||||
|
||||
- compiler: g++-5
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=g++-5"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['g++-5', *default_packages]
|
||||
|
||||
- compiler: g++-5
|
||||
name: "g++-5 multilib"
|
||||
env: ["COMPILER=g++-5"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['gcc-multilib g++-5-multilib linux-libc-dev', *default_packages]
|
||||
|
||||
- compiler: g++-6
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=g++-6"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['g++-6', *default_packages]
|
||||
|
||||
- compiler: g++-7
|
||||
name: "g++-7 c++17"
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON -DCMAKE_CXX_STANDARD=17'", "COMPILER=g++-7"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['g++-7', *default_packages]
|
||||
|
||||
# |---------- LINUX GCC ----------|
|
||||
- dist: xenial
|
||||
compiler: g++-8
|
||||
name: "g++-8 c++17"
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON -DCMAKE_CXX_STANDARD=17'", "COMPILER=g++-8"]
|
||||
addons:
|
||||
apt:
|
||||
sources: *default_sources
|
||||
packages: ['g++-8', *default_packages]
|
||||
|
||||
|
||||
# |---------- LINUX CLANG ----------|
|
||||
- compiler: clang++-3.5
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=clang++-3.5"]
|
||||
addons:
|
||||
apt:
|
||||
sources: [*default_sources, llvm-toolchain-precise-3.5]
|
||||
packages: ['clang-3.5', *default_packages]
|
||||
|
||||
- compiler: clang++-3.6
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=clang++-3.6"]
|
||||
addons:
|
||||
apt:
|
||||
sources: [*default_sources, llvm-toolchain-precise-3.6]
|
||||
packages: ['clang-3.6', *default_packages]
|
||||
|
||||
- compiler: clang++-3.7
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=clang++-3.7"]
|
||||
addons:
|
||||
apt:
|
||||
sources: [*default_sources, llvm-toolchain-precise-3.7]
|
||||
packages: ['clang-3.7', *default_packages]
|
||||
|
||||
- compiler: clang++-3.8
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=clang++-3.8"]
|
||||
addons:
|
||||
apt:
|
||||
sources: [*default_sources, llvm-toolchain-precise-3.8]
|
||||
packages: ['clang-3.8', *default_packages]
|
||||
|
||||
- compiler: clang++-3.9
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=clang++-3.9"]
|
||||
addons:
|
||||
apt:
|
||||
sources: [*default_sources, llvm-toolchain-precise-3.9]
|
||||
packages: ['clang-3.9', *default_packages]
|
||||
|
||||
- compiler: clang++-4.0
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=clang++-4.0"]
|
||||
addons:
|
||||
apt:
|
||||
sources: [*default_sources, llvm-toolchain-trusty-4.0]
|
||||
packages: ['clang-4.0', 'g++-5', *default_packages]
|
||||
|
||||
- compiler: clang++-5.0
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON'", "COMPILER=clang++-5.0"]
|
||||
addons: &clang50
|
||||
apt:
|
||||
packages:
|
||||
- clang-5.0
|
||||
- g++-7
|
||||
- *default_packages
|
||||
sources:
|
||||
- *default_sources
|
||||
- llvm-toolchain-trusty-5.0
|
||||
- sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main'
|
||||
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
|
||||
- env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON -DCMAKE_CXX_STANDARD=17'", "COMPILER=clang++-5.0"]
|
||||
name: "clang++-5.0 c++17"
|
||||
addons: *clang50
|
||||
|
||||
- compiler: clang++-7
|
||||
name: "clang++-7 c++17"
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON -DCMAKE_CXX_STANDARD=17'", "COMPILER=clang++-7"]
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-7
|
||||
- g++-7
|
||||
- *default_packages
|
||||
sources:
|
||||
- *default_sources
|
||||
- llvm-toolchain-trusty-7
|
||||
|
||||
- compiler: clang++-8
|
||||
name: "clang++-8 c++17 libc++"
|
||||
env: ["CMAKE_OPTIONS='-DSKIP_PORTABILITY_TEST=ON -DCMAKE_CXX_STANDARD=17 -DCLANG_USE_LIBCPP=ON -DSKIP_PERFORMANCE_COMPARISON=ON'", "COMPILER=clang++-8"]
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-8
|
||||
- g++-8
|
||||
- libc++-8-dev
|
||||
- libc++abi-8-dev
|
||||
- *default_packages
|
||||
sources:
|
||||
- *default_sources
|
||||
- llvm-toolchain-trusty-8
|
||||
|
||||
# # |---------- LINUX CLANG (32-bit) ----------|
|
||||
# # Doesn't work.
|
||||
# - compiler: clang++
|
||||
# addons:
|
||||
# apt:
|
||||
# sources: [*default_sources]
|
||||
# packages: ['clang', 'gcc-multilib', 'g++-multilib', *default_packages]
|
||||
|
||||
|
||||
# |---------- OSX CLANG ----------|
|
||||
- compiler: clang++
|
||||
os: osx
|
||||
osx_image: xcode7.3
|
||||
env: COMPILER=clang++
|
||||
|
||||
- compiler: clang++
|
||||
os: osx
|
||||
osx_image: xcode8
|
||||
env: COMPILER=clang++
|
||||
|
||||
# # Missing CMake
|
||||
# - compiler: clang++
|
||||
# os: osx
|
||||
# osx_image: xcode8.1
|
||||
|
||||
- compiler: clang++
|
||||
os: osx
|
||||
osx_image: xcode8.2
|
||||
env: COMPILER=clang++
|
||||
|
||||
- compiler: clang++
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
env: COMPILER=clang++
|
||||
|
||||
- compiler: clang++
|
||||
env: ["CMAKE_OPTIONS='-DWITH_WERROR=OFF'"]
|
||||
os: osx
|
||||
osx_image: xcode9
|
||||
env: COMPILER=clang++
|
||||
|
||||
- compiler: clang++
|
||||
env: ["CMAKE_OPTIONS='-DWITH_WERROR=OFF'"]
|
||||
os: osx
|
||||
osx_image: xcode10
|
||||
env: COMPILER=clang++
|
||||
|
||||
install:
|
||||
# Set the ${CXX} variable properly
|
||||
- export CXX=${COMPILER}
|
||||
- ${CXX} --version
|
||||
|
||||
# Dependencies required by the CI are installed in ${TRAVIS_BUILD_DIR}/deps/
|
||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||
- mkdir -p "${DEPS_DIR}"
|
||||
- cd "${DEPS_DIR}"
|
||||
|
||||
- JOBS=2
|
||||
|
||||
# [linux]: Install the right version of libc++
|
||||
- |
|
||||
LLVM_INSTALL=${DEPS_DIR}/llvm/install
|
||||
# if in linux and compiler clang and llvm not installed
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" && "${CXX%%+*}" == "clang" && -n "$(ls -A ${LLVM_INSTALL})" ]]; then
|
||||
if [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2";
|
||||
elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1";
|
||||
elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1";
|
||||
elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1";
|
||||
fi
|
||||
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz"
|
||||
LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz"
|
||||
LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz"
|
||||
mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi
|
||||
travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm
|
||||
travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx
|
||||
travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi
|
||||
(cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_INSTALL})
|
||||
(cd llvm/build/projects/libcxx && make install -j2)
|
||||
(cd llvm/build/projects/libcxxabi && make install -j2)
|
||||
export CXXFLAGS="-isystem ${LLVM_INSTALL}/include/c++/v1"
|
||||
export LDFLAGS="-L ${LLVM_INSTALL}/lib -l c++ -l c++abi"
|
||||
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_INSTALL}/lib"
|
||||
fi
|
||||
|
||||
script:
|
||||
- cd "${TRAVIS_BUILD_DIR}"
|
||||
- if [[ "${COMPILERCC}" != "" ]]; then export CC="${COMPILERCC}"; fi
|
||||
- if [[ "${COMPILER}" != "" ]]; then export CXX="${COMPILER}"; fi
|
||||
- $CXX --version
|
||||
- cmake --version
|
||||
- mkdir build && cd build
|
||||
- cmake ${CMAKE_OPTIONS} .. && make -j4
|
||||
- ctest . --output-on-failure
|
||||
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
@@ -0,0 +1,84 @@
|
||||
cmake_minimum_required (VERSION 2.6.2)
|
||||
project (cereal)
|
||||
|
||||
option(SKIP_PORTABILITY_TEST "Skip portability (32 bit) tests" OFF)
|
||||
option(SKIP_PERFORMANCE_COMPARISON "Skip building performance comparison (requires boost)" OFF)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.0) # installing cereal requires INTERFACE lib
|
||||
option(JUST_INSTALL_CEREAL "Don't do anything besides installing the library" OFF)
|
||||
endif()
|
||||
|
||||
option(THREAD_SAFE "Use mutexes to ensure thread safety" OFF)
|
||||
if(THREAD_SAFE)
|
||||
add_definitions(-DCEREAL_THREAD_SAFE=1)
|
||||
set(CEREAL_THREAD_LIBS "pthread")
|
||||
else()
|
||||
set(CEREAL_THREAD_LIBS "")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /W3 /WX")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "-Wall -g -Wextra -Wshadow -pedantic -Wold-style-cast ${CMAKE_CXX_FLAGS}")
|
||||
option(WITH_WERROR "Compile with '-Werror' C++ compiler flag" ON)
|
||||
if(WITH_WERROR)
|
||||
set(CMAKE_CXX_FLAGS "-Werror ${CMAKE_CXX_FLAGS}")
|
||||
endif(WITH_WERROR)
|
||||
|
||||
option(CLANG_USE_LIBCPP "Use libc++ for clang compilation" OFF)
|
||||
if(CLANG_USE_LIBCPP)
|
||||
set(CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.1)
|
||||
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD STREQUAL "98")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_STANDARD GREATER 14)
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
add_library(cereal INTERFACE)
|
||||
target_include_directories(cereal INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
install(TARGETS cereal EXPORT cereal
|
||||
DESTINATION lib) # ignored
|
||||
install(EXPORT cereal FILE cereal-config.cmake
|
||||
DESTINATION share/cmake/cereal)
|
||||
install(DIRECTORY include/cereal DESTINATION include)
|
||||
endif()
|
||||
|
||||
if(JUST_INSTALL_CEREAL)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include_directories(./include)
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.12)
|
||||
cmake_policy(VERSION 3.12)
|
||||
endif()
|
||||
|
||||
# Boost serialization for performance sandbox
|
||||
find_package(Boost COMPONENTS serialization)
|
||||
|
||||
if(Boost_FOUND)
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
endif(Boost_FOUND)
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(unittests)
|
||||
|
||||
add_subdirectory(sandbox)
|
||||
|
||||
add_subdirectory(doc)
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
CPPFLAGS=-std=c++11 -I./include -Wall -Werror -g
|
||||
CC=g++
|
||||
COVERAGE_OUTPUT=out
|
||||
|
||||
all: unittests sandbox performance sandbox_rtti sandbox_json
|
||||
|
||||
sandbox: sandbox.cpp
|
||||
${CC} sandbox.cpp -o sandbox ${CPPFLAGS}
|
||||
|
||||
sandbox_json: sandbox_json.cpp
|
||||
${CC} sandbox_json.cpp -o sandbox_json ${CPPFLAGS}
|
||||
|
||||
sandbox_rtti: sandbox_rtti.cpp
|
||||
${CC} sandbox_rtti.cpp -o sandbox_rtti ${CPPFLAGS} -O3
|
||||
|
||||
unittests: unittests.cpp
|
||||
${CC} unittests.cpp -o unittests -lboost_unit_test_framework ${CPPFLAGS}
|
||||
./unittests --show_progress
|
||||
|
||||
performance: performance.cpp
|
||||
${CC} performance.cpp -o performance -lboost_serialization ${CPPFLAGS} -O3
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
g++ -std=c++11 -I./include -Wall -Werror -g -O0 -coverage unittests.cpp -o unittests_coverage -lboost_unit_test_framework
|
||||
./unittests_coverage --show_progress
|
||||
lcov --capture --directory . --output-file coverage.info --no-external
|
||||
lcov --remove coverage.info '*/external/*' 'cereal/details/util.hpp' 'unittests.cpp' -o coverage.info
|
||||
genhtml --demangle-cpp coverage.info --output-directory ${COVERAGE_OUTPUT}
|
||||
|
||||
.PHONY: doc
|
||||
doc:
|
||||
@doxygen ./doc/doxygen.cfg
|
||||
|
||||
clean:
|
||||
rm sandbox; rm unittests; rm performance; rm sandbox_rtti; rm sandbox_json;
|
||||
@@ -16,7 +16,7 @@ Installation and use of of cereal is fully documented on the [main web page](htt
|
||||
* Use the serialization archives to load and save data
|
||||
|
||||
```cpp
|
||||
#include <cereal/types/map.hpp>
|
||||
#include <cereal/types/unordered_map.hpp>
|
||||
#include <cereal/types/memory.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
#include <fstream>
|
||||
@@ -55,7 +55,7 @@ struct SomeData
|
||||
|
||||
int main()
|
||||
{
|
||||
std::ofstream os("out.cereal");
|
||||
std::ofstream os("out.cereal", std::ios::binary);
|
||||
cereal::BinaryOutputArchive archive( os );
|
||||
|
||||
SomeData myData;
|
||||
@@ -65,11 +65,21 @@ int main()
|
||||
}
|
||||
```
|
||||
|
||||
### cereal has a mailing list
|
||||
|
||||
Either get in touch over <a href="mailto:cerealcpp@googlegroups.com">email</a> or [on the web](https://groups.google.com/forum/#!forum/cerealcpp).
|
||||
|
||||
|
||||
|
||||
## cereal has a permissive license
|
||||
|
||||
cereal is licensed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause).
|
||||
|
||||
## cereal build status
|
||||
|
||||
* develop : [](https://travis-ci.com/USCiLab/cereal)
|
||||
[](https://ci.appveyor.com/project/AzothAmmo/cereal/branch/develop)
|
||||
|
||||
---
|
||||
|
||||
Were you looking for the Haskell cereal? Go <a href="https://github.com/GaloisInc/cereal">here</a>.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# can use variables like {build} and {branch}
|
||||
version: 1.2.{build}
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
VS_VERSION_MAJOR: 12
|
||||
BOOST_ROOT: C:\Libraries\boost_1_58_0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
VS_VERSION_MAJOR: 14
|
||||
BOOST_ROOT: C:\Libraries\boost_1_60_0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
VS_VERSION_MAJOR: 15
|
||||
BOOST_ROOT: C:\Libraries\boost_1_66_0
|
||||
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 Preview
|
||||
# VS_VERSION_MAJOR: 16
|
||||
# BOOST_ROOT: C:\Libraries\boost_1_66_0
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
- x64
|
||||
|
||||
before_build: "scripts\\appveyor.bat"
|
||||
|
||||
build:
|
||||
parallel: true
|
||||
project: build/cereal.sln
|
||||
verbosity: minimal
|
||||
|
||||
test_script: "scripts\\appveyor.bat test"
|
||||
|
||||
artifacts:
|
||||
- path: build\Testing
|
||||
- path: out
|
||||
@@ -0,0 +1,18 @@
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/doxygen.in" "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg" @ONLY)
|
||||
add_custom_target(doc
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
|
||||
COMMENT "Generating API documentation with Doxygen" VERBATIM
|
||||
)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../scripts/updatedoc.in" "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh" @ONLY)
|
||||
add_custom_target(update-doc
|
||||
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh"
|
||||
DEPENDS doc
|
||||
COMMENT "Copying documentation to gh-pages branch" VERBATIM
|
||||
)
|
||||
|
||||
endif(DOXYGEN_FOUND)
|
||||
@@ -52,7 +52,7 @@ PROJECT_LOGO =
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = doc
|
||||
OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
|
||||
# 4096 sub-directories (in 2 levels) under the output directory of each output
|
||||
@@ -343,7 +343,7 @@ TYPEDEF_HIDES_STRUCT = NO
|
||||
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
|
||||
# corresponding to a cache size of 2^16 = 65536 symbols.
|
||||
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
#SYMBOL_CACHE_SIZE = 0
|
||||
|
||||
# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
|
||||
# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
|
||||
@@ -595,7 +595,7 @@ FILE_VERSION_FILTER =
|
||||
# You can optionally specify a file name after the option, if omitted
|
||||
# DoxygenLayout.xml will be used as the name of the layout file.
|
||||
|
||||
LAYOUT_FILE = "doc/DoxygenLayout.xml"
|
||||
LAYOUT_FILE = "@CMAKE_CURRENT_SOURCE_DIR@/DoxygenLayout.xml"
|
||||
|
||||
# The CITE_BIB_FILES tag can be used to specify one or more bib files
|
||||
# containing the references data. This must be a list of .bib files. The
|
||||
@@ -668,7 +668,7 @@ WARN_LOGFILE =
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = include doc
|
||||
INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../include @CMAKE_CURRENT_SOURCE_DIR@/
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
@@ -701,7 +701,7 @@ RECURSIVE = YES
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE = external
|
||||
EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/../external
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
@@ -911,7 +911,7 @@ HTML_HEADER =
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard footer.
|
||||
|
||||
HTML_FOOTER ="./doc/footer.html"
|
||||
HTML_FOOTER ="@CMAKE_CURRENT_SOURCE_DIR@/footer.html"
|
||||
|
||||
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
|
||||
# style sheet that is used by each HTML page. It can be used to
|
||||
@@ -1294,7 +1294,7 @@ EXTRA_SEARCH_MAPPINGS =
|
||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# generate Latex output.
|
||||
|
||||
GENERATE_LATEX = YES
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
@@ -1476,13 +1476,13 @@ XML_OUTPUT = xml
|
||||
# which can be used by a validating XML parser to check the
|
||||
# syntax of the XML files.
|
||||
|
||||
XML_SCHEMA =
|
||||
# XML_SCHEMA =
|
||||
|
||||
# The XML_DTD tag can be used to specify an XML DTD,
|
||||
# which can be used by a validating XML parser to check the
|
||||
# syntax of the XML files.
|
||||
|
||||
XML_DTD =
|
||||
# XML_DTD =
|
||||
|
||||
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
|
||||
# dump the program listings (including syntax highlighting
|
||||
@@ -1626,7 +1626,7 @@ TAGFILES =
|
||||
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
||||
# a tag file that is based on the input files it reads.
|
||||
|
||||
GENERATE_TAGFILE =
|
||||
GENERATE_TAGFILE = cereal.doxytags
|
||||
|
||||
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
||||
# in the class index. If set to NO only the inherited external classes
|
||||
+6
-2
@@ -22,7 +22,7 @@ If you need reference on a specific file, the <a href="files.html">files</a> pag
|
||||
/*! \defgroup Access Access Control and Disambiguation
|
||||
Provides ways to give cereal access to protected member functions, disambiguate
|
||||
which serialization function cereal should use, and provide ways of using smart
|
||||
pointers with types that have no default constructor */
|
||||
pointers with types that have no default constructor. */
|
||||
|
||||
/*! \defgroup Utility Utility Functionality
|
||||
Name-value pairs, binary data wrappers, exceptions, and other utility functions */
|
||||
@@ -31,7 +31,11 @@ If you need reference on a specific file, the <a href="files.html">files</a> pag
|
||||
Serialization of many types is shipped with cereal, including most of the standard library as well as a few others. */
|
||||
|
||||
/*! \defgroup STLSupport Standard Library Support
|
||||
Serialization methods for nearly all types found in the C++ standard library
|
||||
Serialization methods for nearly all types found in the C++ standard library.
|
||||
\ingroup TypeSupport */
|
||||
|
||||
/*! \defgroup TypeConcepts Abstract Type Concept Support
|
||||
Serialization methods for more abstract type concepts that can generalize over many types.
|
||||
\ingroup TypeSupport */
|
||||
|
||||
/*! \defgroup OtherTypes Miscellaneous Types Support
|
||||
|
||||
+248
-103
@@ -1,7 +1,7 @@
|
||||
/*! \file access.hpp
|
||||
\brief Access control, default construction, and serialization disambiguation */
|
||||
\brief Access control and default construction */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,15 +30,24 @@
|
||||
#define CEREAL_ACCESS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
#include "cereal/macros.hpp"
|
||||
#include "cereal/specialize.hpp"
|
||||
#include "cereal/details/helpers.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! A class that allows cereal to load smart pointers to types that have no default constructor
|
||||
/*! If your class does not have a default constructor, cereal will not be able
|
||||
to load any smart pointers to it unless you overload LoadAndAllocate
|
||||
for your class, and provide an appropriate load_and_allocate method.
|
||||
to load any smart pointers to it unless you overload LoadAndConstruct
|
||||
for your class, and provide an appropriate load_and_construct method. You can also
|
||||
choose to define a member static function instead of specializing this class.
|
||||
|
||||
The specialization of LoadAndAllocate must be placed within the cereal namespace:
|
||||
The specialization of LoadAndConstruct must be placed within the cereal namespace:
|
||||
|
||||
@code{.cpp}
|
||||
struct MyType
|
||||
@@ -46,7 +55,7 @@ namespace cereal
|
||||
MyType( int x ); // note: no default ctor
|
||||
int myX;
|
||||
|
||||
// Define a serialize or save/load pair as you normally would
|
||||
// Define a serialize or load/save pair as you normally would
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
@@ -54,39 +63,162 @@ namespace cereal
|
||||
}
|
||||
};
|
||||
|
||||
// Provide a specialization for LoadAndAllocate for your type
|
||||
// Provide a specialization for LoadAndConstruct for your type
|
||||
namespace cereal
|
||||
{
|
||||
template <> struct LoadAndAllocate<MyType>
|
||||
template <> struct LoadAndConstruct<MyType>
|
||||
{
|
||||
// load_and_allocate will be passed the archive that you will be loading
|
||||
// from and should return a raw pointer to a dynamically allocated instance
|
||||
// of your type.
|
||||
//
|
||||
// This will be captured by a smart pointer of some type and you need not
|
||||
// worry about managing the memory
|
||||
// load_and_construct will be passed the archive that you will be loading
|
||||
// from as well as a construct object which you can use as if it were the
|
||||
// constructor for your type. cereal will handle all memory management for you.
|
||||
template <class Archive>
|
||||
static MyType * load_and_allocate( Archive & ar )
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
|
||||
{
|
||||
int x;
|
||||
ar( x );
|
||||
return new MyType( x );
|
||||
construct( x );
|
||||
}
|
||||
|
||||
// if you require versioning, simply add a const std::uint32_t as the final parameter, e.g.:
|
||||
// load_and_construct( Archive & ar, cereal::construct<MyType> & construct, std::uint32_t const version )
|
||||
};
|
||||
} // end namespace cereal
|
||||
@endcode
|
||||
|
||||
Please note that just as in using external serialization functions, you cannot get
|
||||
access to non-public members of your class by befriending cereal::access. If you
|
||||
have the ability to modify the class you wish to serialize, it is recommended that you
|
||||
use member serialize functions and a static member load_and_construct function.
|
||||
|
||||
load_and_construct functions, regardless of whether they are static members of your class or
|
||||
whether you create one in the LoadAndConstruct specialization, have the following signature:
|
||||
|
||||
@code{.cpp}
|
||||
// generally Archive will be templated, but it can be specific if desired
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct );
|
||||
// with an optional last parameter specifying the version: const std::uint32_t version
|
||||
@endcode
|
||||
|
||||
Versioning behaves the same way as it does for standard serialization functions.
|
||||
|
||||
@tparam T The type to specialize for
|
||||
@ingroup Access */
|
||||
template <class T>
|
||||
struct LoadAndAllocate
|
||||
struct LoadAndConstruct
|
||||
{ };
|
||||
|
||||
// forward decl for construct
|
||||
//! @cond PRIVATE_NEVERDEFINED
|
||||
namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
|
||||
namespace boost_variant_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
|
||||
//! @endcond
|
||||
|
||||
//! Used to construct types with no default constructor
|
||||
/*! When serializing a type that has no default constructor, cereal
|
||||
will attempt to call either the class static function load_and_construct
|
||||
or the appropriate template specialization of LoadAndConstruct. cereal
|
||||
will pass that function a reference to the archive as well as a reference
|
||||
to a construct object which should be used to perform the allocation once
|
||||
data has been appropriately loaded.
|
||||
|
||||
@code{.cpp}
|
||||
struct MyType
|
||||
{
|
||||
// note the lack of default constructor
|
||||
MyType( int xx, int yy );
|
||||
|
||||
int x, y;
|
||||
double notInConstructor;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( x, y );
|
||||
ar( notInConstructor );
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
|
||||
{
|
||||
int x, y;
|
||||
ar( x, y );
|
||||
|
||||
// use construct object to initialize with loaded data
|
||||
construct( x, y );
|
||||
|
||||
// access to member variables and functions via -> operator
|
||||
ar( construct->notInConstructor );
|
||||
|
||||
// could also do the above section by:
|
||||
double z;
|
||||
ar( z );
|
||||
construct->notInConstructor = z;
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
@tparam T The class type being serialized
|
||||
*/
|
||||
template <class T>
|
||||
class construct
|
||||
{
|
||||
//! Called by cereal if no default constructor exists to load and allocate data simultaneously
|
||||
/*! Overloads of this should return a pointer to T and expect an archive as a parameter */
|
||||
static void load_and_allocate(...)
|
||||
{ }
|
||||
public:
|
||||
//! Construct and initialize the type T with the given arguments
|
||||
/*! This will forward all arguments to the underlying type T,
|
||||
calling an appropriate constructor.
|
||||
|
||||
Calling this function more than once will result in an exception
|
||||
being thrown.
|
||||
|
||||
@param args The arguments to the constructor for T
|
||||
@throw Exception If called more than once */
|
||||
template <class ... Args>
|
||||
void operator()( Args && ... args );
|
||||
// implementation deferred due to reliance on cereal::access
|
||||
|
||||
//! Get a reference to the initialized underlying object
|
||||
/*! This must be called after the object has been initialized.
|
||||
|
||||
@return A reference to the initialized object
|
||||
@throw Exception If called before initialization */
|
||||
T * operator->()
|
||||
{
|
||||
if( !itsValid )
|
||||
throw Exception("Object must be initialized prior to accessing members");
|
||||
|
||||
return itsPtr;
|
||||
}
|
||||
|
||||
//! Returns a raw pointer to the initialized underlying object
|
||||
/*! This is mainly intended for use with passing an instance of
|
||||
a constructed object to cereal::base_class.
|
||||
|
||||
It is strongly recommended to avoid using this function in
|
||||
any other circumstance.
|
||||
|
||||
@return A raw pointer to the initialized type */
|
||||
T * ptr()
|
||||
{
|
||||
return operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Ar, class TT> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
|
||||
template <class Ar, class TT> friend struct ::cereal::boost_variant_detail::LoadAndConstructLoadWrapper;
|
||||
|
||||
construct( T * p ) : itsPtr( p ), itsEnableSharedRestoreFunction( [](){} ), itsValid( false ) {}
|
||||
construct( T * p, std::function<void()> enableSharedFunc ) : // g++4.7 ice with default lambda to std func
|
||||
itsPtr( p ), itsEnableSharedRestoreFunction( enableSharedFunc ), itsValid( false ) {}
|
||||
construct( construct const & ) = delete;
|
||||
construct & operator=( construct const & ) = delete;
|
||||
|
||||
T * itsPtr;
|
||||
std::function<void()> itsEnableSharedRestoreFunction;
|
||||
bool itsValid;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! A class that can be made a friend to give cereal access to non public functions
|
||||
/*! If you desire non-public serialization functions within a class, cereal can only
|
||||
access these if you declare cereal::access a friend.
|
||||
@@ -108,99 +240,112 @@ namespace cereal
|
||||
class access
|
||||
{
|
||||
public:
|
||||
// ####### Standard Serialization ########################################
|
||||
template<class Archive, class T> inline
|
||||
static auto member_serialize(Archive & ar, T & t) -> decltype(t.serialize(ar))
|
||||
{ t.serialize(ar); }
|
||||
static auto member_serialize(Archive & ar, T & t) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save(Archive & ar, T const & t) -> decltype(t.save(ar))
|
||||
{ t.save(ar); }
|
||||
|
||||
// Used during detection of non const member save
|
||||
template<class Archive, class T> inline
|
||||
static auto non_const_member_save(Archive & ar, T & t) -> decltype(t.save(ar))
|
||||
{ t.save(ar); }
|
||||
static auto member_save(Archive & ar, T const & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar))
|
||||
{ t.load(ar); }
|
||||
static auto member_save_non_const(Archive & ar, T & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
|
||||
|
||||
template <class T>
|
||||
static void load_and_allocate(...)
|
||||
{ }
|
||||
template<class Archive, class T> inline
|
||||
static auto member_load(Archive & ar, T & t) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_LOAD_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal(Archive const & ar, T const & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal_non_const(Archive const & ar, T & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
|
||||
|
||||
template<class Archive, class T, class U> inline
|
||||
static auto member_load_minimal(Archive const & ar, T & t, U && u) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)))
|
||||
{ return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)); }
|
||||
|
||||
// ####### Versioned Serialization #######################################
|
||||
template<class Archive, class T> inline
|
||||
static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_LOAD_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal(Archive const & ar, T const & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save_minimal_non_const(Archive const & ar, T & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
|
||||
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
|
||||
|
||||
template<class Archive, class T, class U> inline
|
||||
static auto member_load_minimal(Archive const & ar, T & t, U && u, const std::uint32_t version) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version))
|
||||
{ return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version); }
|
||||
|
||||
// ####### Other Functionality ##########################################
|
||||
// for detecting inheritance from enable_shared_from_this
|
||||
template <class T> inline
|
||||
static auto shared_from_this(T & t) -> decltype(t.shared_from_this());
|
||||
|
||||
// for placement new
|
||||
template <class T, class ... Args> inline
|
||||
static void construct( T *& ptr, Args && ... args )
|
||||
{
|
||||
new (ptr) T( std::forward<Args>( args )... );
|
||||
}
|
||||
|
||||
// for non-placement new with a default constructor
|
||||
template <class T> inline
|
||||
static T * construct()
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
|
||||
template <class T> inline
|
||||
static std::false_type load_and_construct(...)
|
||||
{ return std::false_type(); }
|
||||
|
||||
template<class T, class Archive> inline
|
||||
static auto load_and_allocate(Archive & ar) -> decltype(T::load_and_allocate(ar))
|
||||
{
|
||||
return T::load_and_allocate( ar );
|
||||
}
|
||||
};
|
||||
|
||||
//! A specifier used in conjunction with cereal::specialize to disambiguate
|
||||
//! serialization in special cases
|
||||
/*! @relates specialize
|
||||
@ingroup Access */
|
||||
enum class specialization
|
||||
{
|
||||
member_serialize, //!< Force the use of a member serialize function
|
||||
member_load_save, //!< Force the use of a member load/save pair
|
||||
non_member_serialize, //!< Force the use of a non-member serialize function
|
||||
non_member_load_save //!< Force the use of a non-member load/save pair
|
||||
};
|
||||
|
||||
//! A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class
|
||||
/*! cereal attempts to figure out which method of serialization (member vs. non-member serialize
|
||||
or load/save pair) at compile time. If for some reason cereal cannot find a non-ambiguous way
|
||||
of serializing a type, it will produce a static assertion complaining about this.
|
||||
|
||||
This can happen because you have both a serialize and load/save pair, or even because a base
|
||||
class has a serialize (public or private with friend access) and a derived class does not
|
||||
overwrite this due to choosing some other serialization type.
|
||||
|
||||
Specializing this class will tell cereal to explicitly use the serialization type you specify
|
||||
and it will not complain about ambiguity in its compile time selection. However, if cereal detects
|
||||
an ambiguity in specializations, it will continue to issue a static assertion.
|
||||
|
||||
@code{.cpp}
|
||||
class MyParent
|
||||
static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct) -> decltype(T::load_and_construct(ar, construct))
|
||||
{
|
||||
friend class cereal::access;
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar ) {}
|
||||
};
|
||||
|
||||
// Although serialize is private in MyParent, to cereal::access it will look public,
|
||||
// even through MyDerived
|
||||
class MyDerived : public MyParent
|
||||
{
|
||||
public:
|
||||
template <class Archive>
|
||||
void load( Archive & ar ) {}
|
||||
|
||||
template <class Archive>
|
||||
void save( Archive & ar ) {}
|
||||
};
|
||||
|
||||
// The save/load pair in MyDerived is ambiguous because serialize in MyParent can
|
||||
// be accessed from cereal::access. This looks the same as making serialize public
|
||||
// in MyParent, making it seem as though MyDerived has both a serialize and a load/save pair.
|
||||
// cereal will complain about this at compile time unless we disambiguate:
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// This struct specialization will tell cereal which is the right way to serialize the ambiguity
|
||||
template <class Archive> struct specialize<Archive, MyDerived, cereal::specialization::member_load_save> {};
|
||||
|
||||
// If we only had a disambiguation for a specific archive type, it would look something like this
|
||||
template <> struct specialize<cereal::BinaryOutputArchive, MyDerived, cereal::specialization::member_load_save> {};
|
||||
T::load_and_construct( ar, construct );
|
||||
}
|
||||
@endcode
|
||||
|
||||
@tparam T The type to specialize the serialization for
|
||||
@tparam S The specialization type to use for T
|
||||
@ingroup Access */
|
||||
template <class Archive, class T, specialization S>
|
||||
struct specialize : public std::false_type {};
|
||||
template<class T, class Archive> inline
|
||||
static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct, const std::uint32_t version) -> decltype(T::load_and_construct(ar, construct, version))
|
||||
{
|
||||
T::load_and_construct( ar, construct, version );
|
||||
}
|
||||
}; // end class access
|
||||
|
||||
// ######################################################################
|
||||
// Deferred Implementation, see construct for more information
|
||||
template <class T> template <class ... Args> inline
|
||||
void construct<T>::operator()( Args && ... args )
|
||||
{
|
||||
if( itsValid )
|
||||
throw Exception("Attempting to construct an already initialized object");
|
||||
|
||||
::cereal::access::construct( itsPtr, std::forward<Args>( args )... );
|
||||
itsEnableSharedRestoreFunction();
|
||||
itsValid = true;
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_ACCESS_HPP_
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*! \file adapters.hpp
|
||||
\brief Archive adapters that provide additional functionality
|
||||
on top of an existing archive */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_ARCHIVES_ADAPTERS_HPP_
|
||||
#define CEREAL_ARCHIVES_ADAPTERS_HPP_
|
||||
|
||||
#include "cereal/details/helpers.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
#ifdef CEREAL_FUTURE_EXPERIMENTAL
|
||||
|
||||
// Forward declaration for friend access
|
||||
template <class U, class A> U & get_user_data( A & );
|
||||
|
||||
//! Wraps an archive and gives access to user data
|
||||
/*! This adapter is useful if you require access to
|
||||
either raw pointers or references within your
|
||||
serialization functions.
|
||||
|
||||
While cereal does not directly support serialization
|
||||
raw pointers or references, it is sometimes the case
|
||||
that you may want to supply something such as a raw
|
||||
pointer or global reference to some constructor.
|
||||
In this situation this adapter would likely be used
|
||||
with the construct class to allow for non-default
|
||||
constructors.
|
||||
|
||||
@note This feature is experimental and may be altered or removed in a future release. See issue #46.
|
||||
|
||||
@code{.cpp}
|
||||
struct MyUserData
|
||||
{
|
||||
int * myRawPointer;
|
||||
std::reference_wrapper<MyOtherType> myReference;
|
||||
};
|
||||
|
||||
struct MyClass
|
||||
{
|
||||
// Note the raw pointer parameter
|
||||
MyClass( int xx, int * rawP );
|
||||
|
||||
int x;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{ ar( x ); }
|
||||
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyClass> & construct )
|
||||
{
|
||||
int xx;
|
||||
ar( xx );
|
||||
// note the need to use get_user_data to retrieve user data from the archive
|
||||
construct( xx, cereal::get_user_data<MyUserData>( ar ).myRawPointer );
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
MyUserData md;
|
||||
md.myRawPointer = &something;
|
||||
md.myReference = someInstanceOfType;
|
||||
|
||||
std::ifstream is( "data.xml" );
|
||||
cereal::UserDataAdapter<MyUserData, cereal::XMLInputArchive> ar( md, is );
|
||||
|
||||
std::unique_ptr<MyClass> sc;
|
||||
ar( sc ); // use as normal
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@relates get_user_data
|
||||
|
||||
@tparam UserData The type to give the archive access to
|
||||
@tparam Archive The archive to wrap */
|
||||
template <class UserData, class Archive>
|
||||
class UserDataAdapter : public Archive
|
||||
{
|
||||
public:
|
||||
//! Construct the archive with some user data struct
|
||||
/*! This will forward all arguments (other than the user
|
||||
data) to the wrapped archive type. The UserDataAdapter
|
||||
can then be used identically to the wrapped archive type
|
||||
|
||||
@tparam Args The arguments to pass to the constructor of
|
||||
the archive. */
|
||||
template <class ... Args>
|
||||
UserDataAdapter( UserData & ud, Args && ... args ) :
|
||||
Archive( std::forward<Args>( args )... ),
|
||||
userdata( ud )
|
||||
{ }
|
||||
|
||||
private:
|
||||
//! Overload the rtti function to enable dynamic_cast
|
||||
void rtti() {}
|
||||
friend UserData & get_user_data<UserData>( Archive & ar );
|
||||
UserData & userdata; //!< The actual user data
|
||||
};
|
||||
|
||||
//! Retrieves user data from an archive wrapped by UserDataAdapter
|
||||
/*! This will attempt to retrieve the user data associated with
|
||||
some archive wrapped by UserDataAdapter. If this is used on
|
||||
an archive that is not wrapped, a run-time exception will occur.
|
||||
|
||||
@note This feature is experimental and may be altered or removed in a future release. See issue #46.
|
||||
|
||||
@note The correct use of this function cannot be enforced at compile
|
||||
time.
|
||||
|
||||
@relates UserDataAdapter
|
||||
@tparam UserData The data struct contained in the archive
|
||||
@tparam Archive The archive, which should be wrapped by UserDataAdapter
|
||||
@param ar The archive
|
||||
@throws Exception if the archive this is used upon is not wrapped with
|
||||
UserDataAdapter. */
|
||||
template <class UserData, class Archive>
|
||||
UserData & get_user_data( Archive & ar )
|
||||
{
|
||||
try
|
||||
{
|
||||
return dynamic_cast<UserDataAdapter<UserData, Archive> &>( ar ).userdata;
|
||||
}
|
||||
catch( std::bad_cast const & )
|
||||
{
|
||||
throw ::cereal::Exception("Attempting to get user data from archive not wrapped in UserDataAdapter");
|
||||
}
|
||||
}
|
||||
#endif // CEREAL_FUTURE_EXPERIMENTAL
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_ARCHIVES_ADAPTERS_HPP_
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! \file binary.hpp
|
||||
\brief Binary input and output archives */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,7 +29,7 @@
|
||||
#ifndef CEREAL_ARCHIVES_BINARY_HPP_
|
||||
#define CEREAL_ARCHIVES_BINARY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace cereal
|
||||
@@ -43,6 +43,10 @@ namespace cereal
|
||||
and loaded data is the same. If you need to have portability over
|
||||
architectures with different endianness, use PortableBinaryOutputArchive.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\ingroup Archives */
|
||||
class BinaryOutputArchive : public OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
@@ -53,12 +57,14 @@ namespace cereal
|
||||
BinaryOutputArchive(std::ostream & stream) :
|
||||
OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream)
|
||||
{ }
|
||||
{ }
|
||||
|
||||
~BinaryOutputArchive() CEREAL_NOEXCEPT = default;
|
||||
|
||||
//! Writes size bytes of data to the output stream
|
||||
void saveBinary( const void * data, size_t size )
|
||||
void saveBinary( const void * data, std::streamsize size )
|
||||
{
|
||||
size_t const writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
|
||||
auto const writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
|
||||
|
||||
if(writtenSize != size)
|
||||
throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
|
||||
@@ -74,6 +80,10 @@ namespace cereal
|
||||
and loaded data is the same. If you need to have portability over
|
||||
architectures with different endianness, use PortableBinaryOutputArchive.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\ingroup Archives */
|
||||
class BinaryInputArchive : public InputArchive<BinaryInputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
@@ -82,12 +92,14 @@ namespace cereal
|
||||
BinaryInputArchive(std::istream & stream) :
|
||||
InputArchive<BinaryInputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream)
|
||||
{ }
|
||||
{ }
|
||||
|
||||
~BinaryInputArchive() CEREAL_NOEXCEPT = default;
|
||||
|
||||
//! Reads size bytes of data from the input stream
|
||||
void loadBinary( void * const data, size_t size )
|
||||
void loadBinary( void * const data, std::streamsize size )
|
||||
{
|
||||
size_t const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
|
||||
auto const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
|
||||
|
||||
if(readSize != size)
|
||||
throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
|
||||
@@ -103,7 +115,7 @@ namespace cereal
|
||||
//! Saving for POD types to binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
save(BinaryOutputArchive & ar, T const & t)
|
||||
CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, T const & t)
|
||||
{
|
||||
ar.saveBinary(std::addressof(t), sizeof(t));
|
||||
}
|
||||
@@ -111,7 +123,7 @@ namespace cereal
|
||||
//! Loading for POD types from binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
load(BinaryInputArchive & ar, T & t)
|
||||
CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, T & t)
|
||||
{
|
||||
ar.loadBinary(std::addressof(t), sizeof(t));
|
||||
}
|
||||
@@ -119,7 +131,7 @@ namespace cereal
|
||||
//! Serializing NVP types to binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
|
||||
serialize( Archive & ar, NameValuePair<T> & t )
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar( t.value );
|
||||
}
|
||||
@@ -127,28 +139,31 @@ namespace cereal
|
||||
//! Serializing SizeTags to binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
|
||||
serialize( Archive & ar, SizeTag<T> & t )
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
|
||||
{
|
||||
ar( t.size );
|
||||
}
|
||||
|
||||
//! Saving binary data
|
||||
template <class T> inline
|
||||
void save(BinaryOutputArchive & ar, BinaryData<T> const & bd)
|
||||
void CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, BinaryData<T> const & bd)
|
||||
{
|
||||
ar.saveBinary(bd.data, bd.size);
|
||||
ar.saveBinary( bd.data, static_cast<std::streamsize>( bd.size ) );
|
||||
}
|
||||
|
||||
//! Loading binary data
|
||||
template <class T> inline
|
||||
void load(BinaryInputArchive & ar, BinaryData<T> & bd)
|
||||
void CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, BinaryData<T> & bd)
|
||||
{
|
||||
ar.loadBinary(bd.data, bd.size);
|
||||
ar.loadBinary(bd.data, static_cast<std::streamsize>( bd.size ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive);
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive);
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::BinaryInputArchive, cereal::BinaryOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_BINARY_HPP_
|
||||
|
||||
+686
-249
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*! \file binary.hpp
|
||||
\brief Binary input and output archives */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,7 +29,7 @@
|
||||
#ifndef CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
||||
#define CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
|
||||
@@ -39,20 +39,20 @@ namespace cereal
|
||||
{
|
||||
//! Returns true if the current machine is little endian
|
||||
/*! @ingroup Internal */
|
||||
inline bool is_little_endian()
|
||||
inline std::uint8_t is_little_endian()
|
||||
{
|
||||
static std::int32_t test = 1;
|
||||
return *reinterpret_cast<std::int8_t*>( &test );
|
||||
return *reinterpret_cast<std::int8_t*>( &test ) == 1;
|
||||
}
|
||||
|
||||
//! Swaps the order of bytes for some chunk of memory
|
||||
/*! @param data The data as a uint8_t pointer
|
||||
@tparam DataSize The true size of the data
|
||||
@ingroup Internal */
|
||||
template <size_t DataSize>
|
||||
template <std::size_t DataSize>
|
||||
inline void swap_bytes( std::uint8_t * data )
|
||||
{
|
||||
for( size_t i = 0, end = DataSize / 2; i < end; ++i )
|
||||
for( std::size_t i = 0, end = DataSize / 2; i < end; ++i )
|
||||
std::swap( data[i], data[DataSize - i - 1] );
|
||||
}
|
||||
} // end namespace portable_binary_detail
|
||||
@@ -62,10 +62,14 @@ namespace cereal
|
||||
/*! This archive outputs data to a stream in an extremely compact binary
|
||||
representation with as little extra metadata as possible.
|
||||
|
||||
This archive will record the endianness of the data and assuming that
|
||||
the user takes care of ensuring serialized types are the same size
|
||||
This archive will record the endianness of the data as well as the desired in/out endianness
|
||||
and assuming that the user takes care of ensuring serialized types are the same size
|
||||
across machines, is portable over different architectures.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\warning This archive has not been thoroughly tested across different architectures.
|
||||
Please report any issues, optimizations, or feature requests at
|
||||
<a href="www.github.com/USCiLab/cereal">the project github</a>.
|
||||
@@ -74,20 +78,69 @@ namespace cereal
|
||||
class PortableBinaryOutputArchive : public OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
public:
|
||||
//! A class containing various advanced options for the PortableBinaryOutput archive
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
//! Represents desired endianness
|
||||
enum class Endianness : std::uint8_t
|
||||
{ big, little };
|
||||
|
||||
//! Default options, preserve system endianness
|
||||
static Options Default(){ return Options(); }
|
||||
|
||||
//! Save as little endian
|
||||
static Options LittleEndian(){ return Options( Endianness::little ); }
|
||||
|
||||
//! Save as big endian
|
||||
static Options BigEndian(){ return Options( Endianness::big ); }
|
||||
|
||||
//! Specify specific options for the PortableBinaryOutputArchive
|
||||
/*! @param outputEndian The desired endianness of saved (output) data */
|
||||
explicit Options( Endianness outputEndian = getEndianness() ) :
|
||||
itsOutputEndianness( outputEndian ) { }
|
||||
|
||||
private:
|
||||
//! Gets the endianness of the system
|
||||
inline static Endianness getEndianness()
|
||||
{ return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
|
||||
|
||||
//! Checks if Options is set for little endian
|
||||
inline std::uint8_t is_little_endian() const
|
||||
{ return itsOutputEndianness == Endianness::little; }
|
||||
|
||||
friend class PortableBinaryOutputArchive;
|
||||
Endianness itsOutputEndianness;
|
||||
};
|
||||
|
||||
//! Construct, outputting to the provided stream
|
||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||
even cout! */
|
||||
PortableBinaryOutputArchive(std::ostream & stream) :
|
||||
/*! @param stream The stream to output to. Should be opened with std::ios::binary flag.
|
||||
@param options The PortableBinary specific options to use. See the Options struct
|
||||
for the values of default parameters */
|
||||
PortableBinaryOutputArchive(std::ostream & stream, Options const & options = Options::Default()) :
|
||||
OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream)
|
||||
{
|
||||
this->operator()( portable_binary_detail::is_little_endian() );
|
||||
}
|
||||
itsStream(stream),
|
||||
itsConvertEndianness( portable_binary_detail::is_little_endian() ^ options.is_little_endian() )
|
||||
{
|
||||
this->operator()( options.is_little_endian() );
|
||||
}
|
||||
|
||||
~PortableBinaryOutputArchive() CEREAL_NOEXCEPT = default;
|
||||
|
||||
//! Writes size bytes of data to the output stream
|
||||
void saveBinary( const void * data, size_t size )
|
||||
template <std::streamsize DataSize> inline
|
||||
void saveBinary( const void * data, std::streamsize size )
|
||||
{
|
||||
size_t const writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
|
||||
std::streamsize writtenSize = 0;
|
||||
|
||||
if( itsConvertEndianness )
|
||||
{
|
||||
for( std::streamsize i = 0; i < size; i += DataSize )
|
||||
for( std::streamsize j = 0; j < DataSize; ++j )
|
||||
writtenSize += itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ) + DataSize - j - 1 + i, 1 );
|
||||
}
|
||||
else
|
||||
writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
|
||||
|
||||
if(writtenSize != size)
|
||||
throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
|
||||
@@ -95,6 +148,7 @@ namespace cereal
|
||||
|
||||
private:
|
||||
std::ostream & itsStream;
|
||||
const uint8_t itsConvertEndianness; //!< If set to true, we will need to swap bytes upon saving
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
@@ -114,6 +168,10 @@ namespace cereal
|
||||
The archive will do nothing to ensure types are the same size - that is
|
||||
the responsibility of the user.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\warning This archive has not been thoroughly tested across different architectures.
|
||||
Please report any issues, optimizations, or feature requests at
|
||||
<a href="www.github.com/USCiLab/cereal">the project github</a>.
|
||||
@@ -122,27 +180,66 @@ namespace cereal
|
||||
class PortableBinaryInputArchive : public InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>
|
||||
{
|
||||
public:
|
||||
//! A class containing various advanced options for the PortableBinaryInput archive
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
//! Represents desired endianness
|
||||
enum class Endianness : std::uint8_t
|
||||
{ big, little };
|
||||
|
||||
//! Default options, preserve system endianness
|
||||
static Options Default(){ return Options(); }
|
||||
|
||||
//! Load into little endian
|
||||
static Options LittleEndian(){ return Options( Endianness::little ); }
|
||||
|
||||
//! Load into big endian
|
||||
static Options BigEndian(){ return Options( Endianness::big ); }
|
||||
|
||||
//! Specify specific options for the PortableBinaryInputArchive
|
||||
/*! @param inputEndian The desired endianness of loaded (input) data */
|
||||
explicit Options( Endianness inputEndian = getEndianness() ) :
|
||||
itsInputEndianness( inputEndian ) { }
|
||||
|
||||
private:
|
||||
//! Gets the endianness of the system
|
||||
inline static Endianness getEndianness()
|
||||
{ return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
|
||||
|
||||
//! Checks if Options is set for little endian
|
||||
inline std::uint8_t is_little_endian() const
|
||||
{ return itsInputEndianness == Endianness::little; }
|
||||
|
||||
friend class PortableBinaryInputArchive;
|
||||
Endianness itsInputEndianness;
|
||||
};
|
||||
|
||||
//! Construct, loading from the provided stream
|
||||
/*! @param stream The stream to read from. */
|
||||
PortableBinaryInputArchive(std::istream & stream) :
|
||||
/*! @param stream The stream to read from. Should be opened with std::ios::binary flag.
|
||||
@param options The PortableBinary specific options to use. See the Options struct
|
||||
for the values of default parameters */
|
||||
PortableBinaryInputArchive(std::istream & stream, Options const & options = Options::Default()) :
|
||||
InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream),
|
||||
itsConvertEndianness( false )
|
||||
{
|
||||
bool streamLittleEndian;
|
||||
uint8_t streamLittleEndian;
|
||||
this->operator()( streamLittleEndian );
|
||||
itsConvertEndianness = portable_binary_detail::is_little_endian() ^ streamLittleEndian;
|
||||
itsConvertEndianness = options.is_little_endian() ^ streamLittleEndian;
|
||||
}
|
||||
|
||||
~PortableBinaryInputArchive() CEREAL_NOEXCEPT = default;
|
||||
|
||||
//! Reads size bytes of data from the input stream
|
||||
/*! @param data The data to save
|
||||
@param size The number of bytes in the data
|
||||
@tparam DataSize T The size of the actual type of the data elements being loaded */
|
||||
template <size_t DataSize>
|
||||
void loadBinary( void * const data, size_t size )
|
||||
template <std::streamsize DataSize> inline
|
||||
void loadBinary( void * const data, std::streamsize size )
|
||||
{
|
||||
// load data
|
||||
size_t const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
|
||||
auto const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
|
||||
|
||||
if(readSize != size)
|
||||
throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
|
||||
@@ -151,14 +248,14 @@ namespace cereal
|
||||
if( itsConvertEndianness )
|
||||
{
|
||||
std::uint8_t * ptr = reinterpret_cast<std::uint8_t*>( data );
|
||||
for( size_t i = 0; i < size; i += DataSize )
|
||||
portable_binary_detail::swap_bytes<DataSize>( ptr );
|
||||
for( std::streamsize i = 0; i < size; i += DataSize )
|
||||
portable_binary_detail::swap_bytes<DataSize>( ptr + i );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::istream & itsStream;
|
||||
bool itsConvertEndianness; //!< If set to true, we will need to swap bytes upon loading
|
||||
uint8_t itsConvertEndianness; //!< If set to true, we will need to swap bytes upon loading
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
@@ -167,18 +264,18 @@ namespace cereal
|
||||
//! Saving for POD types to portable binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
save(PortableBinaryOutputArchive & ar, T const & t)
|
||||
CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, T const & t)
|
||||
{
|
||||
static_assert( !std::is_floating_point<T>::value ||
|
||||
(std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
|
||||
"Portable binary only supports IEEE 754 standardized floating point" );
|
||||
ar.saveBinary(std::addressof(t), sizeof(t));
|
||||
ar.template saveBinary<sizeof(T)>(std::addressof(t), sizeof(t));
|
||||
}
|
||||
|
||||
//! Loading for POD types from portable binary
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
load(PortableBinaryInputArchive & ar, T & t)
|
||||
CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, T & t)
|
||||
{
|
||||
static_assert( !std::is_floating_point<T>::value ||
|
||||
(std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
|
||||
@@ -189,7 +286,7 @@ namespace cereal
|
||||
//! Serializing NVP types to portable binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
|
||||
serialize( Archive & ar, NameValuePair<T> & t )
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar( t.value );
|
||||
}
|
||||
@@ -197,38 +294,41 @@ namespace cereal
|
||||
//! Serializing SizeTags to portable binary
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
|
||||
serialize( Archive & ar, SizeTag<T> & t )
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
|
||||
{
|
||||
ar( t.size );
|
||||
}
|
||||
|
||||
//! Saving binary data to portable binary
|
||||
template <class T> inline
|
||||
void save(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
|
||||
void CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
|
||||
{
|
||||
typedef typename std::remove_pointer<T>::type TT;
|
||||
static_assert( !std::is_floating_point<TT>::value ||
|
||||
(std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
|
||||
"Portable binary only supports IEEE 754 standardized floating point" );
|
||||
|
||||
ar.saveBinary(bd.data, bd.size);
|
||||
ar.template saveBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
|
||||
}
|
||||
|
||||
//! Loading binary data from portable binary
|
||||
template <class T> inline
|
||||
void load(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
|
||||
void CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
|
||||
{
|
||||
typedef typename std::remove_pointer<T>::type TT;
|
||||
static_assert( !std::is_floating_point<TT>::value ||
|
||||
(std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
|
||||
"Portable binary only supports IEEE 754 standardized floating point" );
|
||||
|
||||
ar.template loadBinary<sizeof(TT)>(bd.data, bd.size);
|
||||
ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive);
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive);
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
||||
|
||||
+513
-187
@@ -1,7 +1,7 @@
|
||||
/*! \file xml.hpp
|
||||
\brief XML input and output archives */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,31 +28,47 @@
|
||||
*/
|
||||
#ifndef CEREAL_ARCHIVES_XML_HPP_
|
||||
#define CEREAL_ARCHIVES_XML_HPP_
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/details/util.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/details/util.hpp"
|
||||
|
||||
#include <cereal/external/rapidxml/rapidxml.hpp>
|
||||
#include <cereal/external/rapidxml/rapidxml_print.hpp>
|
||||
#include <cereal/external/base64.hpp>
|
||||
#include "cereal/external/rapidxml/rapidxml.hpp"
|
||||
#include "cereal/external/rapidxml/rapidxml_print.hpp"
|
||||
#include "cereal/external/base64.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace xml_detail
|
||||
{
|
||||
static const char * CEREAL_XML_STRING = "cereal";
|
||||
#ifndef CEREAL_XML_STRING_VALUE
|
||||
//! The default name for the root node in a cereal xml archive.
|
||||
/*! You can define CEREAL_XML_STRING_VALUE to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_XML_STRING_VALUE "cereal"
|
||||
#endif // CEREAL_XML_STRING_VALUE
|
||||
|
||||
//! The name given to the root node in a cereal xml archive
|
||||
static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
|
||||
|
||||
//! Returns true if the character is whitespace
|
||||
inline bool isWhitespace( char c )
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
|
||||
}
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! An output archive designed to save data to XML
|
||||
/*! This archive uses RapidXML to build an in memory XML tree of the
|
||||
data it serializes before outputting it to its stream upon destruction.
|
||||
The envisioned way of using this archive is in an RAII fashion, letting
|
||||
This archive should be used in an RAII fashion, letting
|
||||
the automatic destruction of the object cause the flush to its stream.
|
||||
|
||||
XML archives provides a human readable output but at decreased
|
||||
@@ -77,20 +93,79 @@ namespace cereal
|
||||
is accomplished through the cereal::SizeTag object, which will also add an attribute
|
||||
to its parent field.
|
||||
\ingroup Archives */
|
||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>
|
||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
|
||||
{
|
||||
public:
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an XMLOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! A class containing various advanced options for the XML archive
|
||||
/*! Options can either be directly passed to the constructor, or chained using the
|
||||
modifier functions for an interface analogous to named parameters */
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
//! Default options
|
||||
static Options Default(){ return Options(); }
|
||||
|
||||
//! Specify specific options for the XMLOutputArchive
|
||||
/*! @param precision_ The precision used for floating point numbers
|
||||
@param indent_ Whether to indent each line of XML
|
||||
@param outputType_ Whether to output the type of each serialized object as an attribute
|
||||
@param sizeAttributes_ Whether dynamically sized containers output the size=dynamic attribute */
|
||||
explicit Options( int precision_ = std::numeric_limits<double>::max_digits10,
|
||||
bool indent_ = true,
|
||||
bool outputType_ = false,
|
||||
bool sizeAttributes_ = true ) :
|
||||
itsPrecision( precision_ ),
|
||||
itsIndent( indent_ ),
|
||||
itsOutputType( outputType_ ),
|
||||
itsSizeAttributes( sizeAttributes_ )
|
||||
{ }
|
||||
|
||||
/*! @name Option Modifiers
|
||||
An interface for setting option settings analogous to named parameters.
|
||||
|
||||
@code{cpp}
|
||||
cereal::XMLOutputArchive ar( myStream,
|
||||
cereal::XMLOutputArchive::Options()
|
||||
.indent(true)
|
||||
.sizeAttributes(false) );
|
||||
@endcode
|
||||
*/
|
||||
//! @{
|
||||
|
||||
//! Sets the precision used for floaing point numbers
|
||||
Options & precision( int value ){ itsPrecision = value; return * this; }
|
||||
//! Whether to indent each line of XML
|
||||
Options & indent( bool enable ){ itsIndent = enable; return *this; }
|
||||
//! Whether to output the type of each serialized object as an attribute
|
||||
Options & outputType( bool enable ){ itsOutputType = enable; return *this; }
|
||||
//! Whether dynamically sized containers (e.g. vector) output the size=dynamic attribute
|
||||
Options & sizeAttributes( bool enable ){ itsSizeAttributes = enable; return *this; }
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
friend class XMLOutputArchive;
|
||||
int itsPrecision;
|
||||
bool itsIndent;
|
||||
bool itsOutputType;
|
||||
bool itsSizeAttributes;
|
||||
};
|
||||
|
||||
//! Construct, outputting to the provided stream upon destruction
|
||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||
even cout! Note that since this archive builds a tree in memory,
|
||||
it will not output to the stream until its destructor is called.
|
||||
@param precision The precision for floating point output. For input and output
|
||||
floating point to test equal, this should be at least 20
|
||||
@param outputType Controls whether type information will be printed in attributes */
|
||||
XMLOutputArchive(std::ostream & stream, size_t precision = 20, bool outputType = false ) :
|
||||
/*! @param stream The stream to output to. Note that XML is only guaranteed to flush
|
||||
its output to the stream upon destruction.
|
||||
@param options The XML specific options to use. See the Options struct
|
||||
for the values of default parameters */
|
||||
XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
|
||||
OutputArchive<XMLOutputArchive>(this),
|
||||
itsStream(stream),
|
||||
itsOutputType( outputType )
|
||||
itsOutputType( options.itsOutputType ),
|
||||
itsIndent( options.itsIndent ),
|
||||
itsSizeAttributes(options.itsSizeAttributes)
|
||||
{
|
||||
// rapidxml will delete all allocations when xml_document is cleared
|
||||
auto node = itsXML.allocate_node( rapidxml::node_declaration );
|
||||
@@ -105,21 +180,48 @@ namespace cereal
|
||||
|
||||
// set attributes on the streams
|
||||
itsStream << std::boolalpha;
|
||||
itsStream.precision( precision );
|
||||
itsStream.precision( options.itsPrecision );
|
||||
itsOS << std::boolalpha;
|
||||
itsOS.precision( precision );
|
||||
itsOS.precision( options.itsPrecision );
|
||||
}
|
||||
|
||||
//! Destructor, flushes the XML
|
||||
~XMLOutputArchive()
|
||||
~XMLOutputArchive() CEREAL_NOEXCEPT
|
||||
{
|
||||
itsStream << itsXML;
|
||||
const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
|
||||
rapidxml::print( itsStream, itsXML, flags );
|
||||
itsXML.clear();
|
||||
}
|
||||
|
||||
//! Saves some binary data, encoded as a base64 string, with an optional name
|
||||
/*! This can be called directly by users and it will automatically create a child node for
|
||||
the current XML node, populate it with a base64 encoded string, and optionally name
|
||||
it. The node will be finished after it has been populated. */
|
||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
itsNodes.top().name = name;
|
||||
|
||||
startNode();
|
||||
|
||||
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
|
||||
saveValue( base64string );
|
||||
|
||||
if( itsOutputType )
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
|
||||
|
||||
finishNode();
|
||||
}
|
||||
|
||||
//! @}
|
||||
/*! @name Internal Functionality
|
||||
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||
the XMLOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! Creates a new node that is a child of the node at the top of the stack
|
||||
/*! Nodes will be given a name that has either been pre-set by a name value pair,
|
||||
or generated based upon a counter unique to the parent node.
|
||||
or generated based upon a counter unique to the parent node. If you want to
|
||||
give a node a specific name, use setNextName prior to calling startNode.
|
||||
|
||||
The node will then be pushed onto the node stack. */
|
||||
void startNode()
|
||||
@@ -128,7 +230,7 @@ namespace cereal
|
||||
const auto nameString = itsNodes.top().getValueName();
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
|
||||
|
||||
// insert into the XML
|
||||
auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
|
||||
@@ -148,18 +250,32 @@ namespace cereal
|
||||
itsNodes.top().name = name;
|
||||
}
|
||||
|
||||
//! Saves some data, encoded as a string
|
||||
//! Saves some data, encoded as a string, into the current top level node
|
||||
/*! The data will be be named with the most recent name if one exists,
|
||||
otherwise it will be given some default delimited value that depends upon
|
||||
the parent node */
|
||||
template <class T> inline
|
||||
void saveValue( T const & value )
|
||||
{
|
||||
itsOS.clear(); itsOS.seekp(0);
|
||||
itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
|
||||
itsOS << value << std::ends;
|
||||
|
||||
auto strValue = itsOS.str();
|
||||
|
||||
// itsOS.str() may contain data from previous calls after the first '\0' that was just inserted
|
||||
// and this data is counted in the length call. We make sure to remove that section so that the
|
||||
// whitespace validation is done properly
|
||||
strValue.resize(std::strlen(strValue.c_str()));
|
||||
|
||||
// If the first or last character is a whitespace, add xml:space attribute
|
||||
const auto len = strValue.length();
|
||||
if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
|
||||
{
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
|
||||
}
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
|
||||
auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
|
||||
|
||||
// insert into the XML
|
||||
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
|
||||
@@ -177,25 +293,7 @@ namespace cereal
|
||||
saveValue( static_cast<int32_t>( value ) );
|
||||
}
|
||||
|
||||
//! Saves some binary data, encoded as a base64 string, with an optional name
|
||||
/*! This will create a new node, optionally named, and insert a value that consists of
|
||||
the data encoded as a base64 string */
|
||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
itsNodes.top().name = name;
|
||||
|
||||
startNode();
|
||||
|
||||
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
|
||||
saveValue( base64string );
|
||||
|
||||
if( itsOutputType )
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
|
||||
|
||||
finishNode();
|
||||
};
|
||||
|
||||
//! Causes the type to be appended to the most recently made node if output type is set to true
|
||||
//! Causes the type to be appended as an attribute to the most recently made node if output type is set to true
|
||||
template <class T> inline
|
||||
void insertType()
|
||||
{
|
||||
@@ -206,7 +304,7 @@ namespace cereal
|
||||
const auto nameString = util::demangledName<T>();
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
|
||||
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
|
||||
}
|
||||
@@ -219,6 +317,8 @@ namespace cereal
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
|
||||
}
|
||||
|
||||
bool hasSizeAttributes() const { return itsSizeAttributes; }
|
||||
|
||||
protected:
|
||||
//! A struct that contains metadata about a node
|
||||
struct NodeInfo
|
||||
@@ -251,12 +351,16 @@ namespace cereal
|
||||
}
|
||||
}; // NodeInfo
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
std::ostream & itsStream; //!< The output stream
|
||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||
std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document
|
||||
std::ostringstream itsOS; //!< Used to format strings internally
|
||||
bool itsOutputType; //!< Controls whether type information is printed
|
||||
bool itsIndent; //!< Controls whether indenting is used
|
||||
bool itsSizeAttributes; //!< Controls whether lists have a size attribute
|
||||
}; // XMLOutputArchive
|
||||
|
||||
// ######################################################################
|
||||
@@ -264,14 +368,47 @@ namespace cereal
|
||||
/*! This archive uses RapidXML to build an in memory XML tree of the
|
||||
data in the stream it is given before loading any types serialized.
|
||||
|
||||
As with the output XML archive, the preferred way to use this archive is in
|
||||
an RAII fashion, ensuring its destruction after all data has been read.
|
||||
|
||||
Input XML should have been produced by the XMLOutputArchive. Data can
|
||||
only be added to dynamically sized containers - the input archive will
|
||||
determine their size by looking at the number of child nodes.
|
||||
determine their size by looking at the number of child nodes. Data that
|
||||
did not originate from an XMLOutputArchive is not officially supported,
|
||||
but may be possible to use if properly formatted.
|
||||
|
||||
The XMLInputArchive does not require that nodes are loaded in the same
|
||||
order they were saved by XMLOutputArchive. Using name value pairs (NVPs),
|
||||
it is possible to load in an out of order fashion or otherwise skip/select
|
||||
specific nodes to load.
|
||||
|
||||
The default behavior of the input archive is to read sequentially starting
|
||||
with the first node and exploring its children. When a given NVP does
|
||||
not match the read in name for a node, the archive will search for that
|
||||
node at the current level and load it if it exists. After loading an out of
|
||||
order node, the archive will then proceed back to loading sequentially from
|
||||
its new position.
|
||||
|
||||
Consider this simple example where loading of some data is skipped:
|
||||
|
||||
@code{cpp}
|
||||
// imagine the input file has someData(1-9) saved in order at the top level node
|
||||
ar( someData1, someData2, someData3 ); // XML loads in the order it sees in the file
|
||||
ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
|
||||
// match expected NVP name, so we search
|
||||
// for the given NVP and load that value
|
||||
ar( someData7, someData8, someData9 ); // with no NVP given, loading resumes at its
|
||||
// current location, proceeding sequentially
|
||||
@endcode
|
||||
|
||||
\ingroup Archives */
|
||||
class XMLInputArchive : public InputArchive<XMLInputArchive>
|
||||
class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
|
||||
{
|
||||
public:
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an XMLInputArchive */
|
||||
//! @{
|
||||
|
||||
//! Construct, reading in from the provided stream
|
||||
/*! Reads in an entire XML document from some stream and parses it as soon
|
||||
as serialization starts
|
||||
@@ -284,9 +421,9 @@ namespace cereal
|
||||
try
|
||||
{
|
||||
itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
|
||||
itsXML.parse<rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
|
||||
itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
|
||||
}
|
||||
catch( rapidxml::parse_error const & e )
|
||||
catch( rapidxml::parse_error const & )
|
||||
{
|
||||
//std::cerr << "-----Original-----" << std::endl;
|
||||
//stream.seekg(0);
|
||||
@@ -306,104 +443,17 @@ namespace cereal
|
||||
itsNodes.emplace( root );
|
||||
}
|
||||
|
||||
//! Prepares to start reading the next node
|
||||
void startNode()
|
||||
{
|
||||
itsNodes.emplace( itsNodes.top().child );
|
||||
}
|
||||
|
||||
//! Finishes reading the current node
|
||||
void finishNode()
|
||||
{
|
||||
// remove current
|
||||
itsNodes.pop();
|
||||
|
||||
// advance parent
|
||||
itsNodes.top().advance();
|
||||
}
|
||||
|
||||
//! Loads a bool
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_unsigned<T>::value && std::is_same<T, bool>::value, void>::type
|
||||
loadValue( T & value )
|
||||
{
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is.setf( std::ios::boolalpha );
|
||||
is >> value;
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an unsigned long
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_unsigned<T>::value && !std::is_same<T, bool>::value && sizeof(T) < sizeof(long long), void>::type
|
||||
loadValue( T & value )
|
||||
{
|
||||
value = std::stoul( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an unsigned long long
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_unsigned<T>::value && !std::is_same<T, bool>::value && sizeof(T) >= sizeof(long long), void>::type
|
||||
loadValue( T & value )
|
||||
{
|
||||
value = std::stoull( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an int
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_signed<T>::value && sizeof(T) <= sizeof(int), void>::type
|
||||
loadValue( T & value )
|
||||
{
|
||||
value = std::stoi( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_signed<T>::value && (sizeof(T) > sizeof(int)) && (sizeof(T) <= sizeof(long)), void>::type
|
||||
loadValue( T & value )
|
||||
{
|
||||
value = std::stol( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long long
|
||||
template <class T> inline
|
||||
typename std::enable_if<std::is_signed<T>::value && (sizeof(T) > sizeof(long)) && (sizeof(T) <= sizeof(long long)), void>::type
|
||||
loadValue( T & value )
|
||||
{
|
||||
value = std::stoll( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a float
|
||||
void loadValue( float & value )
|
||||
{
|
||||
value = std::stof( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a double
|
||||
void loadValue( double & value )
|
||||
{
|
||||
value = std::stod( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long double
|
||||
void loadValue( long double & value )
|
||||
{
|
||||
value = std::stold( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Loads a string from the current node
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
|
||||
{
|
||||
std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
|
||||
|
||||
str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
|
||||
std::istreambuf_iterator<CharT, Traits>() );
|
||||
}
|
||||
|
||||
//! Loads some binary data, encoded as a base64 string
|
||||
/*! This will automatically start and finish a node to load the data */
|
||||
void loadBinaryValue( void * data, size_t size )
|
||||
~XMLInputArchive() CEREAL_NOEXCEPT = default;
|
||||
|
||||
//! Loads some binary data, encoded as a base64 string, optionally specified by some name
|
||||
/*! This will automatically start and finish a node to load the data, and can be called directly by
|
||||
users.
|
||||
|
||||
Note that this follows the same ordering rules specified in the class description in regards
|
||||
to loading in/out of order */
|
||||
void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
setNextName( name );
|
||||
startNode();
|
||||
|
||||
std::string encoded;
|
||||
@@ -417,15 +467,216 @@ namespace cereal
|
||||
std::memcpy( data, decoded.data(), decoded.size() );
|
||||
|
||||
finishNode();
|
||||
};
|
||||
}
|
||||
|
||||
//! Loads the size of the current node
|
||||
//! @}
|
||||
/*! @name Internal Functionality
|
||||
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||
the XMLInputArchive */
|
||||
//! @{
|
||||
|
||||
//! Prepares to start reading the next node
|
||||
/*! This places the next node to be parsed onto the nodes stack.
|
||||
|
||||
By default our strategy is to start with the document root node and then
|
||||
recursively iterate through all children in the order they show up in the document.
|
||||
We don't need to know NVPs do to this; we'll just blindly load in the order things appear in.
|
||||
|
||||
We check to see if the specified NVP matches what the next automatically loaded node is. If they
|
||||
match, we just continue as normal, going in order. If they don't match, we attempt to find a node
|
||||
named after the NVP that is being loaded. If that NVP does not exist, we throw an exception. */
|
||||
void startNode()
|
||||
{
|
||||
auto next = itsNodes.top().child; // By default we would move to the next child node
|
||||
auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
|
||||
|
||||
// If we were given an NVP name, look for it in the current level of the document.
|
||||
// We only need to do this if either we have exhausted the siblings of the current level or
|
||||
// the NVP name does not match the name of the node we would normally read next
|
||||
if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
|
||||
{
|
||||
next = itsNodes.top().search( expectedName );
|
||||
|
||||
if( next == nullptr )
|
||||
throw Exception("XML Parsing failed - provided NVP (" + std::string(expectedName) + ") not found");
|
||||
}
|
||||
|
||||
itsNodes.emplace( next );
|
||||
}
|
||||
|
||||
//! Finishes reading the current node
|
||||
void finishNode()
|
||||
{
|
||||
// remove current
|
||||
itsNodes.pop();
|
||||
|
||||
// advance parent
|
||||
itsNodes.top().advance();
|
||||
|
||||
// Reset name
|
||||
itsNodes.top().name = nullptr;
|
||||
}
|
||||
|
||||
//! Retrieves the current node name
|
||||
//! will return @c nullptr if the node does not have a name
|
||||
const char * getNodeName() const
|
||||
{
|
||||
return itsNodes.top().getChildName();
|
||||
}
|
||||
|
||||
//! Sets the name for the next node created with startNode
|
||||
void setNextName( const char * name )
|
||||
{
|
||||
itsNodes.top().name = name;
|
||||
}
|
||||
|
||||
//! Loads a bool from the current top node
|
||||
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
|
||||
std::is_same<T, bool>::value> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is.setf( std::ios::boolalpha );
|
||||
is >> value;
|
||||
}
|
||||
|
||||
//! Loads a char (signed or unsigned) from the current top node
|
||||
template <class T, traits::EnableIf<std::is_integral<T>::value,
|
||||
!std::is_same<T, bool>::value,
|
||||
sizeof(T) == sizeof(char)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
|
||||
}
|
||||
|
||||
//! Load an int8_t from the current top node (ensures we parse entire number)
|
||||
void loadValue( int8_t & value )
|
||||
{
|
||||
int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
|
||||
}
|
||||
|
||||
//! Load a uint8_t from the current top node (ensures we parse entire number)
|
||||
void loadValue( uint8_t & value )
|
||||
{
|
||||
uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an unsigned long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
|
||||
!std::is_same<T, bool>::value,
|
||||
!std::is_same<T, char>::value,
|
||||
!std::is_same<T, unsigned char>::value,
|
||||
sizeof(T) < sizeof(long long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an unsigned long long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
|
||||
!std::is_same<T, bool>::value,
|
||||
sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as an int from the current top node
|
||||
template <class T, traits::EnableIf<std::is_signed<T>::value,
|
||||
!std::is_same<T, char>::value,
|
||||
sizeof(T) <= sizeof(int)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_signed<T>::value,
|
||||
(sizeof(T) > sizeof(int)),
|
||||
sizeof(T) <= sizeof(long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long long from the current top node
|
||||
template <class T, traits::EnableIf<std::is_signed<T>::value,
|
||||
(sizeof(T) > sizeof(long)),
|
||||
sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a float from the current top node
|
||||
void loadValue( float & value )
|
||||
{
|
||||
try
|
||||
{
|
||||
value = std::stof( itsNodes.top().node->value() );
|
||||
}
|
||||
catch( std::out_of_range const & )
|
||||
{
|
||||
// special case for denormalized values
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is >> value;
|
||||
if( std::fpclassify( value ) != FP_SUBNORMAL )
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a double from the current top node
|
||||
void loadValue( double & value )
|
||||
{
|
||||
try
|
||||
{
|
||||
value = std::stod( itsNodes.top().node->value() );
|
||||
}
|
||||
catch( std::out_of_range const & )
|
||||
{
|
||||
// special case for denormalized values
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is >> value;
|
||||
if( std::fpclassify( value ) != FP_SUBNORMAL )
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//! Loads a type best represented as a long double from the current top node
|
||||
void loadValue( long double & value )
|
||||
{
|
||||
try
|
||||
{
|
||||
value = std::stold( itsNodes.top().node->value() );
|
||||
}
|
||||
catch( std::out_of_range const & )
|
||||
{
|
||||
// special case for denormalized values
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is >> value;
|
||||
if( std::fpclassify( value ) != FP_SUBNORMAL )
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//! Loads a string from the current node from the current top node
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
|
||||
{
|
||||
std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
|
||||
|
||||
str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
|
||||
std::istreambuf_iterator<CharT, Traits>() );
|
||||
}
|
||||
|
||||
//! Loads the size of the current top node
|
||||
template <class T> inline
|
||||
void loadSize( T & value )
|
||||
{
|
||||
value = getNumChildren( itsNodes.top().node );
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Gets the number of children (usually interpreted as size) for the specified node
|
||||
static size_t getNumChildren( rapidxml::xml_node<> * node )
|
||||
{
|
||||
@@ -441,7 +692,6 @@ namespace cereal
|
||||
return size;
|
||||
}
|
||||
|
||||
protected:
|
||||
//! A struct that contains metadata about a node
|
||||
/*! Keeps track of some top level node, its number of
|
||||
remaining children, and the current active child node */
|
||||
@@ -449,24 +699,62 @@ namespace cereal
|
||||
{
|
||||
NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
|
||||
node( n ),
|
||||
child( n ? n->first_node() : nullptr ),
|
||||
size( XMLInputArchive::getNumChildren( n ) )
|
||||
child( n->first_node() ),
|
||||
size( XMLInputArchive::getNumChildren( n ) ),
|
||||
name( nullptr )
|
||||
{ }
|
||||
|
||||
//! Advances to the next sibling node of the child
|
||||
/*! If this is the last sibling child will be null after calling */
|
||||
void advance()
|
||||
{
|
||||
if( size )
|
||||
if( size > 0 )
|
||||
{
|
||||
--size;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
}
|
||||
|
||||
//! Searches for a child with the given name in this node
|
||||
/*! @param searchName The name to search for (must be null terminated)
|
||||
@return The node if found, nullptr otherwise */
|
||||
rapidxml::xml_node<> * search( const char * searchName )
|
||||
{
|
||||
if( searchName )
|
||||
{
|
||||
size_t new_size = XMLInputArchive::getNumChildren( node );
|
||||
const size_t name_size = rapidxml::internal::measure( searchName );
|
||||
|
||||
for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
|
||||
{
|
||||
if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
|
||||
{
|
||||
size = new_size;
|
||||
child = new_child;
|
||||
|
||||
return new_child;
|
||||
}
|
||||
--new_size;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//! Returns the actual name of the next child node, if it exists
|
||||
const char * getChildName() const
|
||||
{
|
||||
return child ? child->name() : nullptr;
|
||||
}
|
||||
|
||||
rapidxml::xml_node<> * node; //!< A pointer to this node
|
||||
rapidxml::xml_node<> * child; //!< A pointer to its current child
|
||||
size_t size;
|
||||
size_t size; //!< The remaining number of children for this node
|
||||
const char * name; //!< The NVP name for next child node
|
||||
}; // NodeInfo
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
std::vector<char> itsData; //!< The raw data loaded
|
||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||
@@ -480,79 +768,115 @@ namespace cereal
|
||||
// ######################################################################
|
||||
//! Prologue for NVPs for XML output archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void prologue( XMLOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Prologue for NVPs for XML input archives
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void prologue( XMLInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for NVPs for XML output archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for NVPs for XML input archives
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void epilogue( XMLInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for deferred data for XML archives
|
||||
/*! Do nothing for the defer wrapper */
|
||||
template <class T> inline
|
||||
void prologue( XMLOutputArchive &, DeferredData<T> const & )
|
||||
{ }
|
||||
|
||||
//! Prologue for deferred data for XML archives
|
||||
template <class T> inline
|
||||
void prologue( XMLInputArchive &, DeferredData<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for deferred for XML archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T> inline
|
||||
void epilogue( XMLOutputArchive &, DeferredData<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for deferred for XML archives
|
||||
/*! Do nothing for the defer wrapper */
|
||||
template <class T> inline
|
||||
void epilogue( XMLInputArchive &, DeferredData<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for SizeTags for XML output archives
|
||||
/*! SizeTags do not start or finish nodes */
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
|
||||
{
|
||||
ar.appendAttribute( "size", "dynamic" );
|
||||
if (ar.hasSizeAttributes())
|
||||
{
|
||||
ar.appendAttribute("size", "dynamic");
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void prologue( XMLInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for SizeTags for XML output archives
|
||||
/*! SizeTags do not start or finish nodes */
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void epilogue( XMLOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
void epilogue( XMLInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for all other types for XML output archives
|
||||
//! Prologue for all other types for XML output archives (except minimal types)
|
||||
/*! Starts a new node, named either automatically or by some NVP,
|
||||
that may be given data by the type about to be archived */
|
||||
template <class T>
|
||||
that may be given data by the type about to be archived
|
||||
|
||||
Minimal types do not start or end nodes */
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
|
||||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
|
||||
void prologue( XMLOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
ar.insertType<T>();
|
||||
}
|
||||
|
||||
//! Prologue for all other types for XML input archives
|
||||
template <class T>
|
||||
//! Prologue for all other types for XML input archives (except minimal types)
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
|
||||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
|
||||
void prologue( XMLInputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for all other types other for XML output archives
|
||||
/*! Finishes the node created in the prologue */
|
||||
template <class T>
|
||||
//! Epilogue for all other types other for XML output archives (except minimal types)
|
||||
/*! Finishes the node created in the prologue
|
||||
|
||||
Minimal types do not start or end nodes */
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
|
||||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
|
||||
void epilogue( XMLOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
//! Epilogue for all other types other for XML output archives
|
||||
template <class T>
|
||||
//! Epilogue for all other types other for XML output archives (except minimal types)
|
||||
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
|
||||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
|
||||
void epilogue( XMLInputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
@@ -564,7 +888,7 @@ namespace cereal
|
||||
|
||||
//! Saving NVP types to XML
|
||||
template <class T> inline
|
||||
void save( XMLOutputArchive & ar, NameValuePair<T> const & t )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
|
||||
{
|
||||
ar.setNextName( t.name );
|
||||
ar( t.value );
|
||||
@@ -572,37 +896,36 @@ namespace cereal
|
||||
|
||||
//! Loading NVP types from XML
|
||||
template <class T> inline
|
||||
void load( XMLInputArchive & ar, NameValuePair<T> & t )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar.setNextName( t.name );
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Saving SizeTags to XML
|
||||
template <class T> inline
|
||||
void save( XMLOutputArchive &, SizeTag<T> const & )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Loading SizeTags from XML
|
||||
template <class T> inline
|
||||
void load( XMLInputArchive & ar, SizeTag<T> & st )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
|
||||
{
|
||||
ar.loadSize( st.size );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Saving for POD types to xml
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
save(XMLOutputArchive & ar, T const & t)
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
|
||||
{
|
||||
ar.saveValue( t );
|
||||
}
|
||||
|
||||
//! Loading for POD types from xml
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
load(XMLInputArchive & ar, T & t)
|
||||
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
|
||||
{
|
||||
ar.loadValue( t );
|
||||
}
|
||||
@@ -610,21 +933,24 @@ namespace cereal
|
||||
// ######################################################################
|
||||
//! saving string to xml
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
{
|
||||
ar.saveValue( str );
|
||||
}
|
||||
|
||||
//! loading string from xml
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void load(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
{
|
||||
ar.loadValue( str );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive);
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive);
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_XML_HPP_
|
||||
|
||||
+629
-120
@@ -1,7 +1,7 @@
|
||||
/*! \file cereal.hpp
|
||||
\brief Main cereal functionality */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,29 +29,24 @@
|
||||
#ifndef CEREAL_CEREAL_HPP_
|
||||
#define CEREAL_CEREAL_HPP_
|
||||
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
#include <cereal/details/traits.hpp>
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include <cereal/types/base_class.hpp>
|
||||
#include "cereal/macros.hpp"
|
||||
#include "cereal/details/traits.hpp"
|
||||
#include "cereal/details/helpers.hpp"
|
||||
#include "cereal/types/base_class.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! An exception class thrown when things go wrong at runtime
|
||||
/*! @ingroup Utility */
|
||||
struct Exception : public std::runtime_error
|
||||
{
|
||||
Exception( const std::string& what ) : std::runtime_error(what) {}
|
||||
Exception( const char* what ) : std::runtime_error(what) {}
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! Creates a name value pair
|
||||
/*! @relates NameValuePair
|
||||
@@ -97,12 +92,65 @@ namespace cereal
|
||||
|
||||
@relates SizeTag
|
||||
@ingroup Utility */
|
||||
template <class T>
|
||||
template <class T> inline
|
||||
SizeTag<T> make_size_tag( T && sz )
|
||||
{
|
||||
return {std::forward<T>(sz)};
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Marks data for deferred serialization
|
||||
/*! cereal performs a recursive depth-first traversal of data it serializes. When
|
||||
serializing smart pointers to large, nested, or cyclical data structures, it
|
||||
is possible to encounter a stack overflow from excessive recursion when following
|
||||
a chain of pointers.
|
||||
|
||||
Deferment can help in these situations if the data can be serialized separately from
|
||||
the pointers used to traverse the structure. For example, a graph structure can have its
|
||||
nodes serialized before its edges:
|
||||
|
||||
@code{.cpp}
|
||||
struct MyEdge
|
||||
{
|
||||
std::shared_ptr<MyNode> connection;
|
||||
int some_value;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
// when we serialize an edge, we'll defer serializing the associated node
|
||||
archive( cereal::defer( connection ),
|
||||
some_value );
|
||||
}
|
||||
};
|
||||
|
||||
struct MyGraphStructure
|
||||
{
|
||||
std::vector<MyEdge> edges;
|
||||
std::vector<MyNodes> nodes;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
// because of the deferment, we ensure all nodes are fully serialized
|
||||
// before any connection pointers to those nodes are serialized
|
||||
archive( edges, nodes );
|
||||
|
||||
// we have to explicitly inform the archive when it is safe to serialize
|
||||
// the deferred data
|
||||
archive.serializeDeferments();
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
@relates DeferredData
|
||||
@ingroup Utility */
|
||||
template <class T> inline
|
||||
DeferredData<T> defer( T && value )
|
||||
{
|
||||
return {std::forward<T>(value)};
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Called before a type is serialized to set up any special archive state
|
||||
//! for processing some type
|
||||
@@ -110,14 +158,14 @@ namespace cereal
|
||||
state or output extra information for a type, specialize this function
|
||||
for the archive type and the types that require the extra information.
|
||||
@ingroup Internal */
|
||||
template <class Archive, class T>
|
||||
template <class Archive, class T> inline
|
||||
void prologue( Archive & /* archive */, T const & /* data */)
|
||||
{ }
|
||||
|
||||
//! Called after a type is serialized to tear down any special archive state
|
||||
//! for processing some type
|
||||
/*! @ingroup Internal */
|
||||
template <class Archive, class T>
|
||||
template <class Archive, class T> inline
|
||||
void epilogue( Archive & /* archive */, T const & /* data */)
|
||||
{ }
|
||||
|
||||
@@ -127,7 +175,7 @@ namespace cereal
|
||||
This allows for empty classes to be serialized even if they do not provide
|
||||
a serialization function. Classes with no data members are considered to be
|
||||
empty. Be warned that if this is enabled and you attempt to serialize an
|
||||
empty class with improperly formed serialize or save/load functions, no
|
||||
empty class with improperly formed serialize or load/save functions, no
|
||||
static error will occur - the error will propogate silently and your
|
||||
intended serialization functions may not be called. You can manually
|
||||
ensure that your classes that have custom serialization are correct
|
||||
@@ -141,15 +189,93 @@ namespace cereal
|
||||
/*! This registration should be done once per archive. A good place to
|
||||
put this is immediately following the definition of your archive.
|
||||
Archive registration is only strictly necessary if you wish to
|
||||
support pointers to polymorphic data types
|
||||
support pointers to polymorphic data types. All archives that
|
||||
come with cereal are already registered.
|
||||
@ingroup Internal */
|
||||
#define CEREAL_REGISTER_ARCHIVE(Archive) \
|
||||
namespace cereal { namespace detail { \
|
||||
template <class T> \
|
||||
typename polymorphic_serialization_support<Archive, T>::type \
|
||||
instantiate_polymorphic_binding( T*, Archive*, adl_tag ); \
|
||||
#define CEREAL_REGISTER_ARCHIVE(Archive) \
|
||||
namespace cereal { namespace detail { \
|
||||
template <class T, class BindingTag> \
|
||||
typename polymorphic_serialization_support<Archive, T>::type \
|
||||
instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
|
||||
} } /* end namespaces */
|
||||
|
||||
//! Helper macro to omit unused warning
|
||||
#if defined(__GNUC__)
|
||||
// GCC / clang don't want the function
|
||||
#define CEREAL_UNUSED_FUNCTION
|
||||
#else
|
||||
#define CEREAL_UNUSED_FUNCTION static void unused() { (void)version; }
|
||||
#endif
|
||||
|
||||
// ######################################################################
|
||||
//! Defines a class version for some type
|
||||
/*! Versioning information is optional and adds some small amount of
|
||||
overhead to serialization. This overhead will occur both in terms of
|
||||
space in the archive (the version information for each class will be
|
||||
stored exactly once) as well as runtime (versioned serialization functions
|
||||
must check to see if they need to load or store version information).
|
||||
|
||||
Versioning is useful if you plan on fundamentally changing the way some
|
||||
type is serialized in the future. Versioned serialization functions
|
||||
cannot be used to load non-versioned data.
|
||||
|
||||
By default, all types have an assumed version value of zero. By
|
||||
using this macro, you may change the version number associated with
|
||||
some type. cereal will then use this value as a second parameter
|
||||
to your serialization functions.
|
||||
|
||||
The interface for the serialization functions is nearly identical
|
||||
to non-versioned serialization with the addition of a second parameter,
|
||||
const std::uint32_t version, which will be supplied with the correct
|
||||
version number. Serializing the version number on a save happens
|
||||
automatically.
|
||||
|
||||
Versioning cannot be mixed with non-versioned serialization functions.
|
||||
Having both types will result result in a compile time error. Data
|
||||
serialized without versioning cannot be loaded by a serialization
|
||||
function with added versioning support.
|
||||
|
||||
Example interface for versioning on a non-member serialize function:
|
||||
|
||||
@code{cpp}
|
||||
CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
|
||||
{
|
||||
// When performing a load, the version associated with the class
|
||||
// is whatever it was when that data was originally serialized
|
||||
//
|
||||
// When we save, we'll use the version that is defined in the macro
|
||||
|
||||
if( version >= some_number )
|
||||
// do this
|
||||
else
|
||||
// do that
|
||||
}
|
||||
@endcode
|
||||
|
||||
Interfaces for other forms of serialization functions is similar. This
|
||||
macro should be placed at global scope.
|
||||
@ingroup Utility */
|
||||
#define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
|
||||
namespace cereal { namespace detail { \
|
||||
template <> struct Version<TYPE> \
|
||||
{ \
|
||||
static const std::uint32_t version; \
|
||||
static std::uint32_t registerVersion() \
|
||||
{ \
|
||||
::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
|
||||
std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
|
||||
return VERSION_NUMBER; \
|
||||
} \
|
||||
CEREAL_UNUSED_FUNCTION \
|
||||
}; /* end Version */ \
|
||||
const std::uint32_t Version<TYPE>::version = \
|
||||
Version<TYPE>::registerVersion(); \
|
||||
} } // end namespaces
|
||||
|
||||
// ######################################################################
|
||||
//! The base output archive class
|
||||
/*! This is the base output archive for all output archives. If you create
|
||||
a custom archive class, it should derive from this, passing itself as
|
||||
@@ -171,11 +297,14 @@ namespace cereal
|
||||
{
|
||||
public:
|
||||
//! Construct the output archive
|
||||
/*! @param self A pointer to the derived ArchiveType (pass this from the derived archive) */
|
||||
OutputArchive(ArchiveType * const self) : self(self), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
|
||||
/*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
|
||||
OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
|
||||
{ }
|
||||
|
||||
OutputArchive & operator=( OutputArchive const & ) = delete;
|
||||
|
||||
//! Serializes all passed in data
|
||||
/*! This is the primary interface for serializing data with an archive */
|
||||
template <class ... Types> inline
|
||||
ArchiveType & operator()( Types && ... args )
|
||||
{
|
||||
@@ -183,14 +312,66 @@ namespace cereal
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serializes any data marked for deferment using defer
|
||||
/*! This will cause any data wrapped in DeferredData to be immediately serialized */
|
||||
void serializeDeferments()
|
||||
{
|
||||
for( auto & deferment : itsDeferments )
|
||||
deferment();
|
||||
}
|
||||
|
||||
/*! @name Boost Transition Layer
|
||||
Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
|
||||
a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
|
||||
//! @{
|
||||
|
||||
//! Indicates this archive is not intended for loading
|
||||
/*! This ensures compatibility with boost archive types. If you are transitioning
|
||||
from boost, you can check this value within a member or external serialize function
|
||||
(i.e., Archive::is_loading::value) to disable behavior specific to loading, until
|
||||
you can transition to split save/load or save_minimal/load_minimal functions */
|
||||
using is_loading = std::false_type;
|
||||
|
||||
//! Indicates this archive is intended for saving
|
||||
/*! This ensures compatibility with boost archive types. If you are transitioning
|
||||
from boost, you can check this value within a member or external serialize function
|
||||
(i.e., Archive::is_saving::value) to enable behavior specific to loading, until
|
||||
you can transition to split save/load or save_minimal/load_minimal functions */
|
||||
using is_saving = std::true_type;
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator&( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator<<( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
//! Registers a shared pointer with the archive
|
||||
/*! This function is used to track shared pointer targets to prevent
|
||||
unnecessary saves from taking place if multiple shared pointers
|
||||
point to the same data.
|
||||
|
||||
@internal
|
||||
@param addr The address (see shared_ptr get()) pointed to by the shared pointer
|
||||
@return A key that uniquely identifies the pointer */
|
||||
std::uint32_t registerSharedPointer( void const * addr )
|
||||
inline std::uint32_t registerSharedPointer( void const * addr )
|
||||
{
|
||||
// Handle null pointers by just returning 0
|
||||
if(addr == 0) return 0;
|
||||
@@ -211,9 +392,10 @@ namespace cereal
|
||||
unnecessary saves of identifying strings used by the polymorphic
|
||||
support functionality.
|
||||
|
||||
@internal
|
||||
@param name The name to associate with a polymorphic type
|
||||
@return A key that uniquely identifies the polymorphic type name */
|
||||
std::uint32_t registerPolymorphicType( char const * name )
|
||||
inline std::uint32_t registerPolymorphicType( char const * name )
|
||||
{
|
||||
auto id = itsPolymorphicTypeMap.find( name );
|
||||
if( id == itsPolymorphicTypeMap.end() )
|
||||
@@ -267,77 +449,193 @@ namespace cereal
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member serialization
|
||||
std::vector<std::function<void(void)>> itsDeferments;
|
||||
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() ||
|
||||
(traits::is_output_serializable<T, ArchiveType>() && traits::has_member_serialize<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
ArchiveType & processImpl(DeferredData<T> const & d)
|
||||
{
|
||||
std::function<void(void)> deferment( [=](){ self->process( d.value ); } );
|
||||
itsDeferments.emplace_back( std::move(deferment) );
|
||||
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Helper macro that expands the requirements for activating an overload
|
||||
/*! Requirements:
|
||||
Has the requested serialization function
|
||||
Does not have version and unversioned at the same time
|
||||
Is output serializable AND
|
||||
is specialized for this type of function OR
|
||||
has no specialization at all */
|
||||
#define PROCESS_IF(name) \
|
||||
traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
|
||||
!traits::has_invalid_output_versioning<T, ArchiveType>::value, \
|
||||
(traits::is_output_serializable<T, ArchiveType>::value && \
|
||||
(traits::is_specialized_##name<T, ArchiveType>::value || \
|
||||
!traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
|
||||
|
||||
//! Member serialization
|
||||
template <class T, PROCESS_IF(member_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_serialize(*self, const_cast<T &>(t));
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_non_member_serialize<T, ArchiveType>() ||
|
||||
(traits::is_output_serializable<T, ArchiveType>() && traits::has_non_member_serialize<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
template <class T, PROCESS_IF(non_member_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
serialize(*self, const_cast<T &>(t));
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t));
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save)
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_member_save<T, ArchiveType>() ||
|
||||
(traits::is_output_serializable<T, ArchiveType>() && traits::has_member_save<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
template <class T, PROCESS_IF(member_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_save(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save)
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_non_member_save<T, ArchiveType>() ||
|
||||
(traits::is_output_serializable<T, ArchiveType>() && traits::has_non_member_save<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
template <class T, PROCESS_IF(non_member_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
save(*self, t);
|
||||
CEREAL_SAVE_FUNCTION_NAME(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save_minimal)
|
||||
template <class T, PROCESS_IF(member_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( access::member_save_minimal(*self, t) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save_minimal)
|
||||
template <class T, PROCESS_IF(non_member_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Empty class specialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<(Flags & AllowEmptyClassElision) &&
|
||||
!traits::is_output_serializable<T, ArchiveType>() && traits::is_empty_class<T>(), ArchiveType &>::type
|
||||
processImpl(T const &)
|
||||
template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
|
||||
!traits::is_output_serializable<T, ArchiveType>::value,
|
||||
std::is_empty<T>::value> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! No matching serialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<!traits::is_specialized<T, ArchiveType>() && !traits::is_output_serializable<T, ArchiveType>() &&
|
||||
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !traits::is_empty_class<T>())),
|
||||
ArchiveType &>::type
|
||||
processImpl(T const &)
|
||||
/*! Invalid if we have invalid output versioning or
|
||||
we are not output serializable, and either
|
||||
don't allow empty class ellision or allow it but are not serializing an empty class */
|
||||
template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
|
||||
(!traits::is_output_serializable<T, ArchiveType>::value &&
|
||||
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
static_assert(traits::is_output_serializable<T, ArchiveType>(), "Trying to serialize an unserializable type with an output archive.\n\n"
|
||||
"Types must either have a serialize function, or separate save/load functions (but not both).\n"
|
||||
"Serialize functions generally have the following signature:\n\n"
|
||||
"template<class Archive>\n"
|
||||
" void serialize(Archive & ar)\n"
|
||||
" {\n"
|
||||
" ar( member1, member2, member3 );\n"
|
||||
" }\n\n" );
|
||||
static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
|
||||
"cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Serialize functions generally have the following signature: \n\n "
|
||||
"template<class Archive> \n "
|
||||
" void serialize(Archive & ar) \n "
|
||||
" { \n "
|
||||
" ar( member1, member2, member3 ); \n "
|
||||
" } \n\n " );
|
||||
|
||||
static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
|
||||
"cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
|
||||
"Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
|
||||
"In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
|
||||
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Registers a class version with the archive and serializes it if necessary
|
||||
/*! If this is the first time this class has been serialized, we will record its
|
||||
version number and serialize that.
|
||||
|
||||
@tparam T The type of the class being serialized */
|
||||
template <class T> inline
|
||||
std::uint32_t registerClassVersion()
|
||||
{
|
||||
static const auto hash = std::type_index(typeid(T)).hash_code();
|
||||
const auto insertResult = itsVersionedTypes.insert( hash );
|
||||
const auto lock = detail::StaticObject<detail::Versions>::lock();
|
||||
const auto version =
|
||||
detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
|
||||
|
||||
if( insertResult.second ) // insertion took place, serialize the version number
|
||||
process( make_nvp<ArchiveType>("cereal_class_version", version) );
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
//! Member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_serialize(*self, const_cast<T &>(t), registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t), registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
access::member_save(*self, t, registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_save)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
CEREAL_SAVE_FUNCTION_NAME(*self, t, registerClassVersion<T>());
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (save_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( access::member_save_minimal(*self, t, registerClassVersion<T>()) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (save_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_save_minimal)> inline
|
||||
ArchiveType & processImpl(T const & t)
|
||||
{
|
||||
self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t, registerClassVersion<T>()) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
#undef PROCESS_IF
|
||||
|
||||
private:
|
||||
ArchiveType * const self;
|
||||
|
||||
@@ -355,6 +653,9 @@ namespace cereal
|
||||
|
||||
//! The id to be given to the next polymorphic type name
|
||||
std::uint32_t itsCurrentPolymorphicTypeId;
|
||||
|
||||
//! Keeps track of classes that have versioning information associated with them
|
||||
std::unordered_set<size_type> itsVersionedTypes;
|
||||
}; // class OutputArchive
|
||||
|
||||
// ######################################################################
|
||||
@@ -379,10 +680,19 @@ namespace cereal
|
||||
{
|
||||
public:
|
||||
//! Construct the output archive
|
||||
/*! @param self A pointer to the derived ArchiveType (pass this from the derived archive) */
|
||||
InputArchive(ArchiveType * const self) : self(self) { }
|
||||
/*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
|
||||
InputArchive(ArchiveType * const derived) :
|
||||
self(derived),
|
||||
itsBaseClassSet(),
|
||||
itsSharedPointerMap(),
|
||||
itsPolymorphicTypeMap(),
|
||||
itsVersionedTypes()
|
||||
{ }
|
||||
|
||||
InputArchive & operator=( InputArchive const & ) = delete;
|
||||
|
||||
//! Serializes all passed in data
|
||||
/*! This is the primary interface for serializing data with an archive */
|
||||
template <class ... Types> inline
|
||||
ArchiveType & operator()( Types && ... args )
|
||||
{
|
||||
@@ -390,42 +700,97 @@ namespace cereal
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serializes any data marked for deferment using defer
|
||||
/*! This will cause any data wrapped in DeferredData to be immediately serialized */
|
||||
void serializeDeferments()
|
||||
{
|
||||
for( auto & deferment : itsDeferments )
|
||||
deferment();
|
||||
}
|
||||
|
||||
/*! @name Boost Transition Layer
|
||||
Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
|
||||
a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
|
||||
//! @{
|
||||
|
||||
//! Indicates this archive is intended for loading
|
||||
/*! This ensures compatibility with boost archive types. If you are transitioning
|
||||
from boost, you can check this value within a member or external serialize function
|
||||
(i.e., Archive::is_loading::value) to enable behavior specific to loading, until
|
||||
you can transition to split save/load or save_minimal/load_minimal functions */
|
||||
using is_loading = std::true_type;
|
||||
|
||||
//! Indicates this archive is not intended for saving
|
||||
/*! This ensures compatibility with boost archive types. If you are transitioning
|
||||
from boost, you can check this value within a member or external serialize function
|
||||
(i.e., Archive::is_saving::value) to disable behavior specific to loading, until
|
||||
you can transition to split save/load or save_minimal/load_minimal functions */
|
||||
using is_saving = std::false_type;
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator&( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Serializes passed in data
|
||||
/*! This is a boost compatability layer and is not the preferred way of using
|
||||
cereal. If you are transitioning from boost, use this until you can
|
||||
transition to the operator() overload */
|
||||
template <class T> inline
|
||||
ArchiveType & operator>>( T && arg )
|
||||
{
|
||||
self->process( std::forward<T>( arg ) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! @}
|
||||
|
||||
//! Retrieves a shared pointer given a unique key for it
|
||||
/*! This is used to retrieve a previously registered shared_ptr
|
||||
which has already been loaded.
|
||||
|
||||
@internal
|
||||
@param id The unique id that was serialized for the pointer
|
||||
@return A shared pointer to the data */
|
||||
std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
|
||||
@return A shared pointer to the data
|
||||
@throw Exception if the id does not exist */
|
||||
inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
|
||||
{
|
||||
if(id == 0) return std::shared_ptr<void>(nullptr);
|
||||
|
||||
auto ptr = itsSharedPointerMap.find( id );
|
||||
if(ptr == itsSharedPointerMap.end())
|
||||
auto iter = itsSharedPointerMap.find( id );
|
||||
if(iter == itsSharedPointerMap.end())
|
||||
throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
|
||||
|
||||
return ptr->second;
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
//! Registers a shared pointer to its unique identifier
|
||||
/*! After a shared pointer has been loaded for the first time, it should
|
||||
/*! After a shared pointer has been allocated for the first time, it should
|
||||
be registered with its loaded id for future references to it.
|
||||
|
||||
@internal
|
||||
@param id The unique identifier for the shared pointer
|
||||
@param ptr The actual shared pointer */
|
||||
void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
|
||||
inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
|
||||
{
|
||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
||||
itsSharedPointerMap.insert( {stripped_id, ptr} );
|
||||
itsSharedPointerMap[stripped_id] = ptr;
|
||||
}
|
||||
|
||||
//! Retrieves the string for a polymorphic type given a unique key for it
|
||||
/*! This is used to retrieve a string previously registered during
|
||||
a polymorphic load.
|
||||
|
||||
@internal
|
||||
@param id The unique id that was serialized for the polymorphic type
|
||||
@return The string identifier for the tyep */
|
||||
std::string getPolymorphicName(std::uint32_t const id)
|
||||
inline std::string getPolymorphicName(std::uint32_t const id)
|
||||
{
|
||||
auto name = itsPolymorphicTypeMap.find( id );
|
||||
if(name == itsPolymorphicTypeMap.end())
|
||||
@@ -439,9 +804,10 @@ namespace cereal
|
||||
/*! After a polymorphic type has been loaded for the first time, it should
|
||||
be registered with its loaded id for future references to it.
|
||||
|
||||
@internal
|
||||
@param id The unique identifier for the polymorphic type
|
||||
@param name The name associated with the tyep */
|
||||
void registerPolymorphicName(std::uint32_t const id, std::string const & name)
|
||||
inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
|
||||
{
|
||||
std::uint32_t const stripped_id = id & ~detail::msb_32bit;
|
||||
itsPolymorphicTypeMap.insert( {stripped_id, name} );
|
||||
@@ -488,93 +854,236 @@ namespace cereal
|
||||
return *self;
|
||||
}
|
||||
|
||||
std::vector<std::function<void(void)>> itsDeferments;
|
||||
|
||||
template <class T> inline
|
||||
ArchiveType & processImpl(DeferredData<T> const & d)
|
||||
{
|
||||
std::function<void(void)> deferment( [=](){ self->process( d.value ); } );
|
||||
itsDeferments.emplace_back( std::move(deferment) );
|
||||
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Helper macro that expands the requirements for activating an overload
|
||||
/*! Requirements:
|
||||
Has the requested serialization function
|
||||
Does not have version and unversioned at the same time
|
||||
Is input serializable AND
|
||||
is specialized for this type of function OR
|
||||
has no specialization at all */
|
||||
#define PROCESS_IF(name) \
|
||||
traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
|
||||
!traits::has_invalid_input_versioning<T, ArchiveType>::value, \
|
||||
(traits::is_input_serializable<T, ArchiveType>::value && \
|
||||
(traits::is_specialized_##name<T, ArchiveType>::value || \
|
||||
!traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
|
||||
|
||||
//! Member serialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() ||
|
||||
(traits::is_input_serializable<T, ArchiveType>() && traits::has_member_serialize<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
template <class T, PROCESS_IF(member_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
access::member_serialize(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_non_member_serialize<T, ArchiveType>() ||
|
||||
(traits::is_input_serializable<T, ArchiveType>() && traits::has_non_member_serialize<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
template <class T, PROCESS_IF(non_member_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
serialize(*self, t);
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load)
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_member_load<T, ArchiveType>() ||
|
||||
(traits::is_input_serializable<T, ArchiveType>() && traits::has_member_load<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
template <class T, PROCESS_IF(member_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
access::member_load(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load)
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::is_specialized_non_member_load<T, ArchiveType>() ||
|
||||
(traits::is_input_serializable<T, ArchiveType>() && traits::has_non_member_load<T, ArchiveType>()),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
template <class T, PROCESS_IF(non_member_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
load(*self, t);
|
||||
CEREAL_LOAD_FUNCTION_NAME(*self, t);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load_minimal)
|
||||
template <class T, PROCESS_IF(member_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process( value );
|
||||
access::member_load_minimal(*self, t, value);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load_minimal)
|
||||
template <class T, PROCESS_IF(non_member_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process( value );
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Empty class specialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<(Flags & AllowEmptyClassElision) &&
|
||||
!traits::is_input_serializable<T, ArchiveType>() && traits::is_empty_class<T>(), ArchiveType &>::type
|
||||
processImpl(T const &)
|
||||
template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
|
||||
!traits::is_input_serializable<T, ArchiveType>::value,
|
||||
std::is_empty<T>::value> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! No matching serialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<!traits::is_specialized<T, ArchiveType>() && !traits::is_input_serializable<T, ArchiveType>() &&
|
||||
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !traits::is_empty_class<T>())),
|
||||
ArchiveType &>::type
|
||||
processImpl(T const &)
|
||||
/*! Invalid if we have invalid input versioning or
|
||||
we are not input serializable, and either
|
||||
don't allow empty class ellision or allow it but are not serializing an empty class */
|
||||
template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
|
||||
(!traits::is_input_serializable<T, ArchiveType>::value &&
|
||||
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
|
||||
ArchiveType & processImpl(T const &)
|
||||
{
|
||||
static_assert(traits::is_output_serializable<T, ArchiveType>(), "Trying to serialize an unserializable type with an output archive.\n\n"
|
||||
"Types must either have a serialize function, or separate save/load functions (but not both).\n"
|
||||
"Serialize functions generally have the following signature:\n\n"
|
||||
"template<class Archive>\n"
|
||||
" void serialize(Archive & ar)\n"
|
||||
" {\n"
|
||||
" ar( member1, member2, member3 );\n"
|
||||
" }\n\n" );
|
||||
static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
|
||||
"cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Serialize functions generally have the following signature: \n\n "
|
||||
"template<class Archive> \n "
|
||||
" void serialize(Archive & ar) \n "
|
||||
" { \n "
|
||||
" ar( member1, member2, member3 ); \n "
|
||||
" } \n\n " );
|
||||
|
||||
static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
|
||||
"cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
|
||||
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
|
||||
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
|
||||
"Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
|
||||
"In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
|
||||
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Befriend for versioning in load_and_construct
|
||||
template <class A, class B, bool C, bool D, bool E, bool F> friend struct detail::Construct;
|
||||
|
||||
//! Registers a class version with the archive and serializes it if necessary
|
||||
/*! If this is the first time this class has been serialized, we will record its
|
||||
version number and serialize that.
|
||||
|
||||
@tparam T The type of the class being serialized */
|
||||
template <class T> inline
|
||||
std::uint32_t loadClassVersion()
|
||||
{
|
||||
static const auto hash = std::type_index(typeid(T)).hash_code();
|
||||
auto lookupResult = itsVersionedTypes.find( hash );
|
||||
|
||||
if( lookupResult != itsVersionedTypes.end() ) // already exists
|
||||
return lookupResult->second;
|
||||
else // need to load
|
||||
{
|
||||
std::uint32_t version;
|
||||
|
||||
process( make_nvp<ArchiveType>("cereal_class_version", version) );
|
||||
itsVersionedTypes.emplace_hint( lookupResult, hash, version );
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
//! Member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
access::member_serialize(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member serialization
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
access::member_load(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_load)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
CEREAL_LOAD_FUNCTION_NAME(*self, t, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
const auto version = loadClassVersion<T>();
|
||||
typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process(value);
|
||||
access::member_load_minimal(*self, t, value, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
const auto version = loadClassVersion<T>();
|
||||
typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
|
||||
self->process(value);
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
#undef PROCESS_IF
|
||||
|
||||
private:
|
||||
ArchiveType * const self;
|
||||
|
||||
//! A set of all base classes that have been serialized
|
||||
std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
|
||||
|
||||
//! Maps from pointer ids to addresses
|
||||
//! Maps from pointer ids to metadata
|
||||
std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
|
||||
|
||||
//! Maps from name ids to names
|
||||
std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
|
||||
|
||||
//! Maps from type hash codes to version numbers
|
||||
std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
|
||||
}; // class InputArchive
|
||||
} // namespace cereal
|
||||
|
||||
// This include needs to come after things such as binary_data, make_nvp, etc
|
||||
#include <cereal/types/common.hpp>
|
||||
#include "cereal/types/common.hpp"
|
||||
|
||||
#endif // CEREAL_CEREAL_HPP_
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Internal helper functionality
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -33,15 +33,32 @@
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "cereal/macros.hpp"
|
||||
#include "cereal/details/static_object.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// ######################################################################
|
||||
//! An exception class thrown when things go wrong at runtime
|
||||
/*! @ingroup Utility */
|
||||
struct Exception : public std::runtime_error
|
||||
{
|
||||
explicit Exception( const std::string & what_ ) : std::runtime_error(what_) {}
|
||||
explicit Exception( const char * what_ ) : std::runtime_error(what_) {}
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! The size type used by cereal
|
||||
/*! To ensure compatability between 32, 64, etc bit machines, we need to use
|
||||
* a fixed size type instead of size_t, which may vary from machine to
|
||||
* machine. */
|
||||
typedef uint64_t size_type;
|
||||
a fixed size type instead of size_t, which may vary from machine to
|
||||
machine.
|
||||
|
||||
The default value for CEREAL_SIZE_TYPE is specified in cereal/macros.hpp */
|
||||
using size_type = CEREAL_SIZE_TYPE;
|
||||
|
||||
// forward decls
|
||||
class BinaryOutputArchive;
|
||||
@@ -50,9 +67,11 @@ namespace cereal
|
||||
// ######################################################################
|
||||
namespace detail
|
||||
{
|
||||
struct NameValuePairCore {};
|
||||
struct NameValuePairCore {}; //!< Traits struct for NVPs
|
||||
struct DeferredDataCore {}; //!< Traits struct for DeferredData
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! For holding name value pairs
|
||||
/*! This pairs a name (some string) with some value such that an archive
|
||||
can potentially take advantage of the pairing.
|
||||
@@ -94,7 +113,7 @@ namespace cereal
|
||||
@endcode
|
||||
|
||||
There is a slight amount of overhead to creating NameValuePairs, so there
|
||||
is a third method which will elide the names when they are not needed by
|
||||
is a third method which will elide the names when they are not used by
|
||||
the Archive:
|
||||
|
||||
@code{.cpp}
|
||||
@@ -120,16 +139,20 @@ namespace cereal
|
||||
class NameValuePair : detail::NameValuePairCore
|
||||
{
|
||||
private:
|
||||
// If we get passed an RValue, we'll just make a local copy if it here
|
||||
// otherwise, we store a reference
|
||||
using DT = typename std::decay<T>::type;
|
||||
using Type = typename std::conditional<std::is_rvalue_reference<T>::value,
|
||||
DT,
|
||||
typename std::add_lvalue_reference<DT>::type>::type;
|
||||
// If we get passed an array, keep the type as is, otherwise store
|
||||
// a reference if we were passed an l value reference, else copy the value
|
||||
using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
|
||||
typename std::remove_cv<T>::type,
|
||||
typename std::conditional<std::is_lvalue_reference<T>::value,
|
||||
T,
|
||||
typename std::decay<T>::type>::type>::type;
|
||||
|
||||
// prevent nested nvps
|
||||
static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
|
||||
"Cannot pair a name to a NameValuePair" );
|
||||
|
||||
NameValuePair & operator=( NameValuePair const & ) = delete;
|
||||
|
||||
public:
|
||||
//! Constructs a new NameValuePair
|
||||
/*! @param n The name of the pair
|
||||
@@ -137,9 +160,9 @@ namespace cereal
|
||||
the value can be both loaded and saved to. If you pass an r-value reference,
|
||||
the NameValuePair will store a copy of it instead of a reference. Thus you should
|
||||
only pass r-values in cases where this makes sense, such as the result of some
|
||||
size() call. In either case, any constness will be stripped away
|
||||
@internal */
|
||||
NameValuePair( char const * n, T && v ) : name(n), value(const_cast<Type>(v)) {}
|
||||
size() call.
|
||||
@internal */
|
||||
NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
|
||||
|
||||
char const * name;
|
||||
Type value;
|
||||
@@ -172,10 +195,10 @@ namespace cereal
|
||||
}
|
||||
|
||||
//! Convenience for creating a templated NVP
|
||||
/*! For use in inteneral generic typing functions which have an
|
||||
/*! For use in internal generic typing functions which have an
|
||||
Archive type declared
|
||||
@internal */
|
||||
#define _CEREAL_NVP(name, value) ::cereal::make_nvp<Archive>(name, value)
|
||||
#define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
|
||||
|
||||
// ######################################################################
|
||||
//! A wrapper around data that can be serialized in a binary fashion
|
||||
@@ -189,29 +212,90 @@ namespace cereal
|
||||
{
|
||||
//! Internally store the pointer as a void *, keeping const if created with
|
||||
//! a const pointer
|
||||
using PT = typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
|
||||
using PT = typename std::conditional<std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||
const void *,
|
||||
void *>::type;
|
||||
|
||||
BinaryData( T && d, uint64_t s ) : data(d), size(s) {}
|
||||
BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
|
||||
|
||||
PT data; //!< pointer to beginning of data
|
||||
PT data; //!< pointer to beginning of data
|
||||
uint64_t size; //!< size in bytes
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! A wrapper around data that should be serialized after all non-deferred data
|
||||
/*! This class is used to demarcate data that can only be safely serialized after
|
||||
any data not wrapped in this class.
|
||||
|
||||
@internal */
|
||||
template <class T>
|
||||
class DeferredData : detail::DeferredDataCore
|
||||
{
|
||||
private:
|
||||
// If we get passed an array, keep the type as is, otherwise store
|
||||
// a reference if we were passed an l value reference, else copy the value
|
||||
using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
|
||||
typename std::remove_cv<T>::type,
|
||||
typename std::conditional<std::is_lvalue_reference<T>::value,
|
||||
T,
|
||||
typename std::decay<T>::type>::type>::type;
|
||||
|
||||
// prevent nested nvps
|
||||
static_assert( !std::is_base_of<detail::DeferredDataCore, T>::value,
|
||||
"Cannot defer DeferredData" );
|
||||
|
||||
DeferredData & operator=( DeferredData const & ) = delete;
|
||||
|
||||
public:
|
||||
//! Constructs a new NameValuePair
|
||||
/*! @param v The value to defer. Ideally this should be an l-value reference so that
|
||||
the value can be both loaded and saved to. If you pass an r-value reference,
|
||||
the DeferredData will store a copy of it instead of a reference. Thus you should
|
||||
only pass r-values in cases where this makes sense, such as the result of some
|
||||
size() call.
|
||||
@internal */
|
||||
DeferredData( T && v ) : value(std::forward<T>(v)) {}
|
||||
|
||||
Type value;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
namespace detail
|
||||
{
|
||||
// base classes for type checking
|
||||
struct OutputArchiveBase {};
|
||||
struct InputArchiveBase {};
|
||||
/* The rtti virtual function only exists to enable an archive to
|
||||
be used in a polymorphic fashion, if necessary. See the
|
||||
archive adapters for an example of this */
|
||||
class OutputArchiveBase
|
||||
{
|
||||
public:
|
||||
OutputArchiveBase() = default;
|
||||
OutputArchiveBase( OutputArchiveBase && ) CEREAL_NOEXCEPT {}
|
||||
OutputArchiveBase & operator=( OutputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
|
||||
virtual ~OutputArchiveBase() CEREAL_NOEXCEPT = default;
|
||||
|
||||
private:
|
||||
virtual void rtti() {}
|
||||
};
|
||||
|
||||
class InputArchiveBase
|
||||
{
|
||||
public:
|
||||
InputArchiveBase() = default;
|
||||
InputArchiveBase( InputArchiveBase && ) CEREAL_NOEXCEPT {}
|
||||
InputArchiveBase & operator=( InputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
|
||||
virtual ~InputArchiveBase() CEREAL_NOEXCEPT = default;
|
||||
|
||||
private:
|
||||
virtual void rtti() {}
|
||||
};
|
||||
|
||||
// forward decls for polymorphic support
|
||||
template <class Archive, class T> struct polymorphic_serialization_support;
|
||||
struct adl_tag;
|
||||
|
||||
// used during saving pointers
|
||||
static const int32_t msb_32bit = 0x80000000;
|
||||
static const uint32_t msb_32bit = 0x80000000;
|
||||
static const int32_t msb2_32bit = 0x40000000;
|
||||
}
|
||||
|
||||
@@ -228,15 +312,16 @@ namespace cereal
|
||||
class SizeTag
|
||||
{
|
||||
private:
|
||||
// If we get passed an RValue, we'll just make a local copy if it here
|
||||
// otherwise, we store a reference
|
||||
using DT = typename std::decay<T>::type;
|
||||
using Type = typename std::conditional<std::is_rvalue_reference<T>::value,
|
||||
DT,
|
||||
typename std::add_lvalue_reference<DT>::type>::type;
|
||||
// Store a reference if passed an lvalue reference, otherwise
|
||||
// make a copy of the data
|
||||
using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
|
||||
T,
|
||||
typename std::decay<T>::type>::type;
|
||||
|
||||
SizeTag & operator=( SizeTag const & ) = delete;
|
||||
|
||||
public:
|
||||
SizeTag( T && sz ) : size(const_cast<Type>(sz)) {}
|
||||
SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
|
||||
|
||||
Type size;
|
||||
};
|
||||
@@ -265,28 +350,28 @@ namespace cereal
|
||||
template <class Key, class Value>
|
||||
struct MapItem
|
||||
{
|
||||
using DecayKey = typename std::decay<Key>::type;
|
||||
using KeyType = typename std::conditional<
|
||||
std::is_rvalue_reference<Key>::value,
|
||||
DecayKey,
|
||||
typename std::add_lvalue_reference<DecayKey>::type>::type;
|
||||
std::is_lvalue_reference<Key>::value,
|
||||
Key,
|
||||
typename std::decay<Key>::type>::type;
|
||||
|
||||
using DecayValue = typename std::decay<Value>::type;
|
||||
using ValueType = typename std::conditional<
|
||||
std::is_rvalue_reference<Value>::value,
|
||||
DecayValue,
|
||||
typename std::add_lvalue_reference<DecayValue>::type>::type;
|
||||
std::is_lvalue_reference<Value>::value,
|
||||
Value,
|
||||
typename std::decay<Value>::type>::type;
|
||||
|
||||
//! Construct a MapItem from a key and a value
|
||||
/*! @internal */
|
||||
MapItem( Key && key, Value && value ) : key(const_cast<KeyType>(key)), value(const_cast<ValueType>(value)) {}
|
||||
MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
|
||||
|
||||
MapItem & operator=( MapItem const & ) = delete;
|
||||
|
||||
KeyType key;
|
||||
ValueType value;
|
||||
|
||||
//! Serialize the MapItem with the NVPs "key" and "value"
|
||||
template <class Archive> inline
|
||||
void serialize(Archive & archive)
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
|
||||
{
|
||||
archive( make_nvp<Archive>("key", key),
|
||||
make_nvp<Archive>("value", value) );
|
||||
@@ -301,6 +386,37 @@ namespace cereal
|
||||
{
|
||||
return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//! Tag for Version, which due to its anonymous namespace, becomes a different
|
||||
//! type in each translation unit
|
||||
/*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
|
||||
namespace{ struct version_binding_tag {}; }
|
||||
|
||||
// ######################################################################
|
||||
//! Version information class
|
||||
/*! This is the base case for classes that have not been explicitly
|
||||
registered */
|
||||
template <class T, class BindingTag = version_binding_tag> struct Version
|
||||
{
|
||||
static const std::uint32_t version = 0;
|
||||
// we don't need to explicitly register these types since they
|
||||
// always get a version number of 0
|
||||
};
|
||||
|
||||
//! Holds all registered version information
|
||||
struct Versions
|
||||
{
|
||||
std::unordered_map<std::size_t, std::uint32_t> mapping;
|
||||
|
||||
std::uint32_t find( std::size_t hash, std::uint32_t version )
|
||||
{
|
||||
const auto result = mapping.emplace( hash, version );
|
||||
return result.first->second;
|
||||
}
|
||||
}; // struct Versions
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_DETAILS_HELPERS_HPP_
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Internal polymorphism support
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -38,38 +38,406 @@
|
||||
|
||||
(C) Copyright 2006 David Abrahams - http://www.boost.org.
|
||||
|
||||
See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for their
|
||||
implementation.
|
||||
See /boost/serialization/export.hpp, /boost/archive/detail/register_archive.hpp,
|
||||
and /boost/serialization/void_cast.hpp for their implementation. Additional details
|
||||
found in other files split across serialization and archive.
|
||||
*/
|
||||
#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
|
||||
#define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
|
||||
|
||||
#include <cereal/details/static_object.hpp>
|
||||
#include <cereal/types/memory.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
#include "cereal/details/polymorphic_impl_fwd.hpp"
|
||||
#include "cereal/details/static_object.hpp"
|
||||
#include "cereal/types/memory.hpp"
|
||||
#include "cereal/types/string.hpp"
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
#include <map>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
||||
//! Helper macro to omit unused warning
|
||||
#if defined(__GNUC__)
|
||||
// GCC / clang don't want the function
|
||||
#define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION
|
||||
#else
|
||||
#define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION static void unused() { (void)b; }
|
||||
#endif
|
||||
|
||||
//! Binds a polymorhic type to all registered archives
|
||||
/*! This binds a polymorphic type to all registered archives that
|
||||
/*! This binds a polymorphic type to all compatible registered archives that
|
||||
have been registered with CEREAL_REGISTER_ARCHIVE. This must be called
|
||||
after all archives are registered (usually after the archives themselves
|
||||
have been included). */
|
||||
#define CEREAL_BIND_TO_ARCHIVES(T) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template<> \
|
||||
struct init_binding<T> { \
|
||||
static bind_to_archives<T> const & b; \
|
||||
}; \
|
||||
bind_to_archives<T> const & init_binding<T>::b = \
|
||||
::cereal::detail::StaticObject< \
|
||||
bind_to_archives<T > \
|
||||
>::getInstance().bind(); \
|
||||
}} // end namespaces
|
||||
#define CEREAL_BIND_TO_ARCHIVES(...) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template<> \
|
||||
struct init_binding<__VA_ARGS__> { \
|
||||
static bind_to_archives<__VA_ARGS__> const & b; \
|
||||
CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
|
||||
}; \
|
||||
bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \
|
||||
::cereal::detail::StaticObject< \
|
||||
bind_to_archives<__VA_ARGS__> \
|
||||
>::getInstance().bind(); \
|
||||
}} /* end namespaces */
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
/* Polymorphic casting support */
|
||||
namespace detail
|
||||
{
|
||||
//! Base type for polymorphic void casting
|
||||
/*! Contains functions for casting between registered base and derived types.
|
||||
|
||||
This is necessary so that cereal can properly cast between polymorphic types
|
||||
even though void pointers are used, which normally have no type information.
|
||||
Runtime type information is used instead to index a compile-time made mapping
|
||||
that can perform the proper cast. In the case of multiple levels of inheritance,
|
||||
cereal will attempt to find the shortest path by using registered relationships to
|
||||
perform the cast.
|
||||
|
||||
This class will be allocated as a StaticObject and only referenced by pointer,
|
||||
allowing a templated derived version of it to define strongly typed functions
|
||||
that cast between registered base and derived types. */
|
||||
struct PolymorphicCaster
|
||||
{
|
||||
PolymorphicCaster() = default;
|
||||
PolymorphicCaster( const PolymorphicCaster & ) = default;
|
||||
PolymorphicCaster & operator=( const PolymorphicCaster & ) = default;
|
||||
PolymorphicCaster( PolymorphicCaster && ) CEREAL_NOEXCEPT {}
|
||||
PolymorphicCaster & operator=( PolymorphicCaster && ) CEREAL_NOEXCEPT { return *this; }
|
||||
virtual ~PolymorphicCaster() CEREAL_NOEXCEPT = default;
|
||||
|
||||
//! Downcasts to the proper derived type
|
||||
virtual void const * downcast( void const * const ptr ) const = 0;
|
||||
//! Upcast to proper base type
|
||||
virtual void * upcast( void * const ptr ) const = 0;
|
||||
//! Upcast to proper base type, shared_ptr version
|
||||
virtual std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const = 0;
|
||||
};
|
||||
|
||||
//! Holds registered mappings between base and derived types for casting
|
||||
/*! This will be allocated as a StaticObject and holds a map containing
|
||||
all registered mappings between base and derived types. */
|
||||
struct PolymorphicCasters
|
||||
{
|
||||
//! Maps from a derived type index to a set of chainable casters
|
||||
using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
|
||||
//! Maps from base type index to a map from derived type index to caster
|
||||
std::unordered_map<std::type_index, DerivedCasterMap> map;
|
||||
|
||||
std::multimap<std::type_index, std::type_index> reverseMap;
|
||||
|
||||
//! Error message used for unregistered polymorphic casts
|
||||
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \
|
||||
throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \
|
||||
"Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \
|
||||
"Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \
|
||||
"Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION.");
|
||||
|
||||
//! Checks if the mapping object that can perform the upcast or downcast exists, and returns it if so
|
||||
/*! Uses the type index from the base and derived class to find the matching
|
||||
registered caster. If no matching caster exists, the bool in the pair will be false and the vector
|
||||
reference should not be used. */
|
||||
static std::pair<bool, std::vector<PolymorphicCaster const *> const &>
|
||||
lookup_if_exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
|
||||
{
|
||||
// First phase of lookup - match base type index
|
||||
auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
|
||||
auto baseIter = baseMap.find( baseIndex );
|
||||
if (baseIter == baseMap.end())
|
||||
return {false, {}};
|
||||
|
||||
// Second phase - find a match from base to derived
|
||||
auto const & derivedMap = baseIter->second;
|
||||
auto derivedIter = derivedMap.find( derivedIndex );
|
||||
if (derivedIter == derivedMap.end())
|
||||
return {false, {}};
|
||||
|
||||
return {true, derivedIter->second};
|
||||
}
|
||||
|
||||
//! Gets the mapping object that can perform the upcast or downcast
|
||||
/*! Uses the type index from the base and derived class to find the matching
|
||||
registered caster. If no matching caster exists, calls the exception function.
|
||||
|
||||
The returned PolymorphicCaster is capable of upcasting or downcasting between the two types. */
|
||||
template <class F> inline
|
||||
static std::vector<PolymorphicCaster const *> const & lookup( std::type_index const & baseIndex, std::type_index const & derivedIndex, F && exceptionFunc )
|
||||
{
|
||||
// First phase of lookup - match base type index
|
||||
auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
|
||||
auto baseIter = baseMap.find( baseIndex );
|
||||
if( baseIter == baseMap.end() )
|
||||
exceptionFunc();
|
||||
|
||||
// Second phase - find a match from base to derived
|
||||
auto const & derivedMap = baseIter->second;
|
||||
auto derivedIter = derivedMap.find( derivedIndex );
|
||||
if( derivedIter == derivedMap.end() )
|
||||
exceptionFunc();
|
||||
|
||||
return derivedIter->second;
|
||||
}
|
||||
|
||||
//! Performs a downcast to the derived type using a registered mapping
|
||||
template <class Derived> inline
|
||||
static const Derived * downcast( const void * dptr, std::type_info const & baseInfo )
|
||||
{
|
||||
auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
|
||||
|
||||
for( auto const * dmap : mapping )
|
||||
dptr = dmap->downcast( dptr );
|
||||
|
||||
return static_cast<Derived const *>( dptr );
|
||||
}
|
||||
|
||||
//! Performs an upcast to the registered base type using the given a derived type
|
||||
/*! The return is untyped because the final casting to the base type must happen in the polymorphic
|
||||
serialization function, where the type is known at compile time */
|
||||
template <class Derived> inline
|
||||
static void * upcast( Derived * const dptr, std::type_info const & baseInfo )
|
||||
{
|
||||
auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
|
||||
|
||||
void * uptr = dptr;
|
||||
for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
|
||||
uptr = (*mIter)->upcast( uptr );
|
||||
|
||||
return uptr;
|
||||
}
|
||||
|
||||
//! Upcasts for shared pointers
|
||||
template <class Derived> inline
|
||||
static std::shared_ptr<void> upcast( std::shared_ptr<Derived> const & dptr, std::type_info const & baseInfo )
|
||||
{
|
||||
auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
|
||||
|
||||
std::shared_ptr<void> uptr = dptr;
|
||||
for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
|
||||
uptr = (*mIter)->upcast( uptr );
|
||||
|
||||
return uptr;
|
||||
}
|
||||
|
||||
#undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
|
||||
};
|
||||
|
||||
#ifdef CEREAL_OLDER_GCC
|
||||
#define CEREAL_EMPLACE_MAP(map, key, value) \
|
||||
map.insert( std::make_pair(std::move(key), std::move(value)) );
|
||||
#else // NOT CEREAL_OLDER_GCC
|
||||
#define CEREAL_EMPLACE_MAP(map, key, value) \
|
||||
map.emplace( key, value );
|
||||
#endif // NOT_CEREAL_OLDER_GCC
|
||||
|
||||
//! Strongly typed derivation of PolymorphicCaster
|
||||
template <class Base, class Derived>
|
||||
struct PolymorphicVirtualCaster : PolymorphicCaster
|
||||
{
|
||||
//! Inserts an entry in the polymorphic casting map for this pairing
|
||||
/*! Creates an explicit mapping between Base and Derived in both upwards and
|
||||
downwards directions, allowing void pointers to either to be properly cast
|
||||
assuming dynamic type information is available */
|
||||
PolymorphicVirtualCaster()
|
||||
{
|
||||
const auto baseKey = std::type_index(typeid(Base));
|
||||
const auto derivedKey = std::type_index(typeid(Derived));
|
||||
|
||||
// First insert the relation Base->Derived
|
||||
const auto lock = StaticObject<PolymorphicCasters>::lock();
|
||||
auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
|
||||
|
||||
{
|
||||
auto & derivedMap = baseMap.insert( {baseKey, PolymorphicCasters::DerivedCasterMap{}} ).first->second;
|
||||
auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
|
||||
derivedVec.push_back( this );
|
||||
}
|
||||
|
||||
// Insert reverse relation Derived->Base
|
||||
auto & reverseMap = StaticObject<PolymorphicCasters>::getInstance().reverseMap;
|
||||
CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
|
||||
|
||||
// Find all chainable unregistered relations
|
||||
/* The strategy here is to process only the nodes in the class hierarchy graph that have been
|
||||
affected by the new insertion. The aglorithm iteratively processes a node an ensures that it
|
||||
is updated with all new shortest length paths. It then rocesses the parents of the active node,
|
||||
with the knowledge that all children have already been processed.
|
||||
|
||||
Note that for the following, we'll use the nomenclature of parent and child to not confuse with
|
||||
the inserted base derived relationship */
|
||||
{
|
||||
// Checks whether there is a path from parent->child and returns a <dist, path> pair
|
||||
// dist is set to MAX if the path does not exist
|
||||
auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) ->
|
||||
std::pair<size_t, std::vector<PolymorphicCaster const *> const &>
|
||||
{
|
||||
auto result = PolymorphicCasters::lookup_if_exists( parentInfo, childInfo );
|
||||
if( result.first )
|
||||
{
|
||||
auto const & path = result.second;
|
||||
return {path.size(), path};
|
||||
}
|
||||
else
|
||||
return {(std::numeric_limits<size_t>::max)(), {}};
|
||||
};
|
||||
|
||||
std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
|
||||
std::vector<std::type_index> dirtySet; // Marks child nodes that have been changed
|
||||
std::unordered_set<std::type_index> processedParents; // Marks parent nodes that have been processed
|
||||
|
||||
// Checks if a child has been marked dirty
|
||||
auto isDirty = [&](std::type_index const & c)
|
||||
{
|
||||
auto const dirtySetSize = dirtySet.size();
|
||||
for( size_t i = 0; i < dirtySetSize; ++i )
|
||||
if( dirtySet[i] == c )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Begin processing the base key and mark derived as dirty
|
||||
parentStack.push( baseKey );
|
||||
dirtySet.emplace_back( derivedKey );
|
||||
|
||||
while( !parentStack.empty() )
|
||||
{
|
||||
using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
|
||||
Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation
|
||||
|
||||
const auto parent = parentStack.top();
|
||||
parentStack.pop();
|
||||
|
||||
// Update paths to all children marked dirty
|
||||
for( auto const & childPair : baseMap[parent] )
|
||||
{
|
||||
const auto child = childPair.first;
|
||||
if( isDirty( child ) && baseMap.count( child ) )
|
||||
{
|
||||
auto parentChildPath = checkRelation( parent, child );
|
||||
|
||||
// Search all paths from the child to its own children (finalChild),
|
||||
// looking for a shorter parth from parent to finalChild
|
||||
for( auto const & finalChildPair : baseMap[child] )
|
||||
{
|
||||
const auto finalChild = finalChildPair.first;
|
||||
|
||||
auto parentFinalChildPath = checkRelation( parent, finalChild );
|
||||
auto childFinalChildPath = checkRelation( child, finalChild );
|
||||
|
||||
const size_t newLength = 1u + parentChildPath.first;
|
||||
|
||||
if( newLength < parentFinalChildPath.first )
|
||||
{
|
||||
std::vector<PolymorphicCaster const *> path = parentChildPath.second;
|
||||
path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
|
||||
|
||||
// Check to see if we have a previous uncommitted path in unregisteredRelations
|
||||
// that is shorter. If so, ignore this path
|
||||
auto hintRange = unregisteredRelations.equal_range( parent );
|
||||
auto hint = hintRange.first;
|
||||
for( ; hint != hintRange.second; ++hint )
|
||||
if( hint->second.first == finalChild )
|
||||
break;
|
||||
|
||||
const bool uncommittedExists = hint != unregisteredRelations.end();
|
||||
if( uncommittedExists && (hint->second.second.size() <= newLength) )
|
||||
continue;
|
||||
|
||||
auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
|
||||
|
||||
// Insert the new path if it doesn't exist, otherwise this will just lookup where to do the
|
||||
// replacement
|
||||
#ifdef CEREAL_OLDER_GCC
|
||||
auto old = unregisteredRelations.insert( hint, std::make_pair(parent, newPath) );
|
||||
#else // NOT CEREAL_OLDER_GCC
|
||||
auto old = unregisteredRelations.emplace_hint( hint, parent, newPath );
|
||||
#endif // NOT CEREAL_OLDER_GCC
|
||||
|
||||
// If there was an uncommitted path, we need to perform a replacement
|
||||
if( uncommittedExists )
|
||||
old->second = newPath;
|
||||
}
|
||||
} // end loop over child's children
|
||||
} // end if dirty and child has children
|
||||
} // end loop over children
|
||||
|
||||
// Insert chained relations
|
||||
for( auto const & it : unregisteredRelations )
|
||||
{
|
||||
auto & derivedMap = baseMap.find( it.first )->second;
|
||||
derivedMap[it.second.first] = it.second.second;
|
||||
CEREAL_EMPLACE_MAP(reverseMap, it.second.first, it.first );
|
||||
}
|
||||
|
||||
// Mark current parent as modified
|
||||
dirtySet.emplace_back( parent );
|
||||
|
||||
// Insert all parents of the current parent node that haven't yet been processed
|
||||
auto parentRange = reverseMap.equal_range( parent );
|
||||
for( auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
|
||||
{
|
||||
const auto pParent = pIter->second;
|
||||
if( !processedParents.count( pParent ) )
|
||||
{
|
||||
parentStack.push( pParent );
|
||||
processedParents.insert( pParent );
|
||||
}
|
||||
}
|
||||
} // end loop over parent stack
|
||||
} // end chainable relations
|
||||
} // end PolymorphicVirtualCaster()
|
||||
|
||||
#undef CEREAL_EMPLACE_MAP
|
||||
|
||||
//! Performs the proper downcast with the templated types
|
||||
void const * downcast( void const * const ptr ) const override
|
||||
{
|
||||
return dynamic_cast<Derived const*>( static_cast<Base const*>( ptr ) );
|
||||
}
|
||||
|
||||
//! Performs the proper upcast with the templated types
|
||||
void * upcast( void * const ptr ) const override
|
||||
{
|
||||
return dynamic_cast<Base*>( static_cast<Derived*>( ptr ) );
|
||||
}
|
||||
|
||||
//! Performs the proper upcast with the templated types (shared_ptr version)
|
||||
std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const override
|
||||
{
|
||||
return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
|
||||
}
|
||||
};
|
||||
|
||||
//! Registers a polymorphic casting relation between a Base and Derived type
|
||||
/*! Registering a relation allows cereal to properly cast between the two types
|
||||
given runtime type information and void pointers.
|
||||
|
||||
Registration happens automatically via cereal::base_class and cereal::virtual_base_class
|
||||
instantiations. For cases where neither is called, see the CEREAL_REGISTER_POLYMORPHIC_RELATION
|
||||
macro */
|
||||
template <class Base, class Derived>
|
||||
struct RegisterPolymorphicCaster
|
||||
{
|
||||
static PolymorphicCaster const * bind( std::true_type /* is_polymorphic<Base> */)
|
||||
{
|
||||
return &StaticObject<PolymorphicVirtualCaster<Base, Derived>>::getInstance();
|
||||
}
|
||||
|
||||
static PolymorphicCaster const * bind( std::false_type /* is_polymorphic<Base> */ )
|
||||
{ return nullptr; }
|
||||
|
||||
//! Performs registration (binding) between Base and Derived
|
||||
/*! If the type is not polymorphic, nothing will happen */
|
||||
static PolymorphicCaster const * bind()
|
||||
{ return bind( typename std::is_polymorphic<Base>::type() ); }
|
||||
};
|
||||
}
|
||||
|
||||
/* General polymorphism support */
|
||||
namespace detail
|
||||
{
|
||||
//! Binds a compile time type with a user defined string
|
||||
@@ -87,9 +455,10 @@ namespace cereal
|
||||
//! A serializer function
|
||||
/*! Serializer functions return nothing and take an archive as
|
||||
their first parameter (will be cast properly inside the function,
|
||||
and a pointer to actual data (contents of smart_ptr's get() function)
|
||||
as their second parameter */
|
||||
typedef std::function<void(void*, void const *)> Serializer;
|
||||
a pointer to actual data (contents of smart_ptr's get() function)
|
||||
as their second parameter, and the type info of the owning smart_ptr
|
||||
as their final parameter */
|
||||
typedef std::function<void(void*, void const *, std::type_info const &)> Serializer;
|
||||
|
||||
//! Struct containing the serializer functions for all pointer types
|
||||
struct Serializers
|
||||
@@ -116,12 +485,12 @@ namespace cereal
|
||||
//! Shared ptr serializer function
|
||||
/*! Serializer functions return nothing and take an archive as
|
||||
their first parameter (will be cast properly inside the function,
|
||||
and a shared_ptr (or unique_ptr for the unique case) of any base
|
||||
type. Internally it will properly be loaded and cast to the
|
||||
correct type. */
|
||||
typedef std::function<void(void*, std::shared_ptr<void> & )> SharedSerializer;
|
||||
a shared_ptr (or unique_ptr for the unique case) of any base
|
||||
type, and the type id of said base type as the third parameter.
|
||||
Internally it will properly be loaded and cast to the correct type. */
|
||||
typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info const &)> SharedSerializer;
|
||||
//! Unique ptr serializer function
|
||||
typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> & )> UniqueSerializer;
|
||||
typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info const &)> UniqueSerializer;
|
||||
|
||||
//! Struct containing the serializer functions for all pointer types
|
||||
struct Serializers
|
||||
@@ -135,8 +504,8 @@ namespace cereal
|
||||
};
|
||||
|
||||
// forward decls for archives from cereal.hpp
|
||||
struct InputArchiveBase;
|
||||
struct OutputArchiveBase;
|
||||
class InputArchiveBase;
|
||||
class OutputArchiveBase;
|
||||
|
||||
//! Creates a binding (map entry) between an input archive type and a polymorphic type
|
||||
/*! Bindings are made when types are registered, assuming that at least one
|
||||
@@ -148,31 +517,39 @@ namespace cereal
|
||||
//! Initialize the binding
|
||||
InputBindingCreator()
|
||||
{
|
||||
auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
|
||||
auto lock = StaticObject<InputBindingMap<Archive>>::lock();
|
||||
auto key = std::string(binding_name<T>::name());
|
||||
auto lb = map.lower_bound(key);
|
||||
|
||||
if (lb != map.end() && lb->first == key)
|
||||
return;
|
||||
|
||||
typename InputBindingMap<Archive>::Serializers serializers;
|
||||
|
||||
serializers.shared_ptr =
|
||||
[](void * arptr, std::shared_ptr<void> & dptr)
|
||||
[](void * arptr, std::shared_ptr<void> & dptr, std::type_info const & baseInfo)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
std::shared_ptr<T> ptr;
|
||||
|
||||
ar( ::cereal::memory_detail::make_ptr_wrapper(ptr) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
dptr = ptr;
|
||||
dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
|
||||
};
|
||||
|
||||
serializers.unique_ptr =
|
||||
[](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr)
|
||||
[](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info const & baseInfo)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
std::unique_ptr<T> ptr;
|
||||
|
||||
ar( ::cereal::memory_detail::make_ptr_wrapper(ptr) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
dptr.reset(ptr.release());
|
||||
dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
|
||||
};
|
||||
|
||||
StaticObject<InputBindingMap<Archive>>::getInstance().map.insert( { std::string(binding_name<T>::name()), serializers } );
|
||||
map.insert( lb, { std::move(key), std::move(serializers) } );
|
||||
}
|
||||
};
|
||||
|
||||
@@ -191,46 +568,111 @@ namespace cereal
|
||||
std::uint32_t id = ar.registerPolymorphicType(name);
|
||||
|
||||
// Serialize the id
|
||||
ar( _CEREAL_NVP("polymorphic_id", id) );
|
||||
ar( CEREAL_NVP_("polymorphic_id", id) );
|
||||
|
||||
// If the msb of the id is 1, then the type name is new, and we should serialize it
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
std::string namestring(name);
|
||||
ar( _CEREAL_NVP("polymorphic_name", namestring) );
|
||||
ar( CEREAL_NVP_("polymorphic_name", namestring) );
|
||||
}
|
||||
}
|
||||
|
||||
//! Holds a properly typed shared_ptr to the polymorphic type
|
||||
class PolymorphicSharedPointerWrapper
|
||||
{
|
||||
public:
|
||||
/*! Wrap a raw polymorphic pointer in a shared_ptr to its true type
|
||||
|
||||
The wrapped pointer will not be responsible for ownership of the held pointer
|
||||
so it will not attempt to destroy it; instead the refcount of the wrapped
|
||||
pointer will be tied to a fake 'ownership pointer' that will do nothing
|
||||
when it ultimately goes out of scope.
|
||||
|
||||
The main reason for doing this, other than not to destroy the true object
|
||||
with our wrapper pointer, is to avoid meddling with the internal reference
|
||||
count in a polymorphic type that inherits from std::enable_shared_from_this.
|
||||
|
||||
@param dptr A void pointer to the contents of the shared_ptr to serialize */
|
||||
PolymorphicSharedPointerWrapper( T const * dptr ) : refCount(), wrappedPtr( refCount, dptr )
|
||||
{ }
|
||||
|
||||
//! Get the wrapped shared_ptr */
|
||||
inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<void> refCount; //!< The ownership pointer
|
||||
std::shared_ptr<T const> wrappedPtr; //!< The wrapped pointer
|
||||
};
|
||||
|
||||
//! Does the actual work of saving a polymorphic shared_ptr
|
||||
/*! This function will properly create a shared_ptr from the void * that is passed in
|
||||
before passing it to the archive for serialization.
|
||||
|
||||
In addition, this will also preserve the state of any internal enable_shared_from_this mechanisms
|
||||
|
||||
@param ar The archive to serialize to
|
||||
@param dptr Pointer to the actual data held by the shared_ptr */
|
||||
static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::true_type /* has_shared_from_this */ )
|
||||
{
|
||||
::cereal::memory_detail::EnableSharedStateHelper<T> state( const_cast<T *>(dptr) );
|
||||
PolymorphicSharedPointerWrapper psptr( dptr );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
|
||||
}
|
||||
|
||||
//! Does the actual work of saving a polymorphic shared_ptr
|
||||
/*! This function will properly create a shared_ptr from the void * that is passed in
|
||||
before passing it to the archive for serialization.
|
||||
|
||||
This version is for types that do not inherit from std::enable_shared_from_this.
|
||||
|
||||
@param ar The archive to serialize to
|
||||
@param dptr Pointer to the actual data held by the shared_ptr */
|
||||
static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::false_type /* has_shared_from_this */ )
|
||||
{
|
||||
PolymorphicSharedPointerWrapper psptr( dptr );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
|
||||
}
|
||||
|
||||
//! Initialize the binding
|
||||
OutputBindingCreator()
|
||||
{
|
||||
auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
|
||||
auto key = std::type_index(typeid(T));
|
||||
auto lb = map.lower_bound(key);
|
||||
|
||||
if (lb != map.end() && lb->first == key)
|
||||
return;
|
||||
|
||||
typename OutputBindingMap<Archive>::Serializers serializers;
|
||||
|
||||
serializers.shared_ptr =
|
||||
[&](void * arptr, void const * dptr)
|
||||
[&](void * arptr, void const * dptr, std::type_info const & baseInfo)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
|
||||
writeMetadata(ar);
|
||||
|
||||
std::shared_ptr<T const> const ptr(static_cast<T const *>(dptr), EmptyDeleter<T const>());
|
||||
auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
|
||||
|
||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
#ifdef _MSC_VER
|
||||
savePolymorphicSharedPtr( ar, ptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
|
||||
#else // not _MSC_VER
|
||||
savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
serializers.unique_ptr =
|
||||
[&](void * arptr, void const * dptr)
|
||||
[&](void * arptr, void const * dptr, std::type_info const & baseInfo)
|
||||
{
|
||||
Archive & ar = *static_cast<Archive*>(arptr);
|
||||
|
||||
writeMetadata(ar);
|
||||
|
||||
std::unique_ptr<T const, EmptyDeleter<T const>> const ptr(static_cast<T const *>(dptr));
|
||||
std::unique_ptr<T const, EmptyDeleter<T const>> const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
|
||||
|
||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
};
|
||||
|
||||
StaticObject<OutputBindingMap<Archive>>::getInstance().map.insert( {std::type_index(typeid(T)), serializers} );
|
||||
map.insert( { std::move(key), std::move(serializers) } );
|
||||
}
|
||||
};
|
||||
|
||||
@@ -238,24 +680,28 @@ namespace cereal
|
||||
//! of instantiate_polymorphic_binding
|
||||
struct adl_tag {};
|
||||
|
||||
//! Tag for init_binding, bind_to_archives and instantiate_polymorphic_binding. Due to the use of anonymous
|
||||
//! namespace it becomes a different type in each translation unit.
|
||||
namespace { struct polymorphic_binding_tag {}; }
|
||||
|
||||
//! Causes the static object bindings between an archive type and a serializable type T
|
||||
template <class Archive, class T>
|
||||
struct create_bindings
|
||||
{
|
||||
static const InputBindingCreator<Archive, T> &
|
||||
load(std::true_type)
|
||||
{
|
||||
return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
|
||||
}
|
||||
static const InputBindingCreator<Archive, T> &
|
||||
load(std::true_type)
|
||||
{
|
||||
return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
|
||||
}
|
||||
|
||||
static const OutputBindingCreator<Archive, T> &
|
||||
save(std::true_type)
|
||||
{
|
||||
return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
|
||||
}
|
||||
static const OutputBindingCreator<Archive, T> &
|
||||
save(std::true_type)
|
||||
{
|
||||
return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
|
||||
}
|
||||
|
||||
inline static void load(std::false_type) {}
|
||||
inline static void save(std::false_type) {}
|
||||
inline static void load(std::false_type) {}
|
||||
inline static void save(std::false_type) {}
|
||||
};
|
||||
|
||||
//! When specialized, causes the compiler to instantiate its parameter
|
||||
@@ -270,20 +716,30 @@ namespace cereal
|
||||
template <class Archive, class T>
|
||||
struct polymorphic_serialization_support
|
||||
{
|
||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
||||
//! Creates the appropriate bindings depending on whether the archive supports
|
||||
//! saving or loading
|
||||
static void instantiate();
|
||||
virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
|
||||
#else // NOT _MSC_VER
|
||||
//! Creates the appropriate bindings depending on whether the archive supports
|
||||
//! saving or loading
|
||||
static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
|
||||
//! This typedef causes the compiler to instantiate this static function
|
||||
typedef instantiate_function<instantiate> unused;
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
// instantiate implementation
|
||||
template <class Archive, class T>
|
||||
void polymorphic_serialization_support<Archive,T>::instantiate()
|
||||
CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
|
||||
{
|
||||
create_bindings<Archive,T>::save( std::is_base_of<detail::OutputArchiveBase, Archive>() );
|
||||
create_bindings<Archive,T>::save( std::integral_constant<bool,
|
||||
std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
|
||||
traits::is_output_serializable<T, Archive>::value>{} );
|
||||
|
||||
create_bindings<Archive,T>::load( std::is_base_of<detail::InputArchiveBase, Archive>() );
|
||||
create_bindings<Archive,T>::load( std::integral_constant<bool,
|
||||
std::is_base_of<detail::InputArchiveBase, Archive>::value &&
|
||||
traits::is_input_serializable<T, Archive>::value>{} );
|
||||
}
|
||||
|
||||
//! Begins the binding process of a type to all registered archives
|
||||
@@ -291,13 +747,13 @@ namespace cereal
|
||||
the CEREAL_REGISTER_ARCHIVE macro. Overload resolution will then force
|
||||
several static objects to be made that allow us to bind together all
|
||||
registered archive types with the parameter type T. */
|
||||
template <class T>
|
||||
template <class T, class Tag = polymorphic_binding_tag>
|
||||
struct bind_to_archives
|
||||
{
|
||||
//! Binding for non abstract types
|
||||
void bind(std::false_type) const
|
||||
{
|
||||
instantiate_polymorphic_binding( (T*)0, 0, adl_tag{} );
|
||||
instantiate_polymorphic_binding(static_cast<T*>(nullptr), 0, Tag{}, adl_tag{});
|
||||
}
|
||||
|
||||
//! Binding for abstract types
|
||||
@@ -309,13 +765,15 @@ namespace cereal
|
||||
do not need to make a binding */
|
||||
bind_to_archives const & bind() const
|
||||
{
|
||||
static_assert( std::is_polymorphic<T>::value,
|
||||
"Attempting to register non polymorphic type" );
|
||||
bind( std::is_abstract<T>() );
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
//! Used to hide the static object used to bind T to registered archives
|
||||
template <class T>
|
||||
template <class T, class Tag = polymorphic_binding_tag>
|
||||
struct init_binding;
|
||||
|
||||
//! Base case overload for instantiation
|
||||
@@ -330,8 +788,8 @@ namespace cereal
|
||||
mechanisms even though they are never called.
|
||||
|
||||
See the documentation for the other functions to try and understand this */
|
||||
template <class T>
|
||||
void instantiate_polymorphic_binding( T*, int, adl_tag ) {};
|
||||
template <class T, typename BindingTag>
|
||||
void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*! \file polymorphic_impl_fwd.hpp
|
||||
\brief Internal polymorphism support forward declarations
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* This code is heavily inspired by the boost serialization implementation by the following authors
|
||||
|
||||
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
(C) Copyright 2006 David Abrahams - http://www.boost.org.
|
||||
|
||||
See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for their
|
||||
implementation.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
|
||||
#define CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//! Forward declaration, see polymorphic_impl.hpp for more information
|
||||
template <class Base, class Derived>
|
||||
struct RegisterPolymorphicCaster;
|
||||
|
||||
//! Forward declaration, see polymorphic_impl.hpp for more information
|
||||
struct PolymorphicCasters;
|
||||
|
||||
//! Forward declaration, see polymorphic_impl.hpp for more information
|
||||
template <class Base, class Derived>
|
||||
struct PolymorphicRelation;
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
|
||||
@@ -2,9 +2,8 @@
|
||||
\brief Internal polymorphism static object support
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
@@ -15,7 +14,6 @@
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -30,6 +28,30 @@
|
||||
#ifndef CEREAL_DETAILS_STATIC_OBJECT_HPP_
|
||||
#define CEREAL_DETAILS_STATIC_OBJECT_HPP_
|
||||
|
||||
#include "cereal/macros.hpp"
|
||||
|
||||
#if CEREAL_THREAD_SAFE
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
//! Prevent link optimization from removing non-referenced static objects
|
||||
/*! Especially for polymorphic support, we create static objects which
|
||||
may not ever be explicitly referenced. Most linkers will detect this
|
||||
and remove the code causing various unpleasant runtime errors. These
|
||||
macros, adopted from Boost (see force_include.hpp) prevent this
|
||||
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||
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) */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define CEREAL_DLL_EXPORT __declspec(dllexport)
|
||||
# define CEREAL_USED
|
||||
#else // clang or gcc
|
||||
# define CEREAL_DLL_EXPORT __attribute__ ((visibility("default")))
|
||||
# define CEREAL_USED __attribute__ ((__used__))
|
||||
#endif
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace detail
|
||||
@@ -38,25 +60,23 @@ namespace cereal
|
||||
/*! This class will create a single copy (singleton) of some
|
||||
type and ensures that merely referencing this type will
|
||||
cause it to be instantiated and initialized pre-execution.
|
||||
|
||||
For example, this is used heavily in the polymorphic pointer
|
||||
serialization mechanisms to bind various archive types with
|
||||
different polymorphic classes */
|
||||
template <class T>
|
||||
class StaticObject
|
||||
class CEREAL_DLL_EXPORT StaticObject
|
||||
{
|
||||
private:
|
||||
//! Forces instantiation at pre-execution time
|
||||
static void instantiate(T const &) {}
|
||||
|
||||
static T & create()
|
||||
{
|
||||
static T t;
|
||||
instantiate(instance);
|
||||
//! Forces instantiation at pre-execution time
|
||||
(void)instance;
|
||||
return t;
|
||||
}
|
||||
|
||||
StaticObject( StaticObject const & other ) = delete;
|
||||
StaticObject( StaticObject const & /*other*/ ) {}
|
||||
|
||||
public:
|
||||
static T & getInstance()
|
||||
@@ -64,12 +84,44 @@ namespace cereal
|
||||
return create();
|
||||
}
|
||||
|
||||
//! A class that acts like std::lock_guard
|
||||
class LockGuard
|
||||
{
|
||||
#if CEREAL_THREAD_SAFE
|
||||
public:
|
||||
LockGuard(std::mutex & m) : lock(m) {}
|
||||
private:
|
||||
std::unique_lock<std::mutex> lock;
|
||||
#else
|
||||
public:
|
||||
LockGuard(LockGuard const &) = default; // prevents implicit copy ctor warning
|
||||
~LockGuard() CEREAL_NOEXCEPT {} // prevents variable not used
|
||||
#endif
|
||||
};
|
||||
|
||||
//! Attempts to lock this static object for the current scope
|
||||
/*! @note This function is a no-op if cereal is not compiled with
|
||||
thread safety enabled (CEREAL_THREAD_SAFE = 1).
|
||||
|
||||
This function returns an object that holds a lock for
|
||||
this StaticObject that will release its lock upon destruction. This
|
||||
call will block until the lock is available. */
|
||||
static LockGuard lock()
|
||||
{
|
||||
#if CEREAL_THREAD_SAFE
|
||||
static std::mutex instanceMutex;
|
||||
return LockGuard{instanceMutex};
|
||||
#else
|
||||
return LockGuard{};
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
static T & instance;
|
||||
};
|
||||
|
||||
template <class T> T & StaticObject<T>::instance = StaticObject<T>::create();
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_
|
||||
|
||||
+1222
-223
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
\brief Internal misc utilities
|
||||
\ingroup Internal */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -31,9 +31,28 @@
|
||||
#define CEREAL_DETAILS_UTIL_HPP_
|
||||
|
||||
#include <typeinfo>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
namespace cereal
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
//! Demangles the type encoded in a string
|
||||
/*! @internal */
|
||||
inline std::string demangle( std::string const & name )
|
||||
{ return name; }
|
||||
|
||||
//! Gets the demangled name of a type
|
||||
/*! @internal */
|
||||
template <class T> inline
|
||||
std::string demangledName()
|
||||
{ return typeid( T ).name(); }
|
||||
} // namespace util
|
||||
} // namespace cereal
|
||||
#else // clang or gcc
|
||||
#include <cxxabi.h>
|
||||
#include <cstdlib>
|
||||
namespace cereal
|
||||
{
|
||||
namespace util
|
||||
@@ -43,7 +62,7 @@ namespace cereal
|
||||
inline std::string demangle(std::string mangledName)
|
||||
{
|
||||
int status = 0;
|
||||
char *demangledName = NULL;
|
||||
char *demangledName = nullptr;
|
||||
std::size_t len;
|
||||
|
||||
demangledName = abi::__cxa_demangle(mangledName.c_str(), 0, &len, &status);
|
||||
@@ -57,9 +76,9 @@ namespace cereal
|
||||
//! Gets the demangled name of a type
|
||||
/*! @internal */
|
||||
template<class T> inline
|
||||
std::string demangledName()
|
||||
{ return demangle(typeid(T).name()); }
|
||||
std::string demangledName()
|
||||
{ return demangle(typeid(T).name()); }
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cereal
|
||||
#endif // clang or gcc branch of _MSC_VER
|
||||
#endif // CEREAL_DETAILS_UTIL_HPP_
|
||||
|
||||
Vendored
+79
-71
@@ -25,102 +25,110 @@
|
||||
#ifndef CEREAL_EXTERNAL_BASE64_HPP_
|
||||
#define CEREAL_EXTERNAL_BASE64_HPP_
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace base64
|
||||
namespace cereal
|
||||
{
|
||||
static const std::string chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
namespace base64
|
||||
{
|
||||
static const std::string chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
inline std::string encode(unsigned char const* bytes_to_encode, size_t in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
inline std::string encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = static_cast<unsigned char>((char_array_3[0] & 0xfc) >> 2);
|
||||
char_array_4[1] = static_cast<unsigned char>( ( ( char_array_3[0] & 0x03 ) << 4 ) + ( ( char_array_3[1] & 0xf0 ) >> 4 ) );
|
||||
char_array_4[2] = static_cast<unsigned char>( ( ( char_array_3[1] & 0x0f ) << 2 ) + ( ( char_array_3[2] & 0xc0 ) >> 6 ) );
|
||||
char_array_4[3] = static_cast<unsigned char>( char_array_3[2] & 0x3f );
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += chars[char_array_4[i]];
|
||||
i = 0;
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
inline std::string decode(std::string const& encoded_string) {
|
||||
size_t in_len = encoded_string.size();
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = static_cast<unsigned char>(chars.find( char_array_4[i] ));
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += chars[char_array_4[j]];
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
inline std::string decode(std::string const& encoded_string) {
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = chars.find(char_array_4[i]);
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = static_cast<unsigned char>(chars.find( char_array_4[j] ));
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = chars.find(char_array_4[j]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // base64
|
||||
} // namespace base64
|
||||
} // namespace cereal
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif // CEREAL_EXTERNAL_BASE64_HPP_
|
||||
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ALLOCATORS_H_
|
||||
#define CEREAL_RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
/*! \class rapidjson::Allocator
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
|
||||
/*! \def CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
|
||||
\ingroup CEREAL_RAPIDJSON_CONFIG
|
||||
\brief User-defined kDefaultChunkCapacity definition.
|
||||
|
||||
User can define this as any \c size that is a power of 2.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
|
||||
#define CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) {
|
||||
if (size) // behavior of malloc(0) is implementation defined.
|
||||
return std::malloc(size);
|
||||
else
|
||||
return NULL; // standardize to returning NULL.
|
||||
}
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
(void)originalSize;
|
||||
if (newSize == 0) {
|
||||
std::free(originalPtr);
|
||||
return NULL;
|
||||
}
|
||||
return std::realloc(originalPtr, newSize);
|
||||
}
|
||||
static void Free(void *ptr) { std::free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
The user-buffer is not deallocated by this allocator.
|
||||
|
||||
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
CEREAL_RAPIDJSON_ASSERT(buffer != 0);
|
||||
CEREAL_RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
CEREAL_RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||
chunkHead_->size = 0; // Clear user buffer
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
size = CEREAL_RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
|
||||
return NULL;
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_) + CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
|
||||
chunkHead_->size += size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//! Resizes a memory block (concept Allocator)
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
if (newSize == 0)
|
||||
return NULL;
|
||||
|
||||
originalSize = CEREAL_RAPIDJSON_ALIGN(originalSize);
|
||||
newSize = CEREAL_RAPIDJSON_ALIGN(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
if (void* newBuffer = Malloc(newSize)) {
|
||||
if (originalSize)
|
||||
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||
return newBuffer;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
\return true if success.
|
||||
*/
|
||||
bool AddChunk(size_t capacity) {
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = CEREAL_RAPIDJSON_NEW(BaseAllocator)();
|
||||
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_ENCODINGS_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_CURSORSTREAMWRAPPER_H_
|
||||
#define CEREAL_RAPIDJSON_CURSORSTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
//! Cursor stream wrapper for counting line and column number if error exists.
|
||||
/*!
|
||||
\tparam InputStream Any stream that implements Stream Concept
|
||||
*/
|
||||
template <typename InputStream, typename Encoding = UTF8<> >
|
||||
class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
CursorStreamWrapper(InputStream& is):
|
||||
GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
|
||||
|
||||
// counting line and column number
|
||||
Ch Take() {
|
||||
Ch ch = this->is_.Take();
|
||||
if(ch == '\n') {
|
||||
line_ ++;
|
||||
col_ = 0;
|
||||
} else {
|
||||
col_ ++;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
//! Get the error line number, if error exists.
|
||||
size_t GetLine() const { return line_; }
|
||||
//! Get the error column number, if error exists.
|
||||
size_t GetColumn() const { return col_; }
|
||||
|
||||
private:
|
||||
size_t line_; //!< Current Line
|
||||
size_t col_; //!< Current Column
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_CURSORSTREAMWRAPPER_H_
|
||||
+2587
-756
File diff suppressed because it is too large
Load Diff
+299
@@ -0,0 +1,299 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ENCODEDSTREAM_H_
|
||||
#define CEREAL_RAPIDJSON_ENCODEDSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "memorystream.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Input byte stream wrapper with a statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
|
||||
*/
|
||||
template <typename Encoding, typename InputByteStream>
|
||||
class EncodedInputStream {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedInputStream(InputByteStream& is) : is_(is) {
|
||||
current_ = Encoding::TakeBOM(is_);
|
||||
}
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedInputStream(const EncodedInputStream&);
|
||||
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||
|
||||
InputByteStream& is_;
|
||||
Ch current_;
|
||||
};
|
||||
|
||||
//! Specialized for UTF8 MemoryStream.
|
||||
template <>
|
||||
class EncodedInputStream<UTF8<>, MemoryStream> {
|
||||
public:
|
||||
typedef UTF8<>::Ch Ch;
|
||||
|
||||
EncodedInputStream(MemoryStream& is) : is_(is) {
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
|
||||
}
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) {}
|
||||
void Flush() {}
|
||||
Ch* PutBegin() { return 0; }
|
||||
size_t PutEnd(Ch*) { return 0; }
|
||||
|
||||
MemoryStream& is_;
|
||||
|
||||
private:
|
||||
EncodedInputStream(const EncodedInputStream&);
|
||||
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||
};
|
||||
|
||||
//! Output byte stream wrapper with statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
class EncodedOutputStream {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
|
||||
if (putBOM)
|
||||
Encoding::PutBOM(os_);
|
||||
}
|
||||
|
||||
void Put(Ch c) { Encoding::Put(os_, c); }
|
||||
void Flush() { os_.Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedOutputStream(const EncodedOutputStream&);
|
||||
EncodedOutputStream& operator=(const EncodedOutputStream&);
|
||||
|
||||
OutputByteStream& os_;
|
||||
};
|
||||
|
||||
#define CEREAL_RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for reading.
|
||||
\tparam InputByteStream type of input byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename InputByteStream>
|
||||
class AutoUTFInputStream {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
CEREAL_RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
|
||||
if (!hasBOM_) {
|
||||
int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
}
|
||||
|
||||
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||
InputByteStream* is_;
|
||||
UTFType type_;
|
||||
Ch current_;
|
||||
TakeFunc takeFunc_;
|
||||
bool hasBOM_;
|
||||
};
|
||||
|
||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for writing.
|
||||
\tparam OutputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
class AutoUTFOutputStream {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
CEREAL_RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
static const PutFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
};
|
||||
|
||||
#undef CEREAL_RAPIDJSON_ENCODINGS_FUNC
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_FILESTREAM_H_
|
||||
+716
@@ -0,0 +1,716 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ENCODINGS_H_
|
||||
#define CEREAL_RAPIDJSON_ENCODINGS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#elif defined(__GNUC__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(overflow)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encoding
|
||||
|
||||
/*! \class rapidjson::Encoding
|
||||
\brief Concept for encoding of Unicode characters.
|
||||
|
||||
\code
|
||||
concept Encoding {
|
||||
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
||||
|
||||
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
||||
|
||||
//! \brief Encode a Unicode codepoint to an output stream.
|
||||
//! \param os Output stream.
|
||||
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint);
|
||||
|
||||
//! \brief Decode a Unicode codepoint from an input stream.
|
||||
//! \param is Input stream.
|
||||
//! \param codepoint Output of the unicode codepoint.
|
||||
//! \return true if a valid codepoint can be decoded from the stream.
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint);
|
||||
|
||||
//! \brief Validate one Unicode codepoint from an encoded stream.
|
||||
//! \param is Input stream to obtain codepoint.
|
||||
//! \param os Output for copying one codepoint.
|
||||
//! \return true if it is valid.
|
||||
//! \note This function just validating and copying the codepoint without actually decode it.
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os);
|
||||
|
||||
// The following functions are deal with byte streams.
|
||||
|
||||
//! Take a character from input byte stream, skip BOM if exist.
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is);
|
||||
|
||||
//! Take a character from input byte stream.
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is);
|
||||
|
||||
//! Put BOM to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os);
|
||||
|
||||
//! Put a character to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF8
|
||||
|
||||
//! UTF-8 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||
http://tools.ietf.org/html/rfc3629
|
||||
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct UTF8 {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
#define CEREAL_RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||
#define CEREAL_RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define CEREAL_RAPIDJSON_TAIL() CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x70)
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (!(c & 0x80)) {
|
||||
*codepoint = static_cast<unsigned char>(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char type = GetRange(static_cast<unsigned char>(c));
|
||||
if (type >= 32) {
|
||||
*codepoint = 0;
|
||||
} else {
|
||||
*codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
|
||||
}
|
||||
bool result = true;
|
||||
switch (type) {
|
||||
case 2: CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 3: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 4: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x50); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 5: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x10); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 6: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 10: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x20); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 11: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x60); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef CEREAL_RAPIDJSON_COPY
|
||||
#undef CEREAL_RAPIDJSON_TRANS
|
||||
#undef CEREAL_RAPIDJSON_TAIL
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
#define CEREAL_RAPIDJSON_COPY() os.Put(c = is.Take())
|
||||
#define CEREAL_RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define CEREAL_RAPIDJSON_TAIL() CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x70)
|
||||
Ch c;
|
||||
CEREAL_RAPIDJSON_COPY();
|
||||
if (!(c & 0x80))
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||
case 2: CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 3: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 4: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x50); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 5: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x10); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 6: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 10: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x20); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
case 11: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x60); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef CEREAL_RAPIDJSON_COPY
|
||||
#undef CEREAL_RAPIDJSON_TRANS
|
||||
#undef CEREAL_RAPIDJSON_TAIL
|
||||
}
|
||||
|
||||
static unsigned char GetRange(unsigned char c) {
|
||||
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
||||
static const unsigned char type[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
};
|
||||
return type[c];
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
typename InputByteStream::Ch c = Take(is);
|
||||
if (static_cast<unsigned char>(c) != 0xEFu) return c;
|
||||
c = is.Take();
|
||||
if (static_cast<unsigned char>(c) != 0xBBu) return c;
|
||||
c = is.Take();
|
||||
if (static_cast<unsigned char>(c) != 0xBFu) return c;
|
||||
c = is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF16
|
||||
|
||||
//! UTF-16 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||
http://tools.ietf.org/html/rfc2781
|
||||
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16 {
|
||||
typedef CharType Ch;
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
if (codepoint <= 0xFFFF) {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
if (codepoint <= 0xFFFF) {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (c < 0xD800 || c > 0xDFFF) {
|
||||
*codepoint = static_cast<unsigned>(c);
|
||||
return true;
|
||||
}
|
||||
else if (c <= 0xDBFF) {
|
||||
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
|
||||
c = is.Take();
|
||||
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
|
||||
*codepoint += 0x10000;
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
typename InputStream::Ch c;
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
|
||||
if (c < 0xD800 || c > 0xDFFF)
|
||||
return true;
|
||||
else if (c <= 0xDBFF) {
|
||||
os.Put(c = is.Take());
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 little endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16LE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 big endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16BE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF32
|
||||
|
||||
//! UTF-32 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32 {
|
||||
typedef CharType Ch;
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(codepoint);
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
PutUnsafe(os, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c = is.Take();
|
||||
*codepoint = c;
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c;
|
||||
os.Put(c = is.Take());
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 little endian enocoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32LE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 big endian encoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32BE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ASCII
|
||||
|
||||
//! ASCII encoding.
|
||||
/*! http://en.wikipedia.org/wiki/ASCII
|
||||
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct ASCII {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 0 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
*codepoint = c;
|
||||
return c <= 0X7F;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c));
|
||||
return c <= 0x7F;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
uint8_t c = static_cast<uint8_t>(Take(is));
|
||||
return static_cast<Ch>(c);
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
(void)os;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AutoUTF
|
||||
|
||||
//! Runtime-specified UTF encoding type of a stream.
|
||||
enum UTFType {
|
||||
kUTF8 = 0, //!< UTF-8.
|
||||
kUTF16LE = 1, //!< UTF-16 little endian.
|
||||
kUTF16BE = 2, //!< UTF-16 big endian.
|
||||
kUTF32LE = 3, //!< UTF-32 little endian.
|
||||
kUTF32BE = 4 //!< UTF-32 big endian.
|
||||
};
|
||||
|
||||
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
||||
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
||||
*/
|
||||
template<typename CharType>
|
||||
struct AutoUTF {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
#define CEREAL_RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
template<typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
|
||||
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||
static const EncodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
||||
(*f[os.GetType()])(os, codepoint);
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||
static const EncodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
|
||||
(*f[os.GetType()])(os, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||
static const DecodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
||||
return (*f[is.GetType()])(is, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
|
||||
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
||||
static const ValidateFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
||||
return (*f[is.GetType()])(is, os);
|
||||
}
|
||||
|
||||
#undef CEREAL_RAPIDJSON_ENCODINGS_FUNC
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Transcoder
|
||||
|
||||
//! Encoding conversion.
|
||||
template<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder {
|
||||
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::Encode(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::EncodeUnsafe(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Validate one Unicode codepoint from an encoded stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||
}
|
||||
};
|
||||
|
||||
// Forward declaration.
|
||||
template<typename Stream>
|
||||
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
|
||||
|
||||
//! Specialization of Transcoder with same source and target encoding.
|
||||
template<typename Encoding>
|
||||
struct Transcoder<Encoding, Encoding> {
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
|
||||
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static CEREAL_RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||
}
|
||||
};
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_ENCODINGS_H_
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ERROR_EN_H_
|
||||
#define CEREAL_RAPIDJSON_ERROR_EN_H_
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(covered-switch-default)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Maps error code of parsing into error message.
|
||||
/*!
|
||||
\ingroup CEREAL_RAPIDJSON_ERRORS
|
||||
\param parseErrorCode Error code obtained in parsing.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
*/
|
||||
inline const CEREAL_RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||
switch (parseErrorCode) {
|
||||
case kParseErrorNone: return CEREAL_RAPIDJSON_ERROR_STRING("No error.");
|
||||
|
||||
case kParseErrorDocumentEmpty: return CEREAL_RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||
case kParseErrorDocumentRootNotSingular: return CEREAL_RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
|
||||
|
||||
case kParseErrorValueInvalid: return CEREAL_RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||
|
||||
case kParseErrorObjectMissName: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||
case kParseErrorObjectMissColon: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||
case kParseErrorObjectMissCommaOrCurlyBracket: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||
|
||||
case kParseErrorArrayMissCommaOrSquareBracket: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||
|
||||
case kParseErrorStringUnicodeEscapeInvalidHex: return CEREAL_RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||
case kParseErrorStringUnicodeSurrogateInvalid: return CEREAL_RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||
case kParseErrorStringEscapeInvalid: return CEREAL_RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||
case kParseErrorStringMissQuotationMark: return CEREAL_RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||
case kParseErrorStringInvalidEncoding: return CEREAL_RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||
|
||||
case kParseErrorNumberTooBig: return CEREAL_RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||
case kParseErrorNumberMissFraction: return CEREAL_RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||
case kParseErrorNumberMissExponent: return CEREAL_RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||
|
||||
case kParseErrorTermination: return CEREAL_RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||
case kParseErrorUnspecificSyntaxError: return CEREAL_RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||
|
||||
default: return CEREAL_RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_ERROR_EN_H_
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ERROR_ERROR_H_
|
||||
#define CEREAL_RAPIDJSON_ERROR_ERROR_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
/*! \file error.h */
|
||||
|
||||
/*! \defgroup CEREAL_RAPIDJSON_ERRORS RapidJSON error handling */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CEREAL_RAPIDJSON_ERROR_CHARTYPE
|
||||
|
||||
//! Character type of error messages.
|
||||
/*! \ingroup CEREAL_RAPIDJSON_ERRORS
|
||||
The default character type is \c char.
|
||||
On Windows, user can define this macro as \c TCHAR for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef CEREAL_RAPIDJSON_ERROR_CHARTYPE
|
||||
#define CEREAL_RAPIDJSON_ERROR_CHARTYPE char
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CEREAL_RAPIDJSON_ERROR_STRING
|
||||
|
||||
//! Macro for converting string literial to \ref CEREAL_RAPIDJSON_ERROR_CHARTYPE[].
|
||||
/*! \ingroup CEREAL_RAPIDJSON_ERRORS
|
||||
By default this conversion macro does nothing.
|
||||
On Windows, user can define this macro as \c _T(x) for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef CEREAL_RAPIDJSON_ERROR_STRING
|
||||
#define CEREAL_RAPIDJSON_ERROR_STRING(x) x
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ParseErrorCode
|
||||
|
||||
//! Error code of parsing.
|
||||
/*! \ingroup CEREAL_RAPIDJSON_ERRORS
|
||||
\see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||
*/
|
||||
enum ParseErrorCode {
|
||||
kParseErrorNone = 0, //!< No error.
|
||||
|
||||
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
|
||||
|
||||
kParseErrorValueInvalid, //!< Invalid value.
|
||||
|
||||
kParseErrorObjectMissName, //!< Missing a name for object member.
|
||||
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
|
||||
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
|
||||
|
||||
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
|
||||
|
||||
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
|
||||
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
|
||||
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
|
||||
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
|
||||
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
|
||||
|
||||
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||
|
||||
kParseErrorTermination, //!< Parsing was terminated.
|
||||
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
|
||||
};
|
||||
|
||||
//! Result of parsing (wraps ParseErrorCode)
|
||||
/*!
|
||||
\ingroup CEREAL_RAPIDJSON_ERRORS
|
||||
\code
|
||||
Document doc;
|
||||
ParseResult ok = doc.Parse("[42]");
|
||||
if (!ok) {
|
||||
fprintf(stderr, "JSON parse error: %s (%u)",
|
||||
GetParseError_En(ok.Code()), ok.Offset());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
\endcode
|
||||
\see GenericReader::Parse, GenericDocument::Parse
|
||||
*/
|
||||
struct ParseResult {
|
||||
//!! Unspecified boolean type
|
||||
typedef bool (ParseResult::*BooleanType)() const;
|
||||
public:
|
||||
//! Default constructor, no error.
|
||||
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||
//! Constructor to set an error.
|
||||
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
|
||||
|
||||
//! Get the error code.
|
||||
ParseErrorCode Code() const { return code_; }
|
||||
//! Get the error offset, if \ref IsError(), 0 otherwise.
|
||||
size_t Offset() const { return offset_; }
|
||||
|
||||
//! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||
operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
|
||||
//! Whether the result is an error.
|
||||
bool IsError() const { return code_ != kParseErrorNone; }
|
||||
|
||||
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
|
||||
bool operator==(ParseErrorCode code) const { return code_ == code; }
|
||||
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
|
||||
|
||||
bool operator!=(const ParseResult& that) const { return !(*this == that); }
|
||||
bool operator!=(ParseErrorCode code) const { return !(*this == code); }
|
||||
friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
|
||||
|
||||
//! Reset error code.
|
||||
void Clear() { Set(kParseErrorNone); }
|
||||
//! Update error code and offset.
|
||||
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
|
||||
|
||||
private:
|
||||
ParseErrorCode code_;
|
||||
size_t offset_;
|
||||
};
|
||||
|
||||
//! Function pointer type of GetParseError().
|
||||
/*! \ingroup CEREAL_RAPIDJSON_ERRORS
|
||||
|
||||
This is the prototype for \c GetParseError_X(), where \c X is a locale.
|
||||
User can dynamically change locale in runtime, e.g.:
|
||||
\code
|
||||
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||
const CEREAL_RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||
\endcode
|
||||
*/
|
||||
typedef const CEREAL_RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_ERROR_ERROR_H_
|
||||
@@ -0,0 +1,99 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_FILEREADSTREAM_H_
|
||||
#define CEREAL_RAPIDJSON_FILEREADSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! File byte stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileReadStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type (byte).
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param fp File pointer opened for read.
|
||||
\param buffer user-supplied buffer.
|
||||
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||
*/
|
||||
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
CEREAL_RAPIDJSON_ASSERT(fp_ != 0);
|
||||
CEREAL_RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||
Read();
|
||||
}
|
||||
|
||||
Ch Peek() const { return *current_; }
|
||||
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void Read() {
|
||||
if (current_ < bufferLast_)
|
||||
++current_;
|
||||
else if (!eof_) {
|
||||
count_ += readCount_;
|
||||
readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
|
||||
bufferLast_ = buffer_ + readCount_ - 1;
|
||||
current_ = buffer_;
|
||||
|
||||
if (readCount_ < bufferSize_) {
|
||||
buffer_[readCount_] = '\0';
|
||||
++bufferLast_;
|
||||
eof_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::FILE* fp_;
|
||||
Ch *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_FILESTREAM_H_
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
#ifndef RAPIDJSON_FILESTREAM_H_
|
||||
#define RAPIDJSON_FILESTREAM_H_
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Wrapper of C file stream for input or output.
|
||||
/*!
|
||||
This simple wrapper does not check the validity of the stream.
|
||||
\implements Stream
|
||||
*/
|
||||
class FileStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); }
|
||||
|
||||
char Peek() const { return current_; }
|
||||
char Take() { char c = current_; Read(); return c; }
|
||||
size_t Tell() const { return count_; }
|
||||
void Put(char c) { fputc(c, fp_); }
|
||||
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
|
||||
private:
|
||||
void Read() {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
int c = fgetc(fp_);
|
||||
if (c != EOF) {
|
||||
current_ = (char)c;
|
||||
count_++;
|
||||
}
|
||||
else
|
||||
current_ = '\0';
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
char current_;
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define CEREAL_RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of C file stream for output using fwrite().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
CEREAL_RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
|
||||
*current_++ = c;
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
std::memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
std::memset(current_, c, n);
|
||||
current_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||
// failure deliberately ignored at this time
|
||||
// added to avoid warn_unused_result build errors
|
||||
}
|
||||
current_ = buffer_;
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
|
||||
std::FILE* fp_;
|
||||
char *buffer_;
|
||||
char *bufferEnd_;
|
||||
char *current_;
|
||||
};
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||
stream.PutN(c, n);
|
||||
}
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_FILESTREAM_H_
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_FWD_H_
|
||||
#define CEREAL_RAPIDJSON_FWD_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
// encodings.h
|
||||
|
||||
template<typename CharType> struct UTF8;
|
||||
template<typename CharType> struct UTF16;
|
||||
template<typename CharType> struct UTF16BE;
|
||||
template<typename CharType> struct UTF16LE;
|
||||
template<typename CharType> struct UTF32;
|
||||
template<typename CharType> struct UTF32BE;
|
||||
template<typename CharType> struct UTF32LE;
|
||||
template<typename CharType> struct ASCII;
|
||||
template<typename CharType> struct AutoUTF;
|
||||
|
||||
template<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder;
|
||||
|
||||
// allocators.h
|
||||
|
||||
class CrtAllocator;
|
||||
|
||||
template <typename BaseAllocator>
|
||||
class MemoryPoolAllocator;
|
||||
|
||||
// stream.h
|
||||
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream;
|
||||
|
||||
typedef GenericStringStream<UTF8<char> > StringStream;
|
||||
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream;
|
||||
|
||||
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
|
||||
|
||||
// stringbuffer.h
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericStringBuffer;
|
||||
|
||||
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
|
||||
|
||||
// filereadstream.h
|
||||
|
||||
class FileReadStream;
|
||||
|
||||
// filewritestream.h
|
||||
|
||||
class FileWriteStream;
|
||||
|
||||
// memorybuffer.h
|
||||
|
||||
template <typename Allocator>
|
||||
struct GenericMemoryBuffer;
|
||||
|
||||
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
|
||||
|
||||
// memorystream.h
|
||||
|
||||
struct MemoryStream;
|
||||
|
||||
// reader.h
|
||||
|
||||
template<typename Encoding, typename Derived>
|
||||
struct BaseReaderHandler;
|
||||
|
||||
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
|
||||
class GenericReader;
|
||||
|
||||
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
|
||||
|
||||
// writer.h
|
||||
|
||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||
class Writer;
|
||||
|
||||
// prettywriter.h
|
||||
|
||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||
class PrettyWriter;
|
||||
|
||||
// document.h
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
struct GenericMember;
|
||||
|
||||
template <bool Const, typename Encoding, typename Allocator>
|
||||
class GenericMemberIterator;
|
||||
|
||||
template<typename CharType>
|
||||
struct GenericStringRef;
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericValue;
|
||||
|
||||
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
|
||||
|
||||
template <typename Encoding, typename Allocator, typename StackAllocator>
|
||||
class GenericDocument;
|
||||
|
||||
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
|
||||
|
||||
// pointer.h
|
||||
|
||||
template <typename ValueType, typename Allocator>
|
||||
class GenericPointer;
|
||||
|
||||
typedef GenericPointer<Value, CrtAllocator> Pointer;
|
||||
|
||||
// schema.h
|
||||
|
||||
template <typename SchemaDocumentType>
|
||||
class IGenericRemoteSchemaDocumentProvider;
|
||||
|
||||
template <typename ValueT, typename Allocator>
|
||||
class GenericSchemaDocument;
|
||||
|
||||
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
|
||||
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
|
||||
|
||||
template <
|
||||
typename SchemaDocumentType,
|
||||
typename OutputHandler,
|
||||
typename StateAllocator>
|
||||
class GenericSchemaValidator;
|
||||
|
||||
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_RAPIDJSONFWD_H_
|
||||
@@ -1,94 +0,0 @@
|
||||
// Generic*Stream code from https://code.google.com/p/rapidjson/issues/detail?id=20
|
||||
#ifndef RAPIDJSON_GENERICSTREAM_H_
|
||||
#define RAPIDJSON_GENERICSTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Wrapper of std::istream for input.
|
||||
class GenericReadStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type (byte).
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is Input stream.
|
||||
*/
|
||||
GenericReadStream(std::istream & is) : is_(&is) {
|
||||
}
|
||||
|
||||
|
||||
Ch Peek() const {
|
||||
if(is_->eof()) return '\0';
|
||||
return static_cast<char>(is_->peek());
|
||||
}
|
||||
|
||||
Ch Take() {
|
||||
if(is_->eof()) return '\0';
|
||||
return static_cast<char>(is_->get());
|
||||
}
|
||||
|
||||
size_t Tell() const {
|
||||
return (int)is_->tellg();
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
std::istream * is_;
|
||||
};
|
||||
|
||||
|
||||
//! Wrapper of std::ostream for output.
|
||||
class GenericWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
//! Constructor
|
||||
/*!
|
||||
\param os Output stream.
|
||||
*/
|
||||
GenericWriteStream(std::ostream& os) : os_(os) {
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
os_.put(c);
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Put(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
os_.flush();
|
||||
}
|
||||
|
||||
size_t Tell() const {
|
||||
return (int)os_.tellp();
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
char Take() { RAPIDJSON_ASSERT(false); }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
std::ostream& os_;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline void PutN(GenericWriteStream& stream, char c, size_t n) {
|
||||
stream.PutN(c, n);
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_GENERICSTREAM_H_
|
||||
@@ -0,0 +1,290 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_BIGINTEGER_H_
|
||||
#define CEREAL_RAPIDJSON_BIGINTEGER_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)
|
||||
#include <intrin.h> // for _umul128
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
class BigInteger {
|
||||
public:
|
||||
typedef uint64_t Type;
|
||||
|
||||
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
|
||||
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||
}
|
||||
|
||||
explicit BigInteger(uint64_t u) : count_(1) {
|
||||
digits_[0] = u;
|
||||
}
|
||||
|
||||
BigInteger(const char* decimals, size_t length) : count_(1) {
|
||||
CEREAL_RAPIDJSON_ASSERT(length > 0);
|
||||
digits_[0] = 0;
|
||||
size_t i = 0;
|
||||
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
|
||||
while (length >= kMaxDigitPerIteration) {
|
||||
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
|
||||
length -= kMaxDigitPerIteration;
|
||||
i += kMaxDigitPerIteration;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
AppendDecimal64(decimals + i, decimals + i + length);
|
||||
}
|
||||
|
||||
BigInteger& operator=(const BigInteger &rhs)
|
||||
{
|
||||
if (this != &rhs) {
|
||||
count_ = rhs.count_;
|
||||
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator=(uint64_t u) {
|
||||
digits_[0] = u;
|
||||
count_ = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator+=(uint64_t u) {
|
||||
Type backup = digits_[0];
|
||||
digits_[0] += u;
|
||||
for (size_t i = 0; i < count_ - 1; i++) {
|
||||
if (digits_[i] >= backup)
|
||||
return *this; // no carry
|
||||
backup = digits_[i + 1];
|
||||
digits_[i + 1] += 1;
|
||||
}
|
||||
|
||||
// Last carry
|
||||
if (digits_[count_ - 1] < backup)
|
||||
PushBack(1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator*=(uint64_t u) {
|
||||
if (u == 0) return *this = 0;
|
||||
if (u == 1) return *this;
|
||||
if (*this == 1) return *this = u;
|
||||
|
||||
uint64_t k = 0;
|
||||
for (size_t i = 0; i < count_; i++) {
|
||||
uint64_t hi;
|
||||
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
|
||||
k = hi;
|
||||
}
|
||||
|
||||
if (k > 0)
|
||||
PushBack(k);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator*=(uint32_t u) {
|
||||
if (u == 0) return *this = 0;
|
||||
if (u == 1) return *this;
|
||||
if (*this == 1) return *this = u;
|
||||
|
||||
uint64_t k = 0;
|
||||
for (size_t i = 0; i < count_; i++) {
|
||||
const uint64_t c = digits_[i] >> 32;
|
||||
const uint64_t d = digits_[i] & 0xFFFFFFFF;
|
||||
const uint64_t uc = u * c;
|
||||
const uint64_t ud = u * d;
|
||||
const uint64_t p0 = ud + k;
|
||||
const uint64_t p1 = uc + (p0 >> 32);
|
||||
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
|
||||
k = p1 >> 32;
|
||||
}
|
||||
|
||||
if (k > 0)
|
||||
PushBack(k);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator<<=(size_t shift) {
|
||||
if (IsZero() || shift == 0) return *this;
|
||||
|
||||
size_t offset = shift / kTypeBit;
|
||||
size_t interShift = shift % kTypeBit;
|
||||
CEREAL_RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
||||
|
||||
if (interShift == 0) {
|
||||
std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
|
||||
count_ += offset;
|
||||
}
|
||||
else {
|
||||
digits_[count_] = 0;
|
||||
for (size_t i = count_; i > 0; i--)
|
||||
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
|
||||
digits_[offset] = digits_[0] << interShift;
|
||||
count_ += offset;
|
||||
if (digits_[count_])
|
||||
count_++;
|
||||
}
|
||||
|
||||
std::memset(digits_, 0, offset * sizeof(Type));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const BigInteger& rhs) const {
|
||||
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
|
||||
}
|
||||
|
||||
bool operator==(const Type rhs) const {
|
||||
return count_ == 1 && digits_[0] == rhs;
|
||||
}
|
||||
|
||||
BigInteger& MultiplyPow5(unsigned exp) {
|
||||
static const uint32_t kPow5[12] = {
|
||||
5,
|
||||
5 * 5,
|
||||
5 * 5 * 5,
|
||||
5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
|
||||
};
|
||||
if (exp == 0) return *this;
|
||||
for (; exp >= 27; exp -= 27) *this *= CEREAL_RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
|
||||
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
|
||||
if (exp > 0) *this *= kPow5[exp - 1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Compute absolute difference of this and rhs.
|
||||
// Assume this != rhs
|
||||
bool Difference(const BigInteger& rhs, BigInteger* out) const {
|
||||
int cmp = Compare(rhs);
|
||||
CEREAL_RAPIDJSON_ASSERT(cmp != 0);
|
||||
const BigInteger *a, *b; // Makes a > b
|
||||
bool ret;
|
||||
if (cmp < 0) { a = &rhs; b = this; ret = true; }
|
||||
else { a = this; b = &rhs; ret = false; }
|
||||
|
||||
Type borrow = 0;
|
||||
for (size_t i = 0; i < a->count_; i++) {
|
||||
Type d = a->digits_[i] - borrow;
|
||||
if (i < b->count_)
|
||||
d -= b->digits_[i];
|
||||
borrow = (d > a->digits_[i]) ? 1 : 0;
|
||||
out->digits_[i] = d;
|
||||
if (d != 0)
|
||||
out->count_ = i + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Compare(const BigInteger& rhs) const {
|
||||
if (count_ != rhs.count_)
|
||||
return count_ < rhs.count_ ? -1 : 1;
|
||||
|
||||
for (size_t i = count_; i-- > 0;)
|
||||
if (digits_[i] != rhs.digits_[i])
|
||||
return digits_[i] < rhs.digits_[i] ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t GetCount() const { return count_; }
|
||||
Type GetDigit(size_t index) const { CEREAL_RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
|
||||
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
|
||||
|
||||
private:
|
||||
void AppendDecimal64(const char* begin, const char* end) {
|
||||
uint64_t u = ParseUint64(begin, end);
|
||||
if (IsZero())
|
||||
*this = u;
|
||||
else {
|
||||
unsigned exp = static_cast<unsigned>(end - begin);
|
||||
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
|
||||
}
|
||||
}
|
||||
|
||||
void PushBack(Type digit) {
|
||||
CEREAL_RAPIDJSON_ASSERT(count_ < kCapacity);
|
||||
digits_[count_++] = digit;
|
||||
}
|
||||
|
||||
static uint64_t ParseUint64(const char* begin, const char* end) {
|
||||
uint64_t r = 0;
|
||||
for (const char* p = begin; p != end; ++p) {
|
||||
CEREAL_RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Assume a * b + k < 2^128
|
||||
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
uint64_t low = _umul128(a, b, outHigh) + k;
|
||||
if (low < k)
|
||||
(*outHigh)++;
|
||||
return low;
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||
p += k;
|
||||
*outHigh = static_cast<uint64_t>(p >> 64);
|
||||
return static_cast<uint64_t>(p);
|
||||
#else
|
||||
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
|
||||
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
|
||||
x1 += (x0 >> 32); // can't give carry
|
||||
x1 += x2;
|
||||
if (x1 < x2)
|
||||
x3 += (static_cast<uint64_t>(1) << 32);
|
||||
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
|
||||
uint64_t hi = x3 + (x1 >> 32);
|
||||
|
||||
lo += k;
|
||||
if (lo < k)
|
||||
hi++;
|
||||
*outHigh = hi;
|
||||
return lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
|
||||
static const size_t kCapacity = kBitCount / sizeof(Type);
|
||||
static const size_t kTypeBit = sizeof(Type) * 8;
|
||||
|
||||
Type digits_[kCapacity];
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_BIGINTEGER_H_
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_DIYFP_H_
|
||||
#define CEREAL_RAPIDJSON_DIYFP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
#include <limits>
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanReverse64)
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
struct DiyFp {
|
||||
DiyFp() : f(), e() {}
|
||||
|
||||
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
|
||||
|
||||
explicit DiyFp(double d) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u = { d };
|
||||
|
||||
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
|
||||
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||
if (biased_e != 0) {
|
||||
f = significand + kDpHiddenBit;
|
||||
e = biased_e - kDpExponentBias;
|
||||
}
|
||||
else {
|
||||
f = significand;
|
||||
e = kDpMinExponent + 1;
|
||||
}
|
||||
}
|
||||
|
||||
DiyFp operator-(const DiyFp& rhs) const {
|
||||
return DiyFp(f - rhs.f, e);
|
||||
}
|
||||
|
||||
DiyFp operator*(const DiyFp& rhs) const {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
uint64_t h;
|
||||
uint64_t l = _umul128(f, rhs.f, &h);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||
uint64_t l = static_cast<uint64_t>(p);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#else
|
||||
const uint64_t M32 = 0xFFFFFFFF;
|
||||
const uint64_t a = f >> 32;
|
||||
const uint64_t b = f & M32;
|
||||
const uint64_t c = rhs.f >> 32;
|
||||
const uint64_t d = rhs.f & M32;
|
||||
const uint64_t ac = a * c;
|
||||
const uint64_t bc = b * c;
|
||||
const uint64_t ad = a * d;
|
||||
const uint64_t bd = b * d;
|
||||
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
||||
tmp += 1U << 31; /// mult_round
|
||||
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
|
||||
#endif
|
||||
}
|
||||
|
||||
DiyFp Normalize() const {
|
||||
CEREAL_RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
unsigned long index;
|
||||
_BitScanReverse64(&index, f);
|
||||
return DiyFp(f << (63 - index), e - (63 - index));
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
int s = __builtin_clzll(f);
|
||||
return DiyFp(f << s, e - s);
|
||||
#else
|
||||
DiyFp res = *this;
|
||||
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
DiyFp NormalizeBoundary() const {
|
||||
DiyFp res = *this;
|
||||
while (!(res.f & (kDpHiddenBit << 1))) {
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
||||
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
|
||||
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||
mi.f <<= mi.e - pl.e;
|
||||
mi.e = pl.e;
|
||||
*plus = pl;
|
||||
*minus = mi;
|
||||
}
|
||||
|
||||
double ToDouble() const {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
}u;
|
||||
CEREAL_RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
|
||||
if (e < kDpDenormalExponent) {
|
||||
// Underflow.
|
||||
return 0.0;
|
||||
}
|
||||
if (e >= kDpMaxExponent) {
|
||||
// Overflow.
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||
static_cast<uint64_t>(e + kDpExponentBias);
|
||||
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static const int kDiySignificandSize = 64;
|
||||
static const int kDpSignificandSize = 52;
|
||||
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
|
||||
static const int kDpMinExponent = -kDpExponentBias;
|
||||
static const int kDpDenormalExponent = -kDpExponentBias + 1;
|
||||
static const uint64_t kDpExponentMask = CEREAL_RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kDpSignificandMask = CEREAL_RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kDpHiddenBit = CEREAL_RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
uint64_t f;
|
||||
int e;
|
||||
};
|
||||
|
||||
inline DiyFp GetCachedPowerByIndex(size_t index) {
|
||||
// 10^-348, 10^-340, ..., 10^340
|
||||
static const uint64_t kCachedPowers_F[] = {
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), CEREAL_RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), CEREAL_RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), CEREAL_RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), CEREAL_RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), CEREAL_RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), CEREAL_RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), CEREAL_RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), CEREAL_RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), CEREAL_RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), CEREAL_RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), CEREAL_RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), CEREAL_RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), CEREAL_RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), CEREAL_RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), CEREAL_RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), CEREAL_RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), CEREAL_RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), CEREAL_RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), CEREAL_RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), CEREAL_RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), CEREAL_RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), CEREAL_RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), CEREAL_RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), CEREAL_RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), CEREAL_RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), CEREAL_RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), CEREAL_RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), CEREAL_RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), CEREAL_RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), CEREAL_RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), CEREAL_RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), CEREAL_RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), CEREAL_RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), CEREAL_RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), CEREAL_RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), CEREAL_RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), CEREAL_RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), CEREAL_RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), CEREAL_RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), CEREAL_RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), CEREAL_RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), CEREAL_RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), CEREAL_RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||
CEREAL_RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||
};
|
||||
static const int16_t kCachedPowers_E[] = {
|
||||
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||
907, 933, 960, 986, 1013, 1039, 1066
|
||||
};
|
||||
CEREAL_RAPIDJSON_ASSERT(index < 87);
|
||||
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||
}
|
||||
|
||||
inline DiyFp GetCachedPower(int e, int* K) {
|
||||
|
||||
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
|
||||
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
|
||||
int k = static_cast<int>(dk);
|
||||
if (dk - k > 0.0)
|
||||
k++;
|
||||
|
||||
unsigned index = static_cast<unsigned>((k >> 3) + 1);
|
||||
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
|
||||
|
||||
return GetCachedPowerByIndex(index);
|
||||
}
|
||||
|
||||
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||
CEREAL_RAPIDJSON_ASSERT(exp >= -348);
|
||||
unsigned index = static_cast<unsigned>(exp + 348) / 8u;
|
||||
*outExp = -348 + static_cast<int>(index) * 8;
|
||||
return GetCachedPowerByIndex(index);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_DIYFP_H_
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_DTOA_
|
||||
#define CEREAL_RAPIDJSON_DTOA_
|
||||
|
||||
#include "itoa.h" // GetDigitsLut()
|
||||
#include "diyfp.h"
|
||||
#include "ieee754.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
|
||||
#endif
|
||||
|
||||
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
||||
while (rest < wp_w && delta - rest >= ten_kappa &&
|
||||
(rest + ten_kappa < wp_w || /// closer
|
||||
wp_w - rest > rest + ten_kappa - wp_w)) {
|
||||
buffer[len - 1]--;
|
||||
rest += ten_kappa;
|
||||
}
|
||||
}
|
||||
|
||||
inline int CountDecimalDigit32(uint32_t n) {
|
||||
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
|
||||
if (n < 10) return 1;
|
||||
if (n < 100) return 2;
|
||||
if (n < 1000) return 3;
|
||||
if (n < 10000) return 4;
|
||||
if (n < 100000) return 5;
|
||||
if (n < 1000000) return 6;
|
||||
if (n < 10000000) return 7;
|
||||
if (n < 100000000) return 8;
|
||||
// Will not reach 10 digits in DigitGen()
|
||||
//if (n < 1000000000) return 9;
|
||||
//return 10;
|
||||
return 9;
|
||||
}
|
||||
|
||||
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||
const DiyFp wp_w = Mp - W;
|
||||
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||
uint64_t p2 = Mp.f & (one.f - 1);
|
||||
int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||
*len = 0;
|
||||
|
||||
while (kappa > 0) {
|
||||
uint32_t d = 0;
|
||||
switch (kappa) {
|
||||
case 9: d = p1 / 100000000; p1 %= 100000000; break;
|
||||
case 8: d = p1 / 10000000; p1 %= 10000000; break;
|
||||
case 7: d = p1 / 1000000; p1 %= 1000000; break;
|
||||
case 6: d = p1 / 100000; p1 %= 100000; break;
|
||||
case 5: d = p1 / 10000; p1 %= 10000; break;
|
||||
case 4: d = p1 / 1000; p1 %= 1000; break;
|
||||
case 3: d = p1 / 100; p1 %= 100; break;
|
||||
case 2: d = p1 / 10; p1 %= 10; break;
|
||||
case 1: d = p1; p1 = 0; break;
|
||||
default:;
|
||||
}
|
||||
if (d || *len)
|
||||
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
|
||||
kappa--;
|
||||
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||
if (tmp <= delta) {
|
||||
*K += kappa;
|
||||
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// kappa = 0
|
||||
for (;;) {
|
||||
p2 *= 10;
|
||||
delta *= 10;
|
||||
char d = static_cast<char>(p2 >> -one.e);
|
||||
if (d || *len)
|
||||
buffer[(*len)++] = static_cast<char>('0' + d);
|
||||
p2 &= one.f - 1;
|
||||
kappa--;
|
||||
if (p2 < delta) {
|
||||
*K += kappa;
|
||||
int index = -kappa;
|
||||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Grisu2(double value, char* buffer, int* length, int* K) {
|
||||
const DiyFp v(value);
|
||||
DiyFp w_m, w_p;
|
||||
v.NormalizedBoundaries(&w_m, &w_p);
|
||||
|
||||
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||
const DiyFp W = v.Normalize() * c_mk;
|
||||
DiyFp Wp = w_p * c_mk;
|
||||
DiyFp Wm = w_m * c_mk;
|
||||
Wm.f++;
|
||||
Wp.f--;
|
||||
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||
}
|
||||
|
||||
inline char* WriteExponent(int K, char* buffer) {
|
||||
if (K < 0) {
|
||||
*buffer++ = '-';
|
||||
K = -K;
|
||||
}
|
||||
|
||||
if (K >= 100) {
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
|
||||
K %= 100;
|
||||
const char* d = GetDigitsLut() + K * 2;
|
||||
*buffer++ = d[0];
|
||||
*buffer++ = d[1];
|
||||
}
|
||||
else if (K >= 10) {
|
||||
const char* d = GetDigitsLut() + K * 2;
|
||||
*buffer++ = d[0];
|
||||
*buffer++ = d[1];
|
||||
}
|
||||
else
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
|
||||
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||
|
||||
if (0 <= k && kk <= 21) {
|
||||
// 1234e7 -> 12340000000
|
||||
for (int i = length; i < kk; i++)
|
||||
buffer[i] = '0';
|
||||
buffer[kk] = '.';
|
||||
buffer[kk + 1] = '0';
|
||||
return &buffer[kk + 2];
|
||||
}
|
||||
else if (0 < kk && kk <= 21) {
|
||||
// 1234e-2 -> 12.34
|
||||
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||
buffer[kk] = '.';
|
||||
if (0 > k + maxDecimalPlaces) {
|
||||
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
|
||||
// Remove extra trailing zeros (at least one) after truncation.
|
||||
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
|
||||
if (buffer[i] != '0')
|
||||
return &buffer[i + 1];
|
||||
return &buffer[kk + 2]; // Reserve one zero
|
||||
}
|
||||
else
|
||||
return &buffer[length + 1];
|
||||
}
|
||||
else if (-6 < kk && kk <= 0) {
|
||||
// 1234e-6 -> 0.001234
|
||||
const int offset = 2 - kk;
|
||||
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
for (int i = 2; i < offset; i++)
|
||||
buffer[i] = '0';
|
||||
if (length - kk > maxDecimalPlaces) {
|
||||
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
|
||||
// Remove extra trailing zeros (at least one) after truncation.
|
||||
for (int i = maxDecimalPlaces + 1; i > 2; i--)
|
||||
if (buffer[i] != '0')
|
||||
return &buffer[i + 1];
|
||||
return &buffer[3]; // Reserve one zero
|
||||
}
|
||||
else
|
||||
return &buffer[length + offset];
|
||||
}
|
||||
else if (kk < -maxDecimalPlaces) {
|
||||
// Truncate to zero
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else if (length == 1) {
|
||||
// 1e30
|
||||
buffer[1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[2]);
|
||||
}
|
||||
else {
|
||||
// 1234e30 -> 1.234e33
|
||||
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
|
||||
buffer[1] = '.';
|
||||
buffer[length + 1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
|
||||
CEREAL_RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
|
||||
Double d(value);
|
||||
if (d.IsZero()) {
|
||||
if (d.Sign())
|
||||
*buffer++ = '-'; // -0.0, Issue #289
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else {
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
value = -value;
|
||||
}
|
||||
int length, K;
|
||||
Grisu2(value, buffer, &length, &K);
|
||||
return Prettify(buffer, length, K, maxDecimalPlaces);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_DTOA_
|
||||
@@ -0,0 +1,78 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_IEEE754_
|
||||
#define CEREAL_RAPIDJSON_IEEE754_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
class Double {
|
||||
public:
|
||||
Double() {}
|
||||
Double(double d) : d_(d) {}
|
||||
Double(uint64_t u) : u_(u) {}
|
||||
|
||||
double Value() const { return d_; }
|
||||
uint64_t Uint64Value() const { return u_; }
|
||||
|
||||
double NextPositiveDouble() const {
|
||||
CEREAL_RAPIDJSON_ASSERT(!Sign());
|
||||
return Double(u_ + 1).Value();
|
||||
}
|
||||
|
||||
bool Sign() const { return (u_ & kSignMask) != 0; }
|
||||
uint64_t Significand() const { return u_ & kSignificandMask; }
|
||||
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
|
||||
|
||||
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
|
||||
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
|
||||
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
|
||||
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
|
||||
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
|
||||
|
||||
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
|
||||
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
|
||||
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
|
||||
|
||||
static int EffectiveSignificandSize(int order) {
|
||||
if (order >= -1021)
|
||||
return 53;
|
||||
else if (order <= -1074)
|
||||
return 0;
|
||||
else
|
||||
return order + 1074;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kSignificandSize = 52;
|
||||
static const int kExponentBias = 0x3FF;
|
||||
static const int kDenormalExponent = 1 - kExponentBias;
|
||||
static const uint64_t kSignMask = CEREAL_RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
|
||||
static const uint64_t kExponentMask = CEREAL_RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kSignificandMask = CEREAL_RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kHiddenBit = CEREAL_RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
union {
|
||||
double d_;
|
||||
uint64_t u_;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_IEEE754_
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ITOA_
|
||||
#define CEREAL_RAPIDJSON_ITOA_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
inline const char* GetDigitsLut() {
|
||||
static const char cDigitsLut[200] = {
|
||||
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
|
||||
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
|
||||
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
|
||||
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
|
||||
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
|
||||
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
|
||||
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
|
||||
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
|
||||
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
|
||||
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
|
||||
};
|
||||
return cDigitsLut;
|
||||
}
|
||||
|
||||
inline char* u32toa(uint32_t value, char* buffer) {
|
||||
CEREAL_RAPIDJSON_ASSERT(buffer != 0);
|
||||
|
||||
const char* cDigitsLut = GetDigitsLut();
|
||||
|
||||
if (value < 10000) {
|
||||
const uint32_t d1 = (value / 100) << 1;
|
||||
const uint32_t d2 = (value % 100) << 1;
|
||||
|
||||
if (value >= 1000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 100)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 10)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
}
|
||||
else if (value < 100000000) {
|
||||
// value = bbbbcccc
|
||||
const uint32_t b = value / 10000;
|
||||
const uint32_t c = value % 10000;
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
if (value >= 10000000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 1000000)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 100000)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
else {
|
||||
// value = aabbbbcccc in decimal
|
||||
|
||||
const uint32_t a = value / 100000000; // 1 to 42
|
||||
value %= 100000000;
|
||||
|
||||
if (a >= 10) {
|
||||
const unsigned i = a << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||
|
||||
const uint32_t b = value / 10000; // 0 to 9999
|
||||
const uint32_t c = value % 10000; // 0 to 9999
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* i32toa(int32_t value, char* buffer) {
|
||||
CEREAL_RAPIDJSON_ASSERT(buffer != 0);
|
||||
uint32_t u = static_cast<uint32_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
|
||||
return u32toa(u, buffer);
|
||||
}
|
||||
|
||||
inline char* u64toa(uint64_t value, char* buffer) {
|
||||
CEREAL_RAPIDJSON_ASSERT(buffer != 0);
|
||||
const char* cDigitsLut = GetDigitsLut();
|
||||
const uint64_t kTen8 = 100000000;
|
||||
const uint64_t kTen9 = kTen8 * 10;
|
||||
const uint64_t kTen10 = kTen8 * 100;
|
||||
const uint64_t kTen11 = kTen8 * 1000;
|
||||
const uint64_t kTen12 = kTen8 * 10000;
|
||||
const uint64_t kTen13 = kTen8 * 100000;
|
||||
const uint64_t kTen14 = kTen8 * 1000000;
|
||||
const uint64_t kTen15 = kTen8 * 10000000;
|
||||
const uint64_t kTen16 = kTen8 * kTen8;
|
||||
|
||||
if (value < kTen8) {
|
||||
uint32_t v = static_cast<uint32_t>(value);
|
||||
if (v < 10000) {
|
||||
const uint32_t d1 = (v / 100) << 1;
|
||||
const uint32_t d2 = (v % 100) << 1;
|
||||
|
||||
if (v >= 1000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (v >= 100)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (v >= 10)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
}
|
||||
else {
|
||||
// value = bbbbcccc
|
||||
const uint32_t b = v / 10000;
|
||||
const uint32_t c = v % 10000;
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
if (value >= 10000000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 1000000)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 100000)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
}
|
||||
else if (value < kTen16) {
|
||||
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||
|
||||
const uint32_t b0 = v0 / 10000;
|
||||
const uint32_t c0 = v0 % 10000;
|
||||
|
||||
const uint32_t d1 = (b0 / 100) << 1;
|
||||
const uint32_t d2 = (b0 % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c0 / 100) << 1;
|
||||
const uint32_t d4 = (c0 % 100) << 1;
|
||||
|
||||
const uint32_t b1 = v1 / 10000;
|
||||
const uint32_t c1 = v1 % 10000;
|
||||
|
||||
const uint32_t d5 = (b1 / 100) << 1;
|
||||
const uint32_t d6 = (b1 % 100) << 1;
|
||||
|
||||
const uint32_t d7 = (c1 / 100) << 1;
|
||||
const uint32_t d8 = (c1 % 100) << 1;
|
||||
|
||||
if (value >= kTen15)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= kTen14)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= kTen13)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
if (value >= kTen12)
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
if (value >= kTen11)
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
if (value >= kTen10)
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
if (value >= kTen9)
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
*buffer++ = cDigitsLut[d5];
|
||||
*buffer++ = cDigitsLut[d5 + 1];
|
||||
*buffer++ = cDigitsLut[d6];
|
||||
*buffer++ = cDigitsLut[d6 + 1];
|
||||
*buffer++ = cDigitsLut[d7];
|
||||
*buffer++ = cDigitsLut[d7 + 1];
|
||||
*buffer++ = cDigitsLut[d8];
|
||||
*buffer++ = cDigitsLut[d8 + 1];
|
||||
}
|
||||
else {
|
||||
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
|
||||
value %= kTen16;
|
||||
|
||||
if (a < 10)
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||
else if (a < 100) {
|
||||
const uint32_t i = a << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else if (a < 1000) {
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
|
||||
|
||||
const uint32_t i = (a % 100) << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else {
|
||||
const uint32_t i = (a / 100) << 1;
|
||||
const uint32_t j = (a % 100) << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
*buffer++ = cDigitsLut[j];
|
||||
*buffer++ = cDigitsLut[j + 1];
|
||||
}
|
||||
|
||||
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||
|
||||
const uint32_t b0 = v0 / 10000;
|
||||
const uint32_t c0 = v0 % 10000;
|
||||
|
||||
const uint32_t d1 = (b0 / 100) << 1;
|
||||
const uint32_t d2 = (b0 % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c0 / 100) << 1;
|
||||
const uint32_t d4 = (c0 % 100) << 1;
|
||||
|
||||
const uint32_t b1 = v1 / 10000;
|
||||
const uint32_t c1 = v1 % 10000;
|
||||
|
||||
const uint32_t d5 = (b1 / 100) << 1;
|
||||
const uint32_t d6 = (b1 % 100) << 1;
|
||||
|
||||
const uint32_t d7 = (c1 / 100) << 1;
|
||||
const uint32_t d8 = (c1 % 100) << 1;
|
||||
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
*buffer++ = cDigitsLut[d5];
|
||||
*buffer++ = cDigitsLut[d5 + 1];
|
||||
*buffer++ = cDigitsLut[d6];
|
||||
*buffer++ = cDigitsLut[d6 + 1];
|
||||
*buffer++ = cDigitsLut[d7];
|
||||
*buffer++ = cDigitsLut[d7 + 1];
|
||||
*buffer++ = cDigitsLut[d8];
|
||||
*buffer++ = cDigitsLut[d8 + 1];
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* i64toa(int64_t value, char* buffer) {
|
||||
CEREAL_RAPIDJSON_ASSERT(buffer != 0);
|
||||
uint64_t u = static_cast<uint64_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
|
||||
return u64toa(u, buffer);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_ITOA_
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_INTERNAL_META_H_
|
||||
#define CEREAL_RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(6334)
|
||||
#endif
|
||||
|
||||
#if CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
//@cond CEREAL_RAPIDJSON_INTERNAL
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||
template <typename T> struct Void { typedef void Type; };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BoolType, TrueType, FalseType
|
||||
//
|
||||
template <bool Cond> struct BoolType {
|
||||
static const bool Value = Cond;
|
||||
typedef BoolType Type;
|
||||
};
|
||||
typedef BoolType<true> TrueType;
|
||||
typedef BoolType<false> FalseType;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||
//
|
||||
|
||||
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||
|
||||
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||
template <> struct AndExprCond<true, true> : TrueType {};
|
||||
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||
template <> struct OrExprCond<false, false> : FalseType {};
|
||||
|
||||
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AddConst, MaybeAddConst, RemoveConst
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
template <typename T> struct RemoveConst { typedef T Type; };
|
||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||
//
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
template <typename T> struct IsConst<const T> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst
|
||||
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||
|
||||
template <typename T> struct IsPointer : FalseType {};
|
||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsBaseOf
|
||||
//
|
||||
#if CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||
|
||||
#else // simplified version adopted from Boost
|
||||
|
||||
template<typename B, typename D> struct IsBaseOfImpl {
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||
CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||
|
||||
typedef char (&Yes)[1];
|
||||
typedef char (&No) [2];
|
||||
|
||||
template <typename T>
|
||||
static Yes Check(const D*, T);
|
||||
static No Check(const B*, int);
|
||||
|
||||
struct Host {
|
||||
operator const B*() const;
|
||||
operator const D*();
|
||||
};
|
||||
|
||||
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||
};
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EnableIf / DisableIf
|
||||
//
|
||||
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||
|
||||
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeTag {};
|
||||
template <typename T> struct RemoveSfinaeTag;
|
||||
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define CEREAL_RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||
< ::CEREAL_RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||
|
||||
#define CEREAL_RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define CEREAL_RAPIDJSON_DISABLEIF(cond) \
|
||||
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define CEREAL_RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
CEREAL_RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
#define CEREAL_RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||
typename ::CEREAL_RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<CEREAL_RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
CEREAL_RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
//@endcond
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_INTERNAL_META_H_
|
||||
+55
-54
@@ -1,54 +1,55 @@
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Computes integer powers of 10 in double (10.0^n).
|
||||
/*! This function uses lookup table for fast and accurate results.
|
||||
\param n positive/negative exponent. Must <= 308.
|
||||
\return 10.0^n
|
||||
*/
|
||||
inline double Pow10(int n) {
|
||||
static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes
|
||||
1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,
|
||||
1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,
|
||||
1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,
|
||||
1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,
|
||||
1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,
|
||||
1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,
|
||||
1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,
|
||||
1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,
|
||||
1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,
|
||||
1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,
|
||||
1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,
|
||||
1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80,
|
||||
1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60,
|
||||
1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40,
|
||||
1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20,
|
||||
1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0,
|
||||
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||
};
|
||||
RAPIDJSON_ASSERT(n <= 308);
|
||||
return n < -308 ? 0.0 : e[n + 308];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_POW10_
|
||||
#define CEREAL_RAPIDJSON_POW10_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Computes integer powers of 10 in double (10.0^n).
|
||||
/*! This function uses lookup table for fast and accurate results.
|
||||
\param n non-negative exponent. Must <= 308.
|
||||
\return 10.0^n
|
||||
*/
|
||||
inline double Pow10(int n) {
|
||||
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
|
||||
1e+0,
|
||||
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||
};
|
||||
CEREAL_RAPIDJSON_ASSERT(n >= 0 && n <= 308);
|
||||
return e[n];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_POW10_
|
||||
|
||||
+740
@@ -0,0 +1,740 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_INTERNAL_REGEX_H_
|
||||
#define CEREAL_RAPIDJSON_INTERNAL_REGEX_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "../stream.h"
|
||||
#include "stack.h"
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
||||
#elif defined(_MSC_VER)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
#if __GNUC__ >= 7
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_REGEX_VERBOSE
|
||||
#define CEREAL_RAPIDJSON_REGEX_VERBOSE 0
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// DecodedStream
|
||||
|
||||
template <typename SourceStream, typename Encoding>
|
||||
class DecodedStream {
|
||||
public:
|
||||
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
|
||||
unsigned Peek() { return codepoint_; }
|
||||
unsigned Take() {
|
||||
unsigned c = codepoint_;
|
||||
if (c) // No further decoding when '\0'
|
||||
Decode();
|
||||
return c;
|
||||
}
|
||||
|
||||
private:
|
||||
void Decode() {
|
||||
if (!Encoding::Decode(ss_, &codepoint_))
|
||||
codepoint_ = 0;
|
||||
}
|
||||
|
||||
SourceStream& ss_;
|
||||
unsigned codepoint_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericRegex
|
||||
|
||||
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
|
||||
static const SizeType kRegexInvalidRange = ~SizeType(0);
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericRegexSearch;
|
||||
|
||||
//! Regular expression engine with subset of ECMAscript grammar.
|
||||
/*!
|
||||
Supported regular expression syntax:
|
||||
- \c ab Concatenation
|
||||
- \c a|b Alternation
|
||||
- \c a? Zero or one
|
||||
- \c a* Zero or more
|
||||
- \c a+ One or more
|
||||
- \c a{3} Exactly 3 times
|
||||
- \c a{3,} At least 3 times
|
||||
- \c a{3,5} 3 to 5 times
|
||||
- \c (ab) Grouping
|
||||
- \c ^a At the beginning
|
||||
- \c a$ At the end
|
||||
- \c . Any character
|
||||
- \c [abc] Character classes
|
||||
- \c [a-c] Character class range
|
||||
- \c [a-z0-9_] Character class combination
|
||||
- \c [^abc] Negated character classes
|
||||
- \c [^a-c] Negated character class range
|
||||
- \c [\b] Backspace (U+0008)
|
||||
- \c \\| \\\\ ... Escape characters
|
||||
- \c \\f Form feed (U+000C)
|
||||
- \c \\n Line feed (U+000A)
|
||||
- \c \\r Carriage return (U+000D)
|
||||
- \c \\t Tab (U+0009)
|
||||
- \c \\v Vertical tab (U+000B)
|
||||
|
||||
\note This is a Thompson NFA engine, implemented with reference to
|
||||
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
|
||||
https://swtch.com/~rsc/regexp/regexp1.html
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericRegex {
|
||||
public:
|
||||
typedef Encoding EncodingType;
|
||||
typedef typename Encoding::Ch Ch;
|
||||
template <typename, typename> friend class GenericRegexSearch;
|
||||
|
||||
GenericRegex(const Ch* source, Allocator* allocator = 0) :
|
||||
ownAllocator_(allocator ? 0 : CEREAL_RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
|
||||
states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
|
||||
anchorBegin_(), anchorEnd_()
|
||||
{
|
||||
GenericStringStream<Encoding> ss(source);
|
||||
DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
|
||||
Parse(ds);
|
||||
}
|
||||
|
||||
~GenericRegex()
|
||||
{
|
||||
CEREAL_RAPIDJSON_DELETE(ownAllocator_);
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
return root_ != kRegexInvalidState;
|
||||
}
|
||||
|
||||
private:
|
||||
enum Operator {
|
||||
kZeroOrOne,
|
||||
kZeroOrMore,
|
||||
kOneOrMore,
|
||||
kConcatenation,
|
||||
kAlternation,
|
||||
kLeftParenthesis
|
||||
};
|
||||
|
||||
static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
|
||||
static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
|
||||
static const unsigned kRangeNegationFlag = 0x80000000;
|
||||
|
||||
struct Range {
|
||||
unsigned start; //
|
||||
unsigned end;
|
||||
SizeType next;
|
||||
};
|
||||
|
||||
struct State {
|
||||
SizeType out; //!< Equals to kInvalid for matching state
|
||||
SizeType out1; //!< Equals to non-kInvalid for split
|
||||
SizeType rangeStart;
|
||||
unsigned codepoint;
|
||||
};
|
||||
|
||||
struct Frag {
|
||||
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
|
||||
SizeType start;
|
||||
SizeType out; //!< link-list of all output states
|
||||
SizeType minIndex;
|
||||
};
|
||||
|
||||
State& GetState(SizeType index) {
|
||||
CEREAL_RAPIDJSON_ASSERT(index < stateCount_);
|
||||
return states_.template Bottom<State>()[index];
|
||||
}
|
||||
|
||||
const State& GetState(SizeType index) const {
|
||||
CEREAL_RAPIDJSON_ASSERT(index < stateCount_);
|
||||
return states_.template Bottom<State>()[index];
|
||||
}
|
||||
|
||||
Range& GetRange(SizeType index) {
|
||||
CEREAL_RAPIDJSON_ASSERT(index < rangeCount_);
|
||||
return ranges_.template Bottom<Range>()[index];
|
||||
}
|
||||
|
||||
const Range& GetRange(SizeType index) const {
|
||||
CEREAL_RAPIDJSON_ASSERT(index < rangeCount_);
|
||||
return ranges_.template Bottom<Range>()[index];
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
void Parse(DecodedStream<InputStream, Encoding>& ds) {
|
||||
Stack<Allocator> operandStack(allocator_, 256); // Frag
|
||||
Stack<Allocator> operatorStack(allocator_, 256); // Operator
|
||||
Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
|
||||
|
||||
*atomCountStack.template Push<unsigned>() = 0;
|
||||
|
||||
unsigned codepoint;
|
||||
while (ds.Peek() != 0) {
|
||||
switch (codepoint = ds.Take()) {
|
||||
case '^':
|
||||
anchorBegin_ = true;
|
||||
break;
|
||||
|
||||
case '$':
|
||||
anchorEnd_ = true;
|
||||
break;
|
||||
|
||||
case '|':
|
||||
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
*operatorStack.template Push<Operator>() = kAlternation;
|
||||
*atomCountStack.template Top<unsigned>() = 0;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
*operatorStack.template Push<Operator>() = kLeftParenthesis;
|
||||
*atomCountStack.template Push<unsigned>() = 0;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
if (operatorStack.Empty())
|
||||
return;
|
||||
operatorStack.template Pop<Operator>(1);
|
||||
atomCountStack.template Pop<unsigned>(1);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
if (!Eval(operandStack, kZeroOrOne))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (!Eval(operandStack, kZeroOrMore))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (!Eval(operandStack, kOneOrMore))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
{
|
||||
unsigned n, m;
|
||||
if (!ParseUnsigned(ds, &n))
|
||||
return;
|
||||
|
||||
if (ds.Peek() == ',') {
|
||||
ds.Take();
|
||||
if (ds.Peek() == '}')
|
||||
m = kInfinityQuantifier;
|
||||
else if (!ParseUnsigned(ds, &m) || m < n)
|
||||
return;
|
||||
}
|
||||
else
|
||||
m = n;
|
||||
|
||||
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
|
||||
return;
|
||||
ds.Take();
|
||||
}
|
||||
break;
|
||||
|
||||
case '.':
|
||||
PushOperand(operandStack, kAnyCharacterClass);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
{
|
||||
SizeType range;
|
||||
if (!ParseRange(ds, &range))
|
||||
return;
|
||||
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
|
||||
GetState(s).rangeStart = range;
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||
}
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '\\': // Escape character
|
||||
if (!CharacterEscape(ds, &codepoint))
|
||||
return; // Unsupported escape character
|
||||
// fall through to default
|
||||
|
||||
default: // Pattern character
|
||||
PushOperand(operandStack, codepoint);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
}
|
||||
}
|
||||
|
||||
while (!operatorStack.Empty())
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
|
||||
// Link the operand to matching state.
|
||||
if (operandStack.GetSize() == sizeof(Frag)) {
|
||||
Frag* e = operandStack.template Pop<Frag>(1);
|
||||
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
|
||||
root_ = e->start;
|
||||
|
||||
#if CEREAL_RAPIDJSON_REGEX_VERBOSE
|
||||
printf("root: %d\n", root_);
|
||||
for (SizeType i = 0; i < stateCount_ ; i++) {
|
||||
State& s = GetState(i);
|
||||
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
|
||||
State* s = states_.template Push<State>();
|
||||
s->out = out;
|
||||
s->out1 = out1;
|
||||
s->codepoint = codepoint;
|
||||
s->rangeStart = kRegexInvalidRange;
|
||||
return stateCount_++;
|
||||
}
|
||||
|
||||
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
|
||||
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||
}
|
||||
|
||||
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
|
||||
if (*atomCountStack.template Top<unsigned>())
|
||||
*operatorStack.template Push<Operator>() = kConcatenation;
|
||||
(*atomCountStack.template Top<unsigned>())++;
|
||||
}
|
||||
|
||||
SizeType Append(SizeType l1, SizeType l2) {
|
||||
SizeType old = l1;
|
||||
while (GetState(l1).out != kRegexInvalidState)
|
||||
l1 = GetState(l1).out;
|
||||
GetState(l1).out = l2;
|
||||
return old;
|
||||
}
|
||||
|
||||
void Patch(SizeType l, SizeType s) {
|
||||
for (SizeType next; l != kRegexInvalidState; l = next) {
|
||||
next = GetState(l).out;
|
||||
GetState(l).out = s;
|
||||
}
|
||||
}
|
||||
|
||||
bool Eval(Stack<Allocator>& operandStack, Operator op) {
|
||||
switch (op) {
|
||||
case kConcatenation:
|
||||
CEREAL_RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
|
||||
{
|
||||
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||
Patch(e1.out, e2.start);
|
||||
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
|
||||
}
|
||||
return true;
|
||||
|
||||
case kAlternation:
|
||||
if (operandStack.GetSize() >= sizeof(Frag) * 2) {
|
||||
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(e1.start, e2.start, 0);
|
||||
*operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kZeroOrOne:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kZeroOrMore:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
Patch(e.out, s);
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kOneOrMore:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
Patch(e.out, s);
|
||||
*operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
// syntax error (e.g. unclosed kLeftParenthesis)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
|
||||
CEREAL_RAPIDJSON_ASSERT(n <= m);
|
||||
CEREAL_RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
|
||||
|
||||
if (n == 0) {
|
||||
if (m == 0) // a{0} not support
|
||||
return false;
|
||||
else if (m == kInfinityQuantifier)
|
||||
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
|
||||
else {
|
||||
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
|
||||
for (unsigned i = 0; i < m - 1; i++)
|
||||
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
|
||||
for (unsigned i = 0; i < m - 1; i++)
|
||||
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
|
||||
CloneTopOperand(operandStack);
|
||||
|
||||
if (m == kInfinityQuantifier)
|
||||
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
|
||||
else if (m > n) {
|
||||
CloneTopOperand(operandStack); // a{3,5} -> a a a a
|
||||
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
|
||||
for (unsigned i = n; i < m - 1; i++)
|
||||
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
|
||||
for (unsigned i = n; i < m; i++)
|
||||
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n - 1; i++)
|
||||
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
|
||||
|
||||
void CloneTopOperand(Stack<Allocator>& operandStack) {
|
||||
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
|
||||
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
|
||||
State* s = states_.template Push<State>(count);
|
||||
memcpy(s, &GetState(src.minIndex), count * sizeof(State));
|
||||
for (SizeType j = 0; j < count; j++) {
|
||||
if (s[j].out != kRegexInvalidState)
|
||||
s[j].out += count;
|
||||
if (s[j].out1 != kRegexInvalidState)
|
||||
s[j].out1 += count;
|
||||
}
|
||||
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
|
||||
stateCount_ += count;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
|
||||
unsigned r = 0;
|
||||
if (ds.Peek() < '0' || ds.Peek() > '9')
|
||||
return false;
|
||||
while (ds.Peek() >= '0' && ds.Peek() <= '9') {
|
||||
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
|
||||
return false; // overflow
|
||||
r = r * 10 + (ds.Take() - '0');
|
||||
}
|
||||
*u = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
|
||||
bool isBegin = true;
|
||||
bool negate = false;
|
||||
int step = 0;
|
||||
SizeType start = kRegexInvalidRange;
|
||||
SizeType current = kRegexInvalidRange;
|
||||
unsigned codepoint;
|
||||
while ((codepoint = ds.Take()) != 0) {
|
||||
if (isBegin) {
|
||||
isBegin = false;
|
||||
if (codepoint == '^') {
|
||||
negate = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (codepoint) {
|
||||
case ']':
|
||||
if (start == kRegexInvalidRange)
|
||||
return false; // Error: nothing inside []
|
||||
if (step == 2) { // Add trailing '-'
|
||||
SizeType r = NewRange('-');
|
||||
CEREAL_RAPIDJSON_ASSERT(current != kRegexInvalidRange);
|
||||
GetRange(current).next = r;
|
||||
}
|
||||
if (negate)
|
||||
GetRange(start).start |= kRangeNegationFlag;
|
||||
*range = start;
|
||||
return true;
|
||||
|
||||
case '\\':
|
||||
if (ds.Peek() == 'b') {
|
||||
ds.Take();
|
||||
codepoint = 0x0008; // Escape backspace character
|
||||
}
|
||||
else if (!CharacterEscape(ds, &codepoint))
|
||||
return false;
|
||||
// fall through to default
|
||||
|
||||
default:
|
||||
switch (step) {
|
||||
case 1:
|
||||
if (codepoint == '-') {
|
||||
step++;
|
||||
break;
|
||||
}
|
||||
// fall through to step 0 for other characters
|
||||
|
||||
case 0:
|
||||
{
|
||||
SizeType r = NewRange(codepoint);
|
||||
if (current != kRegexInvalidRange)
|
||||
GetRange(current).next = r;
|
||||
if (start == kRegexInvalidRange)
|
||||
start = r;
|
||||
current = r;
|
||||
}
|
||||
step = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
CEREAL_RAPIDJSON_ASSERT(step == 2);
|
||||
GetRange(current).end = codepoint;
|
||||
step = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SizeType NewRange(unsigned codepoint) {
|
||||
Range* r = ranges_.template Push<Range>();
|
||||
r->start = r->end = codepoint;
|
||||
r->next = kRegexInvalidRange;
|
||||
return rangeCount_++;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
|
||||
unsigned codepoint;
|
||||
switch (codepoint = ds.Take()) {
|
||||
case '^':
|
||||
case '$':
|
||||
case '|':
|
||||
case '(':
|
||||
case ')':
|
||||
case '?':
|
||||
case '*':
|
||||
case '+':
|
||||
case '.':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
case '\\':
|
||||
*escapedCodepoint = codepoint; return true;
|
||||
case 'f': *escapedCodepoint = 0x000C; return true;
|
||||
case 'n': *escapedCodepoint = 0x000A; return true;
|
||||
case 'r': *escapedCodepoint = 0x000D; return true;
|
||||
case 't': *escapedCodepoint = 0x0009; return true;
|
||||
case 'v': *escapedCodepoint = 0x000B; return true;
|
||||
default:
|
||||
return false; // Unsupported escape character
|
||||
}
|
||||
}
|
||||
|
||||
Allocator* ownAllocator_;
|
||||
Allocator* allocator_;
|
||||
Stack<Allocator> states_;
|
||||
Stack<Allocator> ranges_;
|
||||
SizeType root_;
|
||||
SizeType stateCount_;
|
||||
SizeType rangeCount_;
|
||||
|
||||
static const unsigned kInfinityQuantifier = ~0u;
|
||||
|
||||
// For SearchWithAnchoring()
|
||||
bool anchorBegin_;
|
||||
bool anchorEnd_;
|
||||
};
|
||||
|
||||
template <typename RegexType, typename Allocator = CrtAllocator>
|
||||
class GenericRegexSearch {
|
||||
public:
|
||||
typedef typename RegexType::EncodingType Encoding;
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
|
||||
regex_(regex), allocator_(allocator), ownAllocator_(0),
|
||||
state0_(allocator, 0), state1_(allocator, 0), stateSet_()
|
||||
{
|
||||
CEREAL_RAPIDJSON_ASSERT(regex_.IsValid());
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
|
||||
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
|
||||
state0_.template Reserve<SizeType>(regex_.stateCount_);
|
||||
state1_.template Reserve<SizeType>(regex_.stateCount_);
|
||||
}
|
||||
|
||||
~GenericRegexSearch() {
|
||||
Allocator::Free(stateSet_);
|
||||
CEREAL_RAPIDJSON_DELETE(ownAllocator_);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool Match(InputStream& is) {
|
||||
return SearchWithAnchoring(is, true, true);
|
||||
}
|
||||
|
||||
bool Match(const Ch* s) {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
return Match(is);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool Search(InputStream& is) {
|
||||
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
|
||||
}
|
||||
|
||||
bool Search(const Ch* s) {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
return Search(is);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename RegexType::State State;
|
||||
typedef typename RegexType::Range Range;
|
||||
|
||||
template <typename InputStream>
|
||||
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
|
||||
DecodedStream<InputStream, Encoding> ds(is);
|
||||
|
||||
state0_.Clear();
|
||||
Stack<Allocator> *current = &state0_, *next = &state1_;
|
||||
const size_t stateSetSize = GetStateSetSize();
|
||||
std::memset(stateSet_, 0, stateSetSize);
|
||||
|
||||
bool matched = AddState(*current, regex_.root_);
|
||||
unsigned codepoint;
|
||||
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
|
||||
std::memset(stateSet_, 0, stateSetSize);
|
||||
next->Clear();
|
||||
matched = false;
|
||||
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
|
||||
const State& sr = regex_.GetState(*s);
|
||||
if (sr.codepoint == codepoint ||
|
||||
sr.codepoint == RegexType::kAnyCharacterClass ||
|
||||
(sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
|
||||
{
|
||||
matched = AddState(*next, sr.out) || matched;
|
||||
if (!anchorEnd && matched)
|
||||
return true;
|
||||
}
|
||||
if (!anchorBegin)
|
||||
AddState(*next, regex_.root_);
|
||||
}
|
||||
internal::Swap(current, next);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
size_t GetStateSetSize() const {
|
||||
return (regex_.stateCount_ + 31) / 32 * 4;
|
||||
}
|
||||
|
||||
// Return whether the added states is a match state
|
||||
bool AddState(Stack<Allocator>& l, SizeType index) {
|
||||
CEREAL_RAPIDJSON_ASSERT(index != kRegexInvalidState);
|
||||
|
||||
const State& s = regex_.GetState(index);
|
||||
if (s.out1 != kRegexInvalidState) { // Split
|
||||
bool matched = AddState(l, s.out);
|
||||
return AddState(l, s.out1) || matched;
|
||||
}
|
||||
else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
|
||||
stateSet_[index >> 5] |= (1u << (index & 31));
|
||||
*l.template PushUnsafe<SizeType>() = index;
|
||||
}
|
||||
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
|
||||
}
|
||||
|
||||
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
|
||||
bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
|
||||
while (rangeIndex != kRegexInvalidRange) {
|
||||
const Range& r = regex_.GetRange(rangeIndex);
|
||||
if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
|
||||
return yes;
|
||||
rangeIndex = r.next;
|
||||
}
|
||||
return !yes;
|
||||
}
|
||||
|
||||
const RegexType& regex_;
|
||||
Allocator* allocator_;
|
||||
Allocator* ownAllocator_;
|
||||
Stack<Allocator> state0_;
|
||||
Stack<Allocator> state1_;
|
||||
uint32_t* stateSet_;
|
||||
};
|
||||
|
||||
typedef GenericRegex<UTF8<> > Regex;
|
||||
typedef GenericRegexSearch<Regex> RegexSearch;
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_INTERNAL_REGEX_H_
|
||||
+232
-82
@@ -1,82 +1,232 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
|
||||
RAPIDJSON_ASSERT(stack_capacity_ > 0);
|
||||
if (!allocator_)
|
||||
own_allocator_ = allocator_ = new Allocator();
|
||||
stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
|
||||
~Stack() {
|
||||
Allocator::Free(stack_);
|
||||
delete own_allocator_; // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
|
||||
|
||||
template<typename T>
|
||||
T* Push(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (stack_top_ + sizeof(T) * count >= stack_end_) {
|
||||
size_t new_capacity = stack_capacity_ * 2;
|
||||
size_t size = GetSize();
|
||||
size_t new_size = GetSize() + sizeof(T) * count;
|
||||
if (new_capacity < new_size)
|
||||
new_capacity = new_size;
|
||||
stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
|
||||
stack_capacity_ = new_capacity;
|
||||
stack_top_ = stack_ + size;
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
T* ret = (T*)stack_top_;
|
||||
stack_top_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stack_top_ -= count * sizeof(T);
|
||||
return (T*)stack_top_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return (T*)(stack_top_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return (T*)stack_; }
|
||||
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
size_t GetSize() const { return stack_top_ - stack_; }
|
||||
size_t GetCapacity() const { return stack_capacity_; }
|
||||
|
||||
private:
|
||||
Allocator* allocator_;
|
||||
Allocator* own_allocator_;
|
||||
char *stack_;
|
||||
char *stack_top_;
|
||||
char *stack_end_;
|
||||
size_t stack_capacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define CEREAL_RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "swap.h"
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||
}
|
||||
|
||||
#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack(Stack&& rhs)
|
||||
: allocator_(rhs.allocator_),
|
||||
ownAllocator_(rhs.ownAllocator_),
|
||||
stack_(rhs.stack_),
|
||||
stackTop_(rhs.stackTop_),
|
||||
stackEnd_(rhs.stackEnd_),
|
||||
initialCapacity_(rhs.initialCapacity_)
|
||||
{
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
~Stack() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack& operator=(Stack&& rhs) {
|
||||
if (&rhs != this)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
allocator_ = rhs.allocator_;
|
||||
ownAllocator_ = rhs.ownAllocator_;
|
||||
stack_ = rhs.stack_;
|
||||
stackTop_ = rhs.stackTop_;
|
||||
stackEnd_ = rhs.stackEnd_;
|
||||
initialCapacity_ = rhs.initialCapacity_;
|
||||
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Swap(Stack& rhs) CEREAL_RAPIDJSON_NOEXCEPT {
|
||||
internal::Swap(allocator_, rhs.allocator_);
|
||||
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||
internal::Swap(stack_, rhs.stack_);
|
||||
internal::Swap(stackTop_, rhs.stackTop_);
|
||||
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||
}
|
||||
|
||||
void Clear() { stackTop_ = stack_; }
|
||||
|
||||
void ShrinkToFit() {
|
||||
if (Empty()) {
|
||||
// If the stack is empty, completely deallocate the memory.
|
||||
Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
|
||||
stack_ = 0;
|
||||
stackTop_ = 0;
|
||||
stackEnd_ = 0;
|
||||
}
|
||||
else
|
||||
Resize(GetSize());
|
||||
}
|
||||
|
||||
// Optimization note: try to minimize the size of this function for force inline.
|
||||
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||
template<typename T>
|
||||
CEREAL_RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (CEREAL_RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
|
||||
Expand<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CEREAL_RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||
Reserve<T>(count);
|
||||
return PushUnsafe<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CEREAL_RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||
CEREAL_RAPIDJSON_ASSERT(stackTop_);
|
||||
CEREAL_RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
|
||||
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||
stackTop_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
CEREAL_RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stackTop_ -= count * sizeof(T);
|
||||
return reinterpret_cast<T*>(stackTop_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
CEREAL_RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* Top() const {
|
||||
CEREAL_RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* End() { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
template<typename T>
|
||||
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
bool HasAllocator() const {
|
||||
return allocator_ != 0;
|
||||
}
|
||||
|
||||
Allocator& GetAllocator() {
|
||||
CEREAL_RAPIDJSON_ASSERT(allocator_);
|
||||
return *allocator_;
|
||||
}
|
||||
|
||||
bool Empty() const { return stackTop_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void Expand(size_t count) {
|
||||
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||
size_t newCapacity;
|
||||
if (stack_ == 0) {
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
|
||||
newCapacity = initialCapacity_;
|
||||
} else {
|
||||
newCapacity = GetCapacity();
|
||||
newCapacity += (newCapacity + 1) / 2;
|
||||
}
|
||||
size_t newSize = GetSize() + sizeof(T) * count;
|
||||
if (newCapacity < newSize)
|
||||
newCapacity = newSize;
|
||||
|
||||
Resize(newCapacity);
|
||||
}
|
||||
|
||||
void Resize(size_t newCapacity) {
|
||||
const size_t size = GetSize(); // Backup the current size
|
||||
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||
stackTop_ = stack_ + size;
|
||||
stackEnd_ = stack_ + newCapacity;
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
Allocator::Free(stack_);
|
||||
CEREAL_RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* ownAllocator_;
|
||||
char *stack_;
|
||||
char *stackTop_;
|
||||
char *stackEnd_;
|
||||
size_t initialCapacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_STACK_H_
|
||||
|
||||
+69
-24
@@ -1,24 +1,69 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Custom strlen() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s Null-terminated input string.
|
||||
\return Number of characters in the string.
|
||||
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p != '\0')
|
||||
++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define CEREAL_RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
#include "../stream.h"
|
||||
#include <cwchar>
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom strlen() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s Null-terminated input string.
|
||||
\return Number of characters in the string.
|
||||
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
CEREAL_RAPIDJSON_ASSERT(s != 0);
|
||||
const Ch* p = s;
|
||||
while (*p) ++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline SizeType StrLen(const char* s) {
|
||||
return SizeType(std::strlen(s));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline SizeType StrLen(const wchar_t* s) {
|
||||
return SizeType(std::wcslen(s));
|
||||
}
|
||||
|
||||
//! Returns number of code points in a encoded string.
|
||||
template<typename Encoding>
|
||||
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||
CEREAL_RAPIDJSON_ASSERT(s != 0);
|
||||
CEREAL_RAPIDJSON_ASSERT(outCount != 0);
|
||||
GenericStringStream<Encoding> is(s);
|
||||
const typename Encoding::Ch* end = s + length;
|
||||
SizeType count = 0;
|
||||
while (is.src_ < end) {
|
||||
unsigned codepoint;
|
||||
if (!Encoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
*outCount = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_STRTOD_
|
||||
#define CEREAL_RAPIDJSON_STRTOD_
|
||||
|
||||
#include "ieee754.h"
|
||||
#include "biginteger.h"
|
||||
#include "diyfp.h"
|
||||
#include "pow10.h"
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
inline double FastPath(double significand, int exp) {
|
||||
if (exp < -308)
|
||||
return 0.0;
|
||||
else if (exp >= 0)
|
||||
return significand * internal::Pow10(exp);
|
||||
else
|
||||
return significand / internal::Pow10(-exp);
|
||||
}
|
||||
|
||||
inline double StrtodNormalPrecision(double d, int p) {
|
||||
if (p < -308) {
|
||||
// Prevent expSum < -308, making Pow10(p) = 0
|
||||
d = FastPath(d, -308);
|
||||
d = FastPath(d, p + 308);
|
||||
}
|
||||
else
|
||||
d = FastPath(d, p);
|
||||
return d;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Min3(T a, T b, T c) {
|
||||
T m = a;
|
||||
if (m > b) m = b;
|
||||
if (m > c) m = c;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
|
||||
const Double db(b);
|
||||
const uint64_t bInt = db.IntegerSignificand();
|
||||
const int bExp = db.IntegerExponent();
|
||||
const int hExp = bExp - 1;
|
||||
|
||||
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
|
||||
|
||||
// Adjust for decimal exponent
|
||||
if (dExp >= 0) {
|
||||
dS_Exp2 += dExp;
|
||||
dS_Exp5 += dExp;
|
||||
}
|
||||
else {
|
||||
bS_Exp2 -= dExp;
|
||||
bS_Exp5 -= dExp;
|
||||
hS_Exp2 -= dExp;
|
||||
hS_Exp5 -= dExp;
|
||||
}
|
||||
|
||||
// Adjust for binary exponent
|
||||
if (bExp >= 0)
|
||||
bS_Exp2 += bExp;
|
||||
else {
|
||||
dS_Exp2 -= bExp;
|
||||
hS_Exp2 -= bExp;
|
||||
}
|
||||
|
||||
// Adjust for half ulp exponent
|
||||
if (hExp >= 0)
|
||||
hS_Exp2 += hExp;
|
||||
else {
|
||||
dS_Exp2 -= hExp;
|
||||
bS_Exp2 -= hExp;
|
||||
}
|
||||
|
||||
// Remove common power of two factor from all three scaled values
|
||||
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
|
||||
dS_Exp2 -= common_Exp2;
|
||||
bS_Exp2 -= common_Exp2;
|
||||
hS_Exp2 -= common_Exp2;
|
||||
|
||||
BigInteger dS = d;
|
||||
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
|
||||
|
||||
BigInteger bS(bInt);
|
||||
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
|
||||
|
||||
BigInteger hS(1);
|
||||
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
|
||||
|
||||
BigInteger delta(0);
|
||||
dS.Difference(bS, &delta);
|
||||
|
||||
return delta.Compare(hS);
|
||||
}
|
||||
|
||||
inline bool StrtodFast(double d, int p, double* result) {
|
||||
// Use fast path for string-to-double conversion if possible
|
||||
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
if (p > 22 && p < 22 + 16) {
|
||||
// Fast Path Cases In Disguise
|
||||
d *= internal::Pow10(p - 22);
|
||||
p = 22;
|
||||
}
|
||||
|
||||
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||
*result = FastPath(d, p);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute an approximation and see if it is within 1/2 ULP
|
||||
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
|
||||
uint64_t significand = 0;
|
||||
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||
for (; i < dLen; i++) {
|
||||
if (significand > CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||
(significand == CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||
break;
|
||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||
}
|
||||
|
||||
if (i < dLen && decimals[i] >= '5') // Rounding
|
||||
significand++;
|
||||
|
||||
int remaining = dLen - i;
|
||||
const int kUlpShift = 3;
|
||||
const int kUlp = 1 << kUlpShift;
|
||||
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
||||
|
||||
DiyFp v(significand, 0);
|
||||
v = v.Normalize();
|
||||
error <<= -v.e;
|
||||
|
||||
dExp += remaining;
|
||||
|
||||
int actualExp;
|
||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||
if (actualExp != dExp) {
|
||||
static const DiyFp kPow10[] = {
|
||||
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
|
||||
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
|
||||
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
|
||||
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
|
||||
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
|
||||
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
|
||||
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
|
||||
};
|
||||
int adjustment = dExp - actualExp;
|
||||
CEREAL_RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
|
||||
v = v * kPow10[adjustment - 1];
|
||||
if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
|
||||
error += kUlp / 2;
|
||||
}
|
||||
|
||||
v = v * cachedPower;
|
||||
|
||||
error += kUlp + (error == 0 ? 0 : 1);
|
||||
|
||||
const int oldExp = v.e;
|
||||
v = v.Normalize();
|
||||
error <<= oldExp - v.e;
|
||||
|
||||
const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
|
||||
int precisionSize = 64 - effectiveSignificandSize;
|
||||
if (precisionSize + kUlpShift >= 64) {
|
||||
int scaleExp = (precisionSize + kUlpShift) - 63;
|
||||
v.f >>= scaleExp;
|
||||
v.e += scaleExp;
|
||||
error = (error >> scaleExp) + 1 + kUlp;
|
||||
precisionSize -= scaleExp;
|
||||
}
|
||||
|
||||
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
|
||||
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
|
||||
rounded.f++;
|
||||
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
|
||||
rounded.f >>= 1;
|
||||
rounded.e++;
|
||||
}
|
||||
}
|
||||
|
||||
*result = rounded.ToDouble();
|
||||
|
||||
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||
}
|
||||
|
||||
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
|
||||
CEREAL_RAPIDJSON_ASSERT(dLen >= 0);
|
||||
const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
|
||||
Double a(approx);
|
||||
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||
if (cmp < 0)
|
||||
return a.Value(); // within half ULP
|
||||
else if (cmp == 0) {
|
||||
// Round towards even
|
||||
if (a.Significand() & 1)
|
||||
return a.NextPositiveDouble();
|
||||
else
|
||||
return a.Value();
|
||||
}
|
||||
else // adjustment
|
||||
return a.NextPositiveDouble();
|
||||
}
|
||||
|
||||
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||
CEREAL_RAPIDJSON_ASSERT(d >= 0.0);
|
||||
CEREAL_RAPIDJSON_ASSERT(length >= 1);
|
||||
|
||||
double result = 0.0;
|
||||
if (StrtodFast(d, p, &result))
|
||||
return result;
|
||||
|
||||
CEREAL_RAPIDJSON_ASSERT(length <= INT_MAX);
|
||||
int dLen = static_cast<int>(length);
|
||||
|
||||
CEREAL_RAPIDJSON_ASSERT(length >= decimalPosition);
|
||||
CEREAL_RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
|
||||
int dExpAdjust = static_cast<int>(length - decimalPosition);
|
||||
|
||||
CEREAL_RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
|
||||
int dExp = exp - dExpAdjust;
|
||||
|
||||
// Make sure length+dExp does not overflow
|
||||
CEREAL_RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
|
||||
|
||||
// Trim leading zeros
|
||||
while (dLen > 0 && *decimals == '0') {
|
||||
dLen--;
|
||||
decimals++;
|
||||
}
|
||||
|
||||
// Trim trailing zeros
|
||||
while (dLen > 0 && decimals[dLen - 1] == '0') {
|
||||
dLen--;
|
||||
dExp++;
|
||||
}
|
||||
|
||||
if (dLen == 0) { // Buffer only contains zeros.
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Trim right-most digits
|
||||
const int kMaxDecimalDigit = 767 + 1;
|
||||
if (dLen > kMaxDecimalDigit) {
|
||||
dExp += dLen - kMaxDecimalDigit;
|
||||
dLen = kMaxDecimalDigit;
|
||||
}
|
||||
|
||||
// If too small, underflow to zero.
|
||||
// Any x <= 10^-324 is interpreted as zero.
|
||||
if (dLen + dExp <= -324)
|
||||
return 0.0;
|
||||
|
||||
// If too large, overflow to infinity.
|
||||
// Any x >= 10^309 is interpreted as +infinity.
|
||||
if (dLen + dExp > 309)
|
||||
return std::numeric_limits<double>::infinity();
|
||||
|
||||
if (StrtodDiyFp(decimals, dLen, dExp, &result))
|
||||
return result;
|
||||
|
||||
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||
return StrtodBigInteger(result, decimals, dLen, dExp);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_STRTOD_
|
||||
@@ -0,0 +1,46 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_INTERNAL_SWAP_H_
|
||||
#define CEREAL_RAPIDJSON_INTERNAL_SWAP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||
\note This has the same semantics as std::swap().
|
||||
*/
|
||||
template <typename T>
|
||||
inline void Swap(T& a, T& b) CEREAL_RAPIDJSON_NOEXCEPT {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_INTERNAL_SWAP_H_
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
#define CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <iosfwd>
|
||||
#include <ios>
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
#elif defined(_MSC_VER)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
|
||||
/*!
|
||||
The classes can be wrapped including but not limited to:
|
||||
|
||||
- \c std::istringstream
|
||||
- \c std::stringstream
|
||||
- \c std::wistringstream
|
||||
- \c std::wstringstream
|
||||
- \c std::ifstream
|
||||
- \c std::fstream
|
||||
- \c std::wifstream
|
||||
- \c std::wfstream
|
||||
|
||||
\tparam StreamType Class derived from \c std::basic_istream.
|
||||
*/
|
||||
|
||||
template <typename StreamType>
|
||||
class BasicIStreamWrapper {
|
||||
public:
|
||||
typedef typename StreamType::char_type Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param stream stream opened for read.
|
||||
*/
|
||||
BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
Read();
|
||||
}
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param stream stream opened for read.
|
||||
\param buffer user-supplied buffer.
|
||||
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||
*/
|
||||
BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
CEREAL_RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||
Read();
|
||||
}
|
||||
|
||||
Ch Peek() const { return *current_; }
|
||||
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
BasicIStreamWrapper();
|
||||
BasicIStreamWrapper(const BasicIStreamWrapper&);
|
||||
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
|
||||
|
||||
void Read() {
|
||||
if (current_ < bufferLast_)
|
||||
++current_;
|
||||
else if (!eof_) {
|
||||
count_ += readCount_;
|
||||
readCount_ = bufferSize_;
|
||||
bufferLast_ = buffer_ + readCount_ - 1;
|
||||
current_ = buffer_;
|
||||
|
||||
if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
|
||||
readCount_ = static_cast<size_t>(stream_.gcount());
|
||||
*(bufferLast_ = buffer_ + readCount_) = '\0';
|
||||
eof_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StreamType &stream_;
|
||||
Ch peekBuffer_[4], *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
|
||||
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
|
||||
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
Copyright (C) 2011 Milo Yip
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,70 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_MEMORYBUFFER_H_
|
||||
#define CEREAL_RAPIDJSON_MEMORYBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output byte stream.
|
||||
/*!
|
||||
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
|
||||
|
||||
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
|
||||
|
||||
Differences between MemoryBuffer and StringBuffer:
|
||||
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
|
||||
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
|
||||
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Allocator = CrtAllocator>
|
||||
struct GenericMemoryBuffer {
|
||||
typedef char Ch; // byte
|
||||
|
||||
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() { stack_.ShrinkToFit(); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||
|
||||
const Ch* GetBuffer() const {
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
typedef GenericMemoryBuffer<> MemoryBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
|
||||
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_MEMORYBUFFER_H_
|
||||
@@ -0,0 +1,71 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_MEMORYSTREAM_H_
|
||||
#define CEREAL_RAPIDJSON_MEMORYSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory input byte stream.
|
||||
/*!
|
||||
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
|
||||
|
||||
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
|
||||
|
||||
Differences between MemoryStream and StringStream:
|
||||
1. StringStream has encoding but MemoryStream is a byte stream.
|
||||
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
|
||||
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
|
||||
\note implements Stream concept
|
||||
*/
|
||||
struct MemoryStream {
|
||||
typedef char Ch; // byte
|
||||
|
||||
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
|
||||
|
||||
Ch Peek() const { return CEREAL_RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
|
||||
Ch Take() { return CEREAL_RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
|
||||
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
|
||||
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return Tell() + 4 <= size_ ? src_ : 0;
|
||||
}
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* begin_; //!< Original head of the string.
|
||||
const Ch* end_; //!< End of stream.
|
||||
size_t size_; //!< Size of the stream.
|
||||
};
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_MEMORYBUFFER_H_
|
||||
@@ -0,0 +1,316 @@
|
||||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The above software in this distribution may have been modified by
|
||||
// THL A29 Limited ("Tencent Modifications").
|
||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
// miloyip: VC supports inttypes.h since VC2013
|
||||
#if _MSC_VER >= 1800
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// The fscanf macros for signed integers are:
|
||||
#define SCNd8 "d"
|
||||
#define SCNi8 "i"
|
||||
#define SCNdLEAST8 "d"
|
||||
#define SCNiLEAST8 "i"
|
||||
#define SCNdFAST8 "d"
|
||||
#define SCNiFAST8 "i"
|
||||
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNdFAST16 "hd"
|
||||
#define SCNiFAST16 "hi"
|
||||
|
||||
#define SCNd32 "ld"
|
||||
#define SCNi32 "li"
|
||||
#define SCNdLEAST32 "ld"
|
||||
#define SCNiLEAST32 "li"
|
||||
#define SCNdFAST32 "ld"
|
||||
#define SCNiFAST32 "li"
|
||||
|
||||
#define SCNd64 "I64d"
|
||||
#define SCNi64 "I64i"
|
||||
#define SCNdLEAST64 "I64d"
|
||||
#define SCNiLEAST64 "I64i"
|
||||
#define SCNdFAST64 "I64d"
|
||||
#define SCNiFAST64 "I64i"
|
||||
|
||||
#define SCNdMAX "I64d"
|
||||
#define SCNiMAX "I64i"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNdPTR "I64d"
|
||||
# define SCNiPTR "I64i"
|
||||
#else // _WIN64 ][
|
||||
# define SCNdPTR "ld"
|
||||
# define SCNiPTR "li"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// The fscanf macros for unsigned integers are:
|
||||
#define SCNo8 "o"
|
||||
#define SCNu8 "u"
|
||||
#define SCNx8 "x"
|
||||
#define SCNX8 "X"
|
||||
#define SCNoLEAST8 "o"
|
||||
#define SCNuLEAST8 "u"
|
||||
#define SCNxLEAST8 "x"
|
||||
#define SCNXLEAST8 "X"
|
||||
#define SCNoFAST8 "o"
|
||||
#define SCNuFAST8 "u"
|
||||
#define SCNxFAST8 "x"
|
||||
#define SCNXFAST8 "X"
|
||||
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNxLEAST16 "hx"
|
||||
#define SCNXLEAST16 "hX"
|
||||
#define SCNoFAST16 "ho"
|
||||
#define SCNuFAST16 "hu"
|
||||
#define SCNxFAST16 "hx"
|
||||
#define SCNXFAST16 "hX"
|
||||
|
||||
#define SCNo32 "lo"
|
||||
#define SCNu32 "lu"
|
||||
#define SCNx32 "lx"
|
||||
#define SCNX32 "lX"
|
||||
#define SCNoLEAST32 "lo"
|
||||
#define SCNuLEAST32 "lu"
|
||||
#define SCNxLEAST32 "lx"
|
||||
#define SCNXLEAST32 "lX"
|
||||
#define SCNoFAST32 "lo"
|
||||
#define SCNuFAST32 "lu"
|
||||
#define SCNxFAST32 "lx"
|
||||
#define SCNXFAST32 "lX"
|
||||
|
||||
#define SCNo64 "I64o"
|
||||
#define SCNu64 "I64u"
|
||||
#define SCNx64 "I64x"
|
||||
#define SCNX64 "I64X"
|
||||
#define SCNoLEAST64 "I64o"
|
||||
#define SCNuLEAST64 "I64u"
|
||||
#define SCNxLEAST64 "I64x"
|
||||
#define SCNXLEAST64 "I64X"
|
||||
#define SCNoFAST64 "I64o"
|
||||
#define SCNuFAST64 "I64u"
|
||||
#define SCNxFAST64 "I64x"
|
||||
#define SCNXFAST64 "I64X"
|
||||
|
||||
#define SCNoMAX "I64o"
|
||||
#define SCNuMAX "I64u"
|
||||
#define SCNxMAX "I64x"
|
||||
#define SCNXMAX "I64X"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNoPTR "I64o"
|
||||
# define SCNuPTR "I64u"
|
||||
# define SCNxPTR "I64x"
|
||||
# define SCNXPTR "I64X"
|
||||
#else // _WIN64 ][
|
||||
# define SCNoPTR "lo"
|
||||
# define SCNuPTR "lu"
|
||||
# define SCNxPTR "lx"
|
||||
# define SCNXPTR "lX"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
#endif // _MSC_VER >= 1800
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
||||
@@ -0,0 +1,300 @@
|
||||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The above software in this distribution may have been modified by
|
||||
// THL A29 Limited ("Tencent Modifications").
|
||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
|
||||
#if _MSC_VER >= 1600 // [
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
#undef INT8_C
|
||||
#undef INT16_C
|
||||
#undef INT32_C
|
||||
#undef INT64_C
|
||||
#undef UINT8_C
|
||||
#undef UINT16_C
|
||||
#undef UINT32_C
|
||||
#undef UINT64_C
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#else // ] _MSC_VER >= 1700 [
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler would give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#endif // _MSC_VER >= 1600 ]
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
||||
@@ -0,0 +1,81 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
#define CEREAL_RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
|
||||
/*!
|
||||
The classes can be wrapped including but not limited to:
|
||||
|
||||
- \c std::ostringstream
|
||||
- \c std::stringstream
|
||||
- \c std::wpstringstream
|
||||
- \c std::wstringstream
|
||||
- \c std::ifstream
|
||||
- \c std::fstream
|
||||
- \c std::wofstream
|
||||
- \c std::wfstream
|
||||
|
||||
\tparam StreamType Class derived from \c std::basic_ostream.
|
||||
*/
|
||||
|
||||
template <typename StreamType>
|
||||
class BasicOStreamWrapper {
|
||||
public:
|
||||
typedef typename StreamType::char_type Ch;
|
||||
BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
|
||||
|
||||
void Put(Ch c) {
|
||||
stream_.put(c);
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
stream_.flush();
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
BasicOStreamWrapper(const BasicOStreamWrapper&);
|
||||
BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
|
||||
|
||||
StreamType& stream_;
|
||||
};
|
||||
|
||||
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
|
||||
typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
|
||||
|
||||
#ifdef __clang__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
+1414
File diff suppressed because it is too large
Load Diff
+247
-126
@@ -1,156 +1,277 @@
|
||||
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||
#define RAPIDJSON_PRETTYWRITER_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_PRETTYWRITER_H_
|
||||
#define CEREAL_RAPIDJSON_PRETTYWRITER_H_
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
namespace rapidjson {
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Combination of PrettyWriter format flags.
|
||||
/*! \see PrettyWriter::SetFormatOptions
|
||||
*/
|
||||
enum PrettyFormatOptions {
|
||||
kFormatDefault = 0, //!< Default pretty formatting.
|
||||
kFormatSingleLineArray = 1 //!< Format arrays on a single line.
|
||||
};
|
||||
|
||||
//! Writer with indentation and spacing.
|
||||
/*!
|
||||
\tparam Stream Type of ouptut stream.
|
||||
\tparam Encoding Encoding of both source strings and output.
|
||||
\tparam Allocator Type of allocator for allocating memory of stack.
|
||||
\tparam OutputStream Type of output os.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||
*/
|
||||
template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
|
||||
public:
|
||||
typedef Writer<Stream, Encoding, Allocator> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param stream Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of
|
||||
*/
|
||||
PrettyWriter(Stream& stream, int precision = 20, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(stream, precision, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
|
||||
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//@name Implementation of Handler.
|
||||
//@{
|
||||
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; }
|
||||
PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; }
|
||||
PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; }
|
||||
PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; }
|
||||
PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
|
||||
PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
|
||||
PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
|
||||
#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
PrettyWriter(PrettyWriter&& rhs) :
|
||||
Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
|
||||
#endif
|
||||
|
||||
PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
Base::WriteString(str, length);
|
||||
return *this;
|
||||
}
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
CEREAL_RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
Base::WriteStartObject();
|
||||
return *this;
|
||||
}
|
||||
//! Set pretty writer formatting options.
|
||||
/*! \param options Formatting options.
|
||||
*/
|
||||
PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
|
||||
formatOptions_ = options;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
/*! @name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
if (!empty) {
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
Base::WriteEndObject();
|
||||
return *this;
|
||||
}
|
||||
bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); }
|
||||
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }
|
||||
bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }
|
||||
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }
|
||||
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }
|
||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); }
|
||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }
|
||||
|
||||
PrettyWriter& StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||
Base::WriteStartArray();
|
||||
return *this;
|
||||
}
|
||||
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||
CEREAL_RAPIDJSON_ASSERT(str != 0);
|
||||
(void)copy;
|
||||
PrettyPrefix(kNumberType);
|
||||
return Base::EndValue(Base::WriteString(str, length));
|
||||
}
|
||||
|
||||
PrettyWriter& EndArray(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
CEREAL_RAPIDJSON_ASSERT(str != 0);
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
return Base::EndValue(Base::WriteString(str, length));
|
||||
}
|
||||
|
||||
if (!empty) {
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
Base::WriteEndArray();
|
||||
return *this;
|
||||
}
|
||||
#if CEREAL_RAPIDJSON_HAS_STDSTRING
|
||||
bool String(const std::basic_string<Ch>& str) {
|
||||
return String(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
//@}
|
||||
bool StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
return Base::WriteStartObject();
|
||||
}
|
||||
|
||||
//! Simpler but slower overload.
|
||||
PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
#if CEREAL_RAPIDJSON_HAS_STDSTRING
|
||||
bool Key(const std::basic_string<Ch>& str) {
|
||||
return Key(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
|
||||
CEREAL_RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
|
||||
CEREAL_RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
|
||||
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
bool ret = Base::EndValue(Base::WriteEndObject());
|
||||
(void)ret;
|
||||
CEREAL_RAPIDJSON_ASSERT(ret == true);
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||
return Base::WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
bool ret = Base::EndValue(Base::WriteEndArray());
|
||||
(void)ret;
|
||||
CEREAL_RAPIDJSON_ASSERT(ret == true);
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
|
||||
//! Write a raw JSON value.
|
||||
/*!
|
||||
For user to write a stringified JSON as a value.
|
||||
|
||||
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
|
||||
\param length Length of the json.
|
||||
\param type Type of the root of json.
|
||||
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
|
||||
*/
|
||||
bool RawValue(const Ch* json, size_t length, Type type) {
|
||||
CEREAL_RAPIDJSON_ASSERT(json != 0);
|
||||
PrettyPrefix(type);
|
||||
return Base::EndValue(Base::WriteRawValue(json, length));
|
||||
}
|
||||
|
||||
protected:
|
||||
void PrettyPrefix(Type type) {
|
||||
(void)type;
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
void PrettyPrefix(Type type) {
|
||||
(void)type;
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::stream_.Put(','); // add comma if it is not the first element in array
|
||||
Base::stream_.Put('\n');
|
||||
}
|
||||
else
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::stream_.Put(',');
|
||||
Base::stream_.Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::stream_.Put(':');
|
||||
Base::stream_.Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::stream_.Put('\n');
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::os_->Put(','); // add comma if it is not the first element in array
|
||||
if (formatOptions_ & kFormatSingleLineArray)
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
}
|
||||
if (!(formatOptions_ & kFormatSingleLineArray)) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::os_->Put(',');
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::os_->Put(':');
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::os_->Put('\n');
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(Base::stream_, indentChar_, count);
|
||||
}
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
CEREAL_RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
CEREAL_RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
|
||||
Base::hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
PrettyFormatOptions formatOptions_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
PrettyWriter(const PrettyWriter&);
|
||||
PrettyWriter& operator=(const PrettyWriter&);
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_CEREAL_RAPIDJSON_H_
|
||||
|
||||
+656
-525
File diff suppressed because it is too large
Load Diff
+2085
-548
File diff suppressed because it is too large
Load Diff
+2497
File diff suppressed because it is too large
Load Diff
+223
@@ -0,0 +1,223 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_STREAM_H_
|
||||
#define CEREAL_RAPIDJSON_STREAM_H_
|
||||
|
||||
#include "encodings.h"
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stream
|
||||
|
||||
/*! \class rapidjson::Stream
|
||||
\brief Concept for reading and writing characters.
|
||||
|
||||
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
|
||||
|
||||
For write-only stream, only need to implement Put() and Flush().
|
||||
|
||||
\code
|
||||
concept Stream {
|
||||
typename Ch; //!< Character type of the stream.
|
||||
|
||||
//! Read the current character from stream without moving the read cursor.
|
||||
Ch Peek() const;
|
||||
|
||||
//! Read the current character from stream and moving the read cursor to next character.
|
||||
Ch Take();
|
||||
|
||||
//! Get the current read cursor.
|
||||
//! \return Number of characters read from start.
|
||||
size_t Tell();
|
||||
|
||||
//! Begin writing operation at the current read pointer.
|
||||
//! \return The begin writer pointer.
|
||||
Ch* PutBegin();
|
||||
|
||||
//! Write a character.
|
||||
void Put(Ch c);
|
||||
|
||||
//! Flush the buffer.
|
||||
void Flush();
|
||||
|
||||
//! End the writing operation.
|
||||
//! \param begin The begin write pointer returned by PutBegin().
|
||||
//! \return Number of characters written.
|
||||
size_t PutEnd(Ch* begin);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//! Provides additional information for stream.
|
||||
/*!
|
||||
By using traits pattern, this type provides a default configuration for stream.
|
||||
For custom stream, this type can be specialized for other configuration.
|
||||
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
|
||||
*/
|
||||
template<typename Stream>
|
||||
struct StreamTraits {
|
||||
//! Whether to make local copy of stream for optimization during parsing.
|
||||
/*!
|
||||
By default, for safety, streams do not use local copy optimization.
|
||||
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
|
||||
*/
|
||||
enum { copyOptimization = 0 };
|
||||
};
|
||||
|
||||
//! Reserve n characters for writing to a stream.
|
||||
template<typename Stream>
|
||||
inline void PutReserve(Stream& stream, size_t count) {
|
||||
(void)stream;
|
||||
(void)count;
|
||||
}
|
||||
|
||||
//! Write character to a stream, presuming buffer is reserved.
|
||||
template<typename Stream>
|
||||
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
|
||||
stream.Put(c);
|
||||
}
|
||||
|
||||
//! Put N copies of a character to a stream.
|
||||
template<typename Stream, typename Ch>
|
||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
PutReserve(stream, n);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
PutUnsafe(stream, c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericStreamWrapper
|
||||
|
||||
//! A Stream Wrapper
|
||||
/*! \tThis string stream is a wrapper for any stream by just forwarding any
|
||||
\treceived message to the origin stream.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
template <typename InputStream, typename Encoding = UTF8<> >
|
||||
class GenericStreamWrapper {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
GenericStreamWrapper(InputStream& is): is_(is) {}
|
||||
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() { return is_.Tell(); }
|
||||
Ch* PutBegin() { return is_.PutBegin(); }
|
||||
void Put(Ch ch) { is_.Put(ch); }
|
||||
void Flush() { is_.Flush(); }
|
||||
size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }
|
||||
|
||||
// wrapper for MemoryStream
|
||||
const Ch* Peek4() const { return is_.Peek4(); }
|
||||
|
||||
// wrapper for AutoUTFInputStream
|
||||
UTFType GetType() const { return is_.GetType(); }
|
||||
bool HasBOM() const { return is_.HasBOM(); }
|
||||
|
||||
protected:
|
||||
InputStream& is_;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
//! Read-only string stream.
|
||||
/*! \note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||
|
||||
Ch Peek() const { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* head_; //!< Original head of the string.
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! String stream with UTF8 encoding.
|
||||
typedef GenericStringStream<UTF8<> > StringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InsituStringStream
|
||||
|
||||
//! A read-write string stream.
|
||||
/*! This string stream is particularly designed for in-situ parsing.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
|
||||
|
||||
// Read
|
||||
Ch Peek() { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
// Write
|
||||
void Put(Ch c) { CEREAL_RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||
|
||||
Ch* PutBegin() { return dst_ = src_; }
|
||||
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
|
||||
void Flush() {}
|
||||
|
||||
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
|
||||
void Pop(size_t count) { dst_ -= count; }
|
||||
|
||||
Ch* src_;
|
||||
Ch* dst_;
|
||||
Ch* head_;
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericInsituStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! Insitu string stream with UTF8 encoding.
|
||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_STREAM_H_
|
||||
+121
-49
@@ -1,49 +1,121 @@
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\implements Stream
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
struct GenericStringBuffer {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
|
||||
const char* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t Size() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef CEREAL_RAPIDJSON_STRINGBUFFER_H_
|
||||
#define CEREAL_RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#include <utility> // std::move
|
||||
#endif
|
||||
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_PUSH
|
||||
CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericStringBuffer {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
#if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
|
||||
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
|
||||
if (&rhs != this)
|
||||
stack_ = std::move(rhs.stack_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.ShrinkToFit();
|
||||
stack_.template Pop<Ch>(1);
|
||||
}
|
||||
|
||||
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
|
||||
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||
|
||||
const Ch* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
//! Get the size of string in bytes in the string buffer.
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
//! Get the length of string in Ch in the string buffer.
|
||||
size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
GenericStringBuffer(const GenericStringBuffer&);
|
||||
GenericStringBuffer& operator=(const GenericStringBuffer&);
|
||||
};
|
||||
|
||||
//! String buffer with UTF8 encoding
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
|
||||
stream.Reserve(count);
|
||||
}
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
|
||||
stream.PutUnsafe(c);
|
||||
}
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
CEREAL_RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
CEREAL_RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // CEREAL_RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
+709
-302
File diff suppressed because it is too large
Load Diff
+185
-156
@@ -1,12 +1,12 @@
|
||||
#ifndef RAPIDXML_HPP_INCLUDED
|
||||
#define RAPIDXML_HPP_INCLUDED
|
||||
#ifndef CEREAL_RAPIDXML_HPP_INCLUDED
|
||||
#define CEREAL_RAPIDXML_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
|
||||
// If standard library is disabled, user must provide implementations of required functions and typedefs
|
||||
#if !defined(RAPIDXML_NO_STDLIB)
|
||||
#if !defined(CEREAL_RAPIDXML_NO_STDLIB)
|
||||
#include <cstdlib> // For std::size_t
|
||||
#include <cassert> // For assert
|
||||
#include <new> // For placement new
|
||||
@@ -17,18 +17,20 @@
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // Conditional expression is constant
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDXML_PARSE_ERROR
|
||||
// CEREAL_RAPIDXML_PARSE_ERROR
|
||||
|
||||
#if defined(RAPIDXML_NO_EXCEPTIONS)
|
||||
#if defined(CEREAL_RAPIDXML_NO_EXCEPTIONS)
|
||||
|
||||
#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); }
|
||||
#define CEREAL_RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); }
|
||||
|
||||
namespace cereal {
|
||||
namespace rapidxml
|
||||
{
|
||||
//! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS,
|
||||
//! When exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS,
|
||||
//! this function is called to notify user about the error.
|
||||
//! It must be defined by the user.
|
||||
//! <br><br>
|
||||
@@ -46,13 +48,15 @@ namespace rapidxml
|
||||
//! \param where Pointer to character data where error was detected.
|
||||
void parse_error_handler(const char *what, void *where);
|
||||
}
|
||||
} // end namespace cereal
|
||||
|
||||
#else
|
||||
|
||||
#include <exception> // For std::exception
|
||||
|
||||
#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
|
||||
#define CEREAL_RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
|
||||
|
||||
namespace cereal {
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
@@ -62,7 +66,7 @@ namespace rapidxml
|
||||
//! Use where() function to get a pointer to position within source text where error was detected.
|
||||
//! <br><br>
|
||||
//! If throwing exceptions by the parser is undesirable,
|
||||
//! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included.
|
||||
//! it can be disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included.
|
||||
//! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception.
|
||||
//! This function must be defined by the user.
|
||||
//! <br><br>
|
||||
@@ -73,15 +77,15 @@ namespace rapidxml
|
||||
public:
|
||||
|
||||
//! Constructs parse error
|
||||
parse_error(const char *what, void *where)
|
||||
: m_what(what)
|
||||
, m_where(where)
|
||||
parse_error(const char *what_, void *where_)
|
||||
: m_what(what_)
|
||||
, m_where(where_)
|
||||
{
|
||||
}
|
||||
|
||||
//! Gets human readable description of error.
|
||||
//! \return Pointer to null terminated description of the error.
|
||||
virtual const char *what() const throw()
|
||||
virtual const char *what() const CEREAL_NOEXCEPT override
|
||||
{
|
||||
return m_what;
|
||||
}
|
||||
@@ -102,34 +106,36 @@ namespace rapidxml
|
||||
|
||||
};
|
||||
}
|
||||
} // end namespace cereal
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Pool sizes
|
||||
|
||||
#ifndef RAPIDXML_STATIC_POOL_SIZE
|
||||
#ifndef CEREAL_RAPIDXML_STATIC_POOL_SIZE
|
||||
// Size of static memory block of memory_pool.
|
||||
// Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
|
||||
// Define CEREAL_RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
|
||||
// No dynamic memory allocations are performed by memory_pool until static memory is exhausted.
|
||||
#define RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
|
||||
#define CEREAL_RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDXML_DYNAMIC_POOL_SIZE
|
||||
#ifndef CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE
|
||||
// Size of dynamic memory block of memory_pool.
|
||||
// Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
|
||||
// Define CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
|
||||
// After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool.
|
||||
#define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
|
||||
#define CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDXML_ALIGNMENT
|
||||
#ifndef CEREAL_RAPIDXML_ALIGNMENT
|
||||
// Memory allocation alignment.
|
||||
// Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer.
|
||||
// Define CEREAL_RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer.
|
||||
// All memory allocations for nodes, attributes and strings will be aligned to this value.
|
||||
// This must be a power of 2 and at least 1, otherwise memory_pool will not work.
|
||||
#define RAPIDXML_ALIGNMENT sizeof(void *)
|
||||
#define CEREAL_RAPIDXML_ALIGNMENT sizeof(void *)
|
||||
#endif
|
||||
|
||||
namespace cereal {
|
||||
namespace rapidxml
|
||||
{
|
||||
// Forward declarations
|
||||
@@ -311,7 +317,7 @@ namespace rapidxml
|
||||
const Ch *tmp = p;
|
||||
while (*tmp)
|
||||
++tmp;
|
||||
return tmp - p;
|
||||
return static_cast<std::size_t>(tmp - p);
|
||||
}
|
||||
|
||||
// Compare strings for equality
|
||||
@@ -334,6 +340,14 @@ namespace rapidxml
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
inline bool preserve_space(xml_node<Ch>* node)
|
||||
{
|
||||
const Ch preserve_value[] = { Ch('p'), Ch('r'), Ch('e'), Ch('s'), Ch('e'), Ch('r'), Ch('v'), Ch('e') };
|
||||
const xml_attribute<Ch>* space = node->first_attribute("xml:space");
|
||||
return space && internal::compare(space->value(), space->value_size(), preserve_value, sizeof(preserve_value) / sizeof(Ch), true);
|
||||
}
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
@@ -357,23 +371,23 @@ namespace rapidxml
|
||||
//! It is also possible to create a standalone memory_pool, and use it
|
||||
//! to allocate nodes, whose lifetime will not be tied to any document.
|
||||
//! <br><br>
|
||||
//! Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory.
|
||||
//! Pool maintains <code>CEREAL_RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory.
|
||||
//! Until static memory is exhausted, no dynamic memory allocations are done.
|
||||
//! When static memory is exhausted, pool allocates additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> each,
|
||||
//! When static memory is exhausted, pool allocates additional blocks of memory of size <code>CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE</code> each,
|
||||
//! by using global <code>new[]</code> and <code>delete[]</code> operators.
|
||||
//! This behaviour can be changed by setting custom allocation routines.
|
||||
//! Use set_allocator() function to set them.
|
||||
//! <br><br>
|
||||
//! Allocations for nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code> bytes.
|
||||
//! Allocations for nodes, attributes and strings are aligned at <code>CEREAL_RAPIDXML_ALIGNMENT</code> bytes.
|
||||
//! This value defaults to the size of pointer on target architecture.
|
||||
//! <br><br>
|
||||
//! To obtain absolutely top performance from the parser,
|
||||
//! it is important that all nodes are allocated from a single, contiguous block of memory.
|
||||
//! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably.
|
||||
//! If required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code>
|
||||
//! If required, you can tweak <code>CEREAL_RAPIDXML_STATIC_POOL_SIZE</code>, <code>CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>CEREAL_RAPIDXML_ALIGNMENT</code>
|
||||
//! to obtain best wasted memory to performance compromise.
|
||||
//! To do it, define their values before rapidxml.hpp file is included.
|
||||
//! \param Ch Character type of created nodes.
|
||||
//! \tparam Ch Character type of created nodes.
|
||||
template<class Ch = char>
|
||||
class memory_pool
|
||||
{
|
||||
@@ -403,7 +417,7 @@ namespace rapidxml
|
||||
|
||||
//! Allocates a new node from the pool, and optionally assigns name and value to it.
|
||||
//! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
|
||||
//! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
|
||||
//! If exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS, this function
|
||||
//! will call rapidxml::parse_error_handler() function.
|
||||
//! \param type Type of node to create.
|
||||
//! \param name Name to assign to the node, or 0 to assign no name.
|
||||
@@ -436,7 +450,7 @@ namespace rapidxml
|
||||
|
||||
//! Allocates a new attribute from the pool, and optionally assigns name and value to it.
|
||||
//! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
|
||||
//! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
|
||||
//! If exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS, this function
|
||||
//! will call rapidxml::parse_error_handler() function.
|
||||
//! \param name Name to assign to the attribute, or 0 to assign no name.
|
||||
//! \param value Value to assign to the attribute, or 0 to assign no value.
|
||||
@@ -467,7 +481,7 @@ namespace rapidxml
|
||||
|
||||
//! Allocates a char array of given size from the pool, and optionally copies a given string to it.
|
||||
//! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
|
||||
//! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
|
||||
//! If exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS, this function
|
||||
//! will call rapidxml::parse_error_handler() function.
|
||||
//! \param source String to initialize the allocated memory with, or 0 to not initialize it.
|
||||
//! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.
|
||||
@@ -571,7 +585,7 @@ namespace rapidxml
|
||||
|
||||
char *align(char *ptr)
|
||||
{
|
||||
std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1));
|
||||
std::size_t alignment = ((CEREAL_RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (CEREAL_RAPIDXML_ALIGNMENT - 1))) & (CEREAL_RAPIDXML_ALIGNMENT - 1));
|
||||
return ptr + alignment;
|
||||
}
|
||||
|
||||
@@ -587,9 +601,9 @@ namespace rapidxml
|
||||
else
|
||||
{
|
||||
memory = new char[size];
|
||||
#ifdef RAPIDXML_NO_EXCEPTIONS
|
||||
#ifdef CEREAL_RAPIDXML_NO_EXCEPTIONS
|
||||
if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc
|
||||
RAPIDXML_PARSE_ERROR("out of memory", 0);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("out of memory", 0);
|
||||
#endif
|
||||
}
|
||||
return static_cast<char *>(memory);
|
||||
@@ -603,13 +617,13 @@ namespace rapidxml
|
||||
// If not enough memory left in current pool, allocate a new pool
|
||||
if (result + size > m_end)
|
||||
{
|
||||
// Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE)
|
||||
std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE;
|
||||
// Calculate required pool size (may be bigger than CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE)
|
||||
std::size_t pool_size = CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE;
|
||||
if (pool_size < size)
|
||||
pool_size = size;
|
||||
|
||||
// Allocate
|
||||
std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation
|
||||
std::size_t alloc_size = sizeof(header) + (2 * CEREAL_RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation
|
||||
char *raw_memory = allocate_raw(alloc_size);
|
||||
|
||||
// Setup new pool in allocated memory
|
||||
@@ -632,7 +646,7 @@ namespace rapidxml
|
||||
char *m_begin; // Start of raw memory making up current pool
|
||||
char *m_ptr; // First free byte in current pool
|
||||
char *m_end; // One past last available byte in current pool
|
||||
char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory
|
||||
char m_static_memory[CEREAL_RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory
|
||||
alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used
|
||||
free_func *m_free_func; // Free function, or 0 if default is to be used
|
||||
};
|
||||
@@ -642,7 +656,7 @@ namespace rapidxml
|
||||
|
||||
//! Base class for xml_node and xml_attribute implementing common functions:
|
||||
//! name(), name_size(), value(), value_size() and parent().
|
||||
//! \param Ch Character type to use
|
||||
//! \tparam Ch Character type to use
|
||||
template<class Ch = char>
|
||||
class xml_base
|
||||
{
|
||||
@@ -715,20 +729,20 @@ namespace rapidxml
|
||||
//! <br><br>
|
||||
//! Size of name must be specified separately, because name does not have to be zero terminated.
|
||||
//! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).
|
||||
//! \param name Name of node to set. Does not have to be zero terminated.
|
||||
//! \param name_ Name of node to set. Does not have to be zero terminated.
|
||||
//! \param size Size of name, in characters. This does not include zero terminator, if one is present.
|
||||
void name(const Ch *name, std::size_t size)
|
||||
void name(const Ch *name_, std::size_t size)
|
||||
{
|
||||
m_name = const_cast<Ch *>(name);
|
||||
m_name = const_cast<Ch *>(name_);
|
||||
m_name_size = size;
|
||||
}
|
||||
|
||||
//! Sets name of node to a zero-terminated string.
|
||||
//! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
|
||||
//! \param name Name of node to set. Must be zero terminated.
|
||||
void name(const Ch *name)
|
||||
//! \param name_ Name of node to set. Must be zero terminated.
|
||||
void name(const Ch *name_)
|
||||
{
|
||||
this->name(name, internal::measure(name));
|
||||
this->name(name_, internal::measure(name_));
|
||||
}
|
||||
|
||||
//! Sets value of node to a non zero-terminated string.
|
||||
@@ -745,20 +759,20 @@ namespace rapidxml
|
||||
//! <br><br>
|
||||
//! If an element has a child node of type node_data, it will take precedence over element value when printing.
|
||||
//! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.
|
||||
//! \param value value of node to set. Does not have to be zero terminated.
|
||||
//! \param value_ value of node to set. Does not have to be zero terminated.
|
||||
//! \param size Size of value, in characters. This does not include zero terminator, if one is present.
|
||||
void value(const Ch *value, std::size_t size)
|
||||
void value(const Ch *value_, std::size_t size)
|
||||
{
|
||||
m_value = const_cast<Ch *>(value);
|
||||
m_value = const_cast<Ch *>(value_);
|
||||
m_value_size = size;
|
||||
}
|
||||
|
||||
//! Sets value of node to a zero-terminated string.
|
||||
//! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
|
||||
//! \param value Vame of node to set. Must be zero terminated.
|
||||
void value(const Ch *value)
|
||||
//! \param value_ Vame of node to set. Must be zero terminated.
|
||||
void value(const Ch *value_)
|
||||
{
|
||||
this->value(value, internal::measure(value));
|
||||
this->value(value_, internal::measure(value_));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -792,7 +806,7 @@ namespace rapidxml
|
||||
//! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base).
|
||||
//! Note that after parse, both name and value of attribute will point to interior of source text used for parsing.
|
||||
//! Thus, this text must persist in memory for the lifetime of attribute.
|
||||
//! \param Ch Character type to use.
|
||||
//! \tparam Ch Character type to use.
|
||||
template<class Ch = char>
|
||||
class xml_attribute: public xml_base<Ch>
|
||||
{
|
||||
@@ -848,18 +862,18 @@ namespace rapidxml
|
||||
}
|
||||
|
||||
//! Gets next attribute, optionally matching attribute name.
|
||||
//! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param name_ Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
|
||||
//! \return Pointer to found attribute, or 0 if not found.
|
||||
xml_attribute<Ch> *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
|
||||
xml_attribute<Ch> *next_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
|
||||
{
|
||||
if (name)
|
||||
if (name_)
|
||||
{
|
||||
if (name_size == 0)
|
||||
name_size = internal::measure(name);
|
||||
if (name_size_ == 0)
|
||||
name_size_ = internal::measure(name_);
|
||||
for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute)
|
||||
if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
|
||||
if (internal::compare(attribute->name(), attribute->name_size(), name_, name_size_, case_sensitive))
|
||||
return attribute;
|
||||
return 0;
|
||||
}
|
||||
@@ -884,7 +898,7 @@ namespace rapidxml
|
||||
//! <br><br>
|
||||
//! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing.
|
||||
//! Thus, this text must persist in the memory for the lifetime of node.
|
||||
//! \param Ch Character type to use.
|
||||
//! \tparam Ch Character type to use.
|
||||
template<class Ch = char>
|
||||
class xml_node: public xml_base<Ch>
|
||||
{
|
||||
@@ -896,9 +910,9 @@ namespace rapidxml
|
||||
|
||||
//! Constructs an empty node with the specified type.
|
||||
//! Consider using memory_pool of appropriate document to allocate nodes manually.
|
||||
//! \param type Type of node to construct.
|
||||
xml_node(node_type type)
|
||||
: m_type(type)
|
||||
//! \param type_ Type of node to construct.
|
||||
xml_node(node_type type_)
|
||||
: m_type(type_)
|
||||
, m_first_node(0)
|
||||
, m_first_attribute(0)
|
||||
{
|
||||
@@ -928,18 +942,18 @@ namespace rapidxml
|
||||
}
|
||||
|
||||
//! Gets first child node, optionally matching node name.
|
||||
//! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param name_ Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
|
||||
//! \return Pointer to found child, or 0 if not found.
|
||||
xml_node<Ch> *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
|
||||
xml_node<Ch> *first_node(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
|
||||
{
|
||||
if (name)
|
||||
if (name_)
|
||||
{
|
||||
if (name_size == 0)
|
||||
name_size = internal::measure(name);
|
||||
if (name_size_ == 0)
|
||||
name_size_ = internal::measure(name_);
|
||||
for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
|
||||
if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
|
||||
if (internal::compare(child->name(), child->name_size(), name_, name_size_, case_sensitive))
|
||||
return child;
|
||||
return 0;
|
||||
}
|
||||
@@ -996,19 +1010,19 @@ namespace rapidxml
|
||||
//! Gets next sibling node, optionally matching node name.
|
||||
//! Behaviour is undefined if node has no parent.
|
||||
//! Use parent() to test if node has a parent.
|
||||
//! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param name_ Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
|
||||
//! \return Pointer to found sibling, or 0 if not found.
|
||||
xml_node<Ch> *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
|
||||
xml_node<Ch> *next_sibling(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
|
||||
{
|
||||
assert(this->m_parent); // Cannot query for siblings if node has no parent
|
||||
if (name)
|
||||
if (name_)
|
||||
{
|
||||
if (name_size == 0)
|
||||
name_size = internal::measure(name);
|
||||
if (name_size_ == 0)
|
||||
name_size_ = internal::measure(name_);
|
||||
for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
|
||||
if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
|
||||
if (internal::compare(sibling->name(), sibling->name_size(), name_, name_size_, case_sensitive))
|
||||
return sibling;
|
||||
return 0;
|
||||
}
|
||||
@@ -1017,18 +1031,18 @@ namespace rapidxml
|
||||
}
|
||||
|
||||
//! Gets first attribute of node, optionally matching attribute name.
|
||||
//! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param name_ Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
|
||||
//! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
|
||||
//! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
|
||||
//! \return Pointer to found attribute, or 0 if not found.
|
||||
xml_attribute<Ch> *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
|
||||
xml_attribute<Ch> *first_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
|
||||
{
|
||||
if (name)
|
||||
if (name_)
|
||||
{
|
||||
if (name_size == 0)
|
||||
name_size = internal::measure(name);
|
||||
if (name_size_ == 0)
|
||||
name_size_ = internal::measure(name_);
|
||||
for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute)
|
||||
if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
|
||||
if (internal::compare(attribute->name(), attribute->name_size(), name_, name_size_, case_sensitive))
|
||||
return attribute;
|
||||
return 0;
|
||||
}
|
||||
@@ -1060,10 +1074,10 @@ namespace rapidxml
|
||||
// Node modification
|
||||
|
||||
//! Sets type of node.
|
||||
//! \param type Type of node to set.
|
||||
void type(node_type type)
|
||||
//! \param type_ Type of node to set.
|
||||
void type(node_type type_)
|
||||
{
|
||||
m_type = type;
|
||||
m_type = type_;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -1352,7 +1366,7 @@ namespace rapidxml
|
||||
//! parse() function allocates memory for nodes and attributes by using functions of xml_document,
|
||||
//! which are inherited from memory_pool.
|
||||
//! To access root node of the document, use the document itself, as if it was an xml_node.
|
||||
//! \param Ch Character type to use.
|
||||
//! \tparam Ch Character type to use.
|
||||
template<class Ch = char>
|
||||
class xml_document: public xml_node<Ch>, public memory_pool<Ch>
|
||||
{
|
||||
@@ -1404,7 +1418,7 @@ namespace rapidxml
|
||||
this->append_node(node);
|
||||
}
|
||||
else
|
||||
RAPIDXML_PARSE_ERROR("expected <", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected <", text);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1513,7 +1527,7 @@ namespace rapidxml
|
||||
{
|
||||
// Insert 8-bit ASCII character
|
||||
// Todo: possibly verify that code is less than 256 and use replacement char otherwise?
|
||||
text[0] = static_cast<unsigned char>(code);
|
||||
text[0] = static_cast<Ch>(code);
|
||||
text += 1;
|
||||
}
|
||||
else
|
||||
@@ -1521,33 +1535,33 @@ namespace rapidxml
|
||||
// Insert UTF8 sequence
|
||||
if (code < 0x80) // 1 byte sequence
|
||||
{
|
||||
text[0] = static_cast<unsigned char>(code);
|
||||
text[0] = static_cast<Ch>(code);
|
||||
text += 1;
|
||||
}
|
||||
else if (code < 0x800) // 2 byte sequence
|
||||
{
|
||||
text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[0] = static_cast<unsigned char>(code | 0xC0);
|
||||
text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[0] = static_cast<Ch>(code | 0xC0);
|
||||
text += 2;
|
||||
}
|
||||
else if (code < 0x10000) // 3 byte sequence
|
||||
{
|
||||
text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[0] = static_cast<unsigned char>(code | 0xE0);
|
||||
text[2] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[0] = static_cast<Ch>(code | 0xE0);
|
||||
text += 3;
|
||||
}
|
||||
else if (code < 0x110000) // 4 byte sequence
|
||||
{
|
||||
text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[0] = static_cast<unsigned char>(code | 0xF0);
|
||||
text[3] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[2] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
|
||||
text[0] = static_cast<Ch>(code | 0xF0);
|
||||
text += 4;
|
||||
}
|
||||
else // Invalid, only codes up to 0x10FFFF are allowed in Unicode
|
||||
{
|
||||
RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1566,7 +1580,7 @@ namespace rapidxml
|
||||
// - replacing XML character entity references with proper characters (' & " < > &#...;)
|
||||
// - condensing whitespace sequences to single space character
|
||||
template<class StopPred, class StopPredPure, int Flags>
|
||||
static Ch *skip_and_expand_character_refs(Ch *&text)
|
||||
static Ch *skip_and_expand_character_refs(Ch *&text, bool preserve_space)
|
||||
{
|
||||
// If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
|
||||
if (Flags & parse_no_entity_translation &&
|
||||
@@ -1678,7 +1692,7 @@ namespace rapidxml
|
||||
if (*src == Ch(';'))
|
||||
++src;
|
||||
else
|
||||
RAPIDXML_PARSE_ERROR("expected ;", src);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected ;", src);
|
||||
continue;
|
||||
|
||||
// Something else
|
||||
@@ -1691,7 +1705,7 @@ namespace rapidxml
|
||||
}
|
||||
|
||||
// If whitespace condensing is enabled
|
||||
if (Flags & parse_normalize_whitespace)
|
||||
if ((Flags & parse_normalize_whitespace) && !preserve_space)
|
||||
{
|
||||
// Test if condensing is needed
|
||||
if (whitespace_pred::test(*src))
|
||||
@@ -1743,7 +1757,7 @@ namespace rapidxml
|
||||
while (text[0] != Ch('?') || text[1] != Ch('>'))
|
||||
{
|
||||
if (!text[0])
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
text += 2; // Skip '?>'
|
||||
@@ -1761,7 +1775,7 @@ namespace rapidxml
|
||||
|
||||
// Skip ?>
|
||||
if (text[0] != Ch('?') || text[1] != Ch('>'))
|
||||
RAPIDXML_PARSE_ERROR("expected ?>", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected ?>", text);
|
||||
text += 2;
|
||||
|
||||
return declaration;
|
||||
@@ -1778,7 +1792,7 @@ namespace rapidxml
|
||||
while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
|
||||
{
|
||||
if (!text[0])
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
text += 3; // Skip '-->'
|
||||
@@ -1786,19 +1800,19 @@ namespace rapidxml
|
||||
}
|
||||
|
||||
// Remember value start
|
||||
Ch *value = text;
|
||||
Ch *value_ = text;
|
||||
|
||||
// Skip until end of comment
|
||||
while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
|
||||
{
|
||||
if (!text[0])
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
|
||||
// Create comment node
|
||||
xml_node<Ch> *comment = this->allocate_node(node_comment);
|
||||
comment->value(value, text - value);
|
||||
comment->value(value_, static_cast<std::size_t>(text - value_));
|
||||
|
||||
// Place zero terminator after comment value
|
||||
if (!(Flags & parse_no_string_terminators))
|
||||
@@ -1813,7 +1827,7 @@ namespace rapidxml
|
||||
xml_node<Ch> *parse_doctype(Ch *&text)
|
||||
{
|
||||
// Remember value start
|
||||
Ch *value = text;
|
||||
Ch *value_ = text;
|
||||
|
||||
// Skip to >
|
||||
while (*text != Ch('>'))
|
||||
@@ -1834,7 +1848,7 @@ namespace rapidxml
|
||||
{
|
||||
case Ch('['): ++depth; break;
|
||||
case Ch(']'): --depth; break;
|
||||
case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
case 0: CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
}
|
||||
++text;
|
||||
}
|
||||
@@ -1843,7 +1857,7 @@ namespace rapidxml
|
||||
|
||||
// Error on end of text
|
||||
case Ch('\0'):
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
|
||||
// Other character, skip it
|
||||
default:
|
||||
@@ -1857,7 +1871,7 @@ namespace rapidxml
|
||||
{
|
||||
// Create a new doctype node
|
||||
xml_node<Ch> *doctype = this->allocate_node(node_doctype);
|
||||
doctype->value(value, text - value);
|
||||
doctype->value(value_, static_cast<std::size_t>(text - value_));
|
||||
|
||||
// Place zero terminator after value
|
||||
if (!(Flags & parse_no_string_terminators))
|
||||
@@ -1885,28 +1899,28 @@ namespace rapidxml
|
||||
xml_node<Ch> *pi = this->allocate_node(node_pi);
|
||||
|
||||
// Extract PI target name
|
||||
Ch *name = text;
|
||||
Ch *name_ = text;
|
||||
skip<node_name_pred, Flags>(text);
|
||||
if (text == name)
|
||||
RAPIDXML_PARSE_ERROR("expected PI target", text);
|
||||
pi->name(name, text - name);
|
||||
if (text == name_)
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected PI target", text);
|
||||
pi->name(name_, static_cast<std::size_t>(text - name_));
|
||||
|
||||
// Skip whitespace between pi target and pi
|
||||
skip<whitespace_pred, Flags>(text);
|
||||
|
||||
// Remember start of pi
|
||||
Ch *value = text;
|
||||
Ch *value_ = text;
|
||||
|
||||
// Skip to '?>'
|
||||
while (text[0] != Ch('?') || text[1] != Ch('>'))
|
||||
{
|
||||
if (*text == Ch('\0'))
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
|
||||
// Set pi value (verbatim, no entity expansion or whitespace normalization)
|
||||
pi->value(value, text - value);
|
||||
pi->value(value_, static_cast<std::size_t>(text - value_));
|
||||
|
||||
// Place zero terminator after name and value
|
||||
if (!(Flags & parse_no_string_terminators))
|
||||
@@ -1924,7 +1938,7 @@ namespace rapidxml
|
||||
while (text[0] != Ch('?') || text[1] != Ch('>'))
|
||||
{
|
||||
if (*text == Ch('\0'))
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
text += 2; // Skip '?>'
|
||||
@@ -1942,15 +1956,17 @@ namespace rapidxml
|
||||
if (!(Flags & parse_trim_whitespace))
|
||||
text = contents_start;
|
||||
|
||||
const bool preserve_space = internal::preserve_space(node);
|
||||
|
||||
// Skip until end of data
|
||||
Ch *value = text, *end;
|
||||
if (Flags & parse_normalize_whitespace)
|
||||
end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text);
|
||||
Ch *value_ = text, *end;
|
||||
if ((Flags & parse_normalize_whitespace) && !preserve_space)
|
||||
end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text, false);
|
||||
else
|
||||
end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text);
|
||||
end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text, preserve_space);
|
||||
|
||||
// Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
|
||||
if (Flags & parse_trim_whitespace)
|
||||
if ((Flags & parse_trim_whitespace) && !preserve_space)
|
||||
{
|
||||
if (Flags & parse_normalize_whitespace)
|
||||
{
|
||||
@@ -1971,14 +1987,14 @@ namespace rapidxml
|
||||
if (!(Flags & parse_no_data_nodes))
|
||||
{
|
||||
xml_node<Ch> *data = this->allocate_node(node_data);
|
||||
data->value(value, end - value);
|
||||
data->value(value_, static_cast<std::size_t>(end - value_));
|
||||
node->append_node(data);
|
||||
}
|
||||
|
||||
// Add data to parent node if no data exists yet
|
||||
if (!(Flags & parse_no_element_values))
|
||||
if (*node->value() == Ch('\0'))
|
||||
node->value(value, end - value);
|
||||
node->value(value_, static_cast<std::size_t>(end - value_));
|
||||
|
||||
// Place zero terminator after value
|
||||
if (!(Flags & parse_no_string_terminators))
|
||||
@@ -2003,7 +2019,7 @@ namespace rapidxml
|
||||
while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
|
||||
{
|
||||
if (!text[0])
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
text += 3; // Skip ]]>
|
||||
@@ -2011,17 +2027,17 @@ namespace rapidxml
|
||||
}
|
||||
|
||||
// Skip until end of cdata
|
||||
Ch *value = text;
|
||||
Ch *value_ = text;
|
||||
while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
|
||||
{
|
||||
if (!text[0])
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
|
||||
// Create new cdata node
|
||||
xml_node<Ch> *cdata = this->allocate_node(node_cdata);
|
||||
cdata->value(value, text - value);
|
||||
cdata->value(value_, static_cast<std::size_t>(text - value_));
|
||||
|
||||
// Place zero terminator after value
|
||||
if (!(Flags & parse_no_string_terminators))
|
||||
@@ -2039,11 +2055,11 @@ namespace rapidxml
|
||||
xml_node<Ch> *element = this->allocate_node(node_element);
|
||||
|
||||
// Extract element name
|
||||
Ch *name = text;
|
||||
Ch *name_ = text;
|
||||
skip<node_name_pred, Flags>(text);
|
||||
if (text == name)
|
||||
RAPIDXML_PARSE_ERROR("expected element name", text);
|
||||
element->name(name, text - name);
|
||||
if (text == name_)
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected element name", text);
|
||||
element->name(name_, static_cast<std::size_t>(text - name_));
|
||||
|
||||
// Skip whitespace between element name and attributes or >
|
||||
skip<whitespace_pred, Flags>(text);
|
||||
@@ -2061,11 +2077,11 @@ namespace rapidxml
|
||||
{
|
||||
++text;
|
||||
if (*text != Ch('>'))
|
||||
RAPIDXML_PARSE_ERROR("expected >", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected >", text);
|
||||
++text;
|
||||
}
|
||||
else
|
||||
RAPIDXML_PARSE_ERROR("expected >", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected >", text);
|
||||
|
||||
// Place zero terminator after name
|
||||
if (!(Flags & parse_no_string_terminators))
|
||||
@@ -2152,7 +2168,7 @@ namespace rapidxml
|
||||
while (*text != Ch('>'))
|
||||
{
|
||||
if (*text == 0)
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
++text;
|
||||
}
|
||||
++text; // Skip '>'
|
||||
@@ -2187,6 +2203,12 @@ namespace rapidxml
|
||||
case Ch('<'):
|
||||
if (text[1] == Ch('/'))
|
||||
{
|
||||
Ch *contents_end = 0;
|
||||
if (internal::preserve_space(node))
|
||||
{
|
||||
contents_end = text;
|
||||
}
|
||||
|
||||
// Node closing
|
||||
text += 2; // Skip '</'
|
||||
if (Flags & parse_validate_closing_tags)
|
||||
@@ -2194,8 +2216,8 @@ namespace rapidxml
|
||||
// Skip and validate closing tag name
|
||||
Ch *closing_name = text;
|
||||
skip<node_name_pred, Flags>(text);
|
||||
if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true))
|
||||
RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
|
||||
if (!internal::compare(node->name(), node->name_size(), closing_name, static_cast<std::size_t>(text - closing_name), true))
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2205,8 +2227,14 @@ namespace rapidxml
|
||||
// Skip remaining whitespace after node name
|
||||
skip<whitespace_pred, Flags>(text);
|
||||
if (*text != Ch('>'))
|
||||
RAPIDXML_PARSE_ERROR("expected >", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected >", text);
|
||||
++text; // Skip '>'
|
||||
|
||||
if (contents_end && contents_end != contents_start)
|
||||
{
|
||||
node->value(contents_start, static_cast<std::size_t>(contents_end - contents_start));
|
||||
node->value()[node->value_size()] = Ch('\0');
|
||||
}
|
||||
return; // Node closed, finished parsing contents
|
||||
}
|
||||
else
|
||||
@@ -2220,7 +2248,7 @@ namespace rapidxml
|
||||
|
||||
// End of data - error
|
||||
case Ch('\0'):
|
||||
RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
|
||||
|
||||
// Data node
|
||||
default:
|
||||
@@ -2239,15 +2267,15 @@ namespace rapidxml
|
||||
while (attribute_name_pred::test(*text))
|
||||
{
|
||||
// Extract attribute name
|
||||
Ch *name = text;
|
||||
Ch *name_ = text;
|
||||
++text; // Skip first character of attribute name
|
||||
skip<attribute_name_pred, Flags>(text);
|
||||
if (text == name)
|
||||
RAPIDXML_PARSE_ERROR("expected attribute name", name);
|
||||
if (text == name_)
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected attribute name", name_);
|
||||
|
||||
// Create new attribute
|
||||
xml_attribute<Ch> *attribute = this->allocate_attribute();
|
||||
attribute->name(name, text - name);
|
||||
attribute->name(name_, static_cast<std::size_t>(text - name_));
|
||||
node->append_attribute(attribute);
|
||||
|
||||
// Skip whitespace after attribute name
|
||||
@@ -2255,7 +2283,7 @@ namespace rapidxml
|
||||
|
||||
// Skip =
|
||||
if (*text != Ch('='))
|
||||
RAPIDXML_PARSE_ERROR("expected =", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected =", text);
|
||||
++text;
|
||||
|
||||
// Add terminating zero after name
|
||||
@@ -2268,23 +2296,23 @@ namespace rapidxml
|
||||
// Skip quote and remember if it was ' or "
|
||||
Ch quote = *text;
|
||||
if (quote != Ch('\'') && quote != Ch('"'))
|
||||
RAPIDXML_PARSE_ERROR("expected ' or \"", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
|
||||
++text;
|
||||
|
||||
// Extract attribute value and expand char refs in it
|
||||
Ch *value = text, *end;
|
||||
Ch *value_ = text, *end;
|
||||
const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes
|
||||
if (quote == Ch('\''))
|
||||
end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text);
|
||||
end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text, false);
|
||||
else
|
||||
end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text);
|
||||
end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text, false);
|
||||
|
||||
// Set attribute value
|
||||
attribute->value(value, end - value);
|
||||
attribute->value(value_, static_cast<std::size_t>(end - value_));
|
||||
|
||||
// Make sure that end quote is present
|
||||
if (*text != quote)
|
||||
RAPIDXML_PARSE_ERROR("expected ' or \"", text);
|
||||
CEREAL_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
|
||||
++text; // Skip quote
|
||||
|
||||
// Add terminating zero after value
|
||||
@@ -2583,9 +2611,10 @@ namespace rapidxml
|
||||
//! \endcond
|
||||
|
||||
}
|
||||
} // end namespace cereal
|
||||
|
||||
// Undefine internal macros
|
||||
#undef RAPIDXML_PARSE_ERROR
|
||||
#undef CEREAL_RAPIDXML_PARSE_ERROR
|
||||
|
||||
// On MSVC, restore warnings state
|
||||
#ifdef _MSC_VER
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#ifndef CEREAL_RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define CEREAL_RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
namespace cereal {
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
@@ -169,5 +170,6 @@ namespace rapidxml
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif
|
||||
|
||||
+9
-5
@@ -1,5 +1,5 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#ifndef CEREAL_RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define CEREAL_RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
@@ -8,11 +8,12 @@
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#ifndef CEREAL_RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace cereal {
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
@@ -116,7 +117,7 @@ namespace rapidxml
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int /*flags*/)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
@@ -362,10 +363,12 @@ namespace rapidxml
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
#ifndef __GNUC__
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
@@ -393,7 +396,7 @@ namespace rapidxml
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#ifndef CEREAL_RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
@@ -420,5 +423,6 @@ namespace rapidxml
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#ifndef CEREAL_RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define CEREAL_RAPIDXML_UTILS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace cereal {
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
@@ -117,5 +118,6 @@ namespace rapidxml
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*! \file macros.hpp
|
||||
\brief Preprocessor macros that can customise the cereal library
|
||||
|
||||
By default, cereal looks for serialization functions with very
|
||||
specific names, that is: serialize, load, save, load_minimal,
|
||||
or save_minimal.
|
||||
|
||||
This file allows an advanced user to change these names to conform
|
||||
to some other style or preference. This is implemented using
|
||||
preprocessor macros.
|
||||
|
||||
As a result of this, in internal cereal code you will see macros
|
||||
used for these function names. In user code, you should name
|
||||
the functions like you normally would and not use the macros
|
||||
to improve readability.
|
||||
\ingroup utility */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_MACROS_HPP_
|
||||
#define CEREAL_MACROS_HPP_
|
||||
|
||||
#ifndef CEREAL_THREAD_SAFE
|
||||
//! Whether cereal should be compiled for a threaded environment
|
||||
/*! This macro causes cereal to use mutexes to control access to
|
||||
global internal state in a thread safe manner.
|
||||
|
||||
Note that even with this enabled you must still ensure that
|
||||
archives are accessed by only one thread at a time; it is safe
|
||||
to use multiple archives in paralel, but not to access one archive
|
||||
from many places simultaneously. */
|
||||
#define CEREAL_THREAD_SAFE 0
|
||||
#endif // CEREAL_THREAD_SAFE
|
||||
|
||||
#ifndef CEREAL_SIZE_TYPE
|
||||
//! Determines the data type used for size_type
|
||||
/*! cereal uses size_type to ensure that the serialized size of
|
||||
dynamic containers is compatible across different architectures
|
||||
(e.g. 32 vs 64 bit), which may use different underlying types for
|
||||
std::size_t.
|
||||
|
||||
More information can be found in cereal/details/helpers.hpp.
|
||||
|
||||
If you choose to modify this type, ensure that you use a fixed
|
||||
size type (e.g. uint32_t). */
|
||||
#define CEREAL_SIZE_TYPE uint64_t
|
||||
#endif // CEREAL_SIZE_TYPE
|
||||
|
||||
// ######################################################################
|
||||
#ifndef CEREAL_SERIALIZE_FUNCTION_NAME
|
||||
//! The serialization/deserialization function name to search for.
|
||||
/*! You can define @c CEREAL_SERIALIZE_FUNCTION_NAME to be different assuming
|
||||
you do so before this file is included. */
|
||||
#define CEREAL_SERIALIZE_FUNCTION_NAME serialize
|
||||
#endif // CEREAL_SERIALIZE_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_LOAD_FUNCTION_NAME
|
||||
//! The deserialization (load) function name to search for.
|
||||
/*! You can define @c CEREAL_LOAD_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_LOAD_FUNCTION_NAME load
|
||||
#endif // CEREAL_LOAD_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_SAVE_FUNCTION_NAME
|
||||
//! The serialization (save) function name to search for.
|
||||
/*! You can define @c CEREAL_SAVE_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_SAVE_FUNCTION_NAME save
|
||||
#endif // CEREAL_SAVE_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_LOAD_MINIMAL_FUNCTION_NAME
|
||||
//! The deserialization (load_minimal) function name to search for.
|
||||
/*! You can define @c CEREAL_LOAD_MINIMAL_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_LOAD_MINIMAL_FUNCTION_NAME load_minimal
|
||||
#endif // CEREAL_LOAD_MINIMAL_FUNCTION_NAME
|
||||
|
||||
#ifndef CEREAL_SAVE_MINIMAL_FUNCTION_NAME
|
||||
//! The serialization (save_minimal) function name to search for.
|
||||
/*! You can define @c CEREAL_SAVE_MINIMAL_FUNCTION_NAME to be different assuming you do so
|
||||
before this file is included. */
|
||||
#define CEREAL_SAVE_MINIMAL_FUNCTION_NAME save_minimal
|
||||
#endif // CEREAL_SAVE_MINIMAL_FUNCTION_NAME
|
||||
|
||||
// ######################################################################
|
||||
//! Defines the CEREAL_NOEXCEPT macro to use instead of noexcept
|
||||
/*! If a compiler we support does not support noexcept, this macro
|
||||
will detect this and define CEREAL_NOEXCEPT as a no-op
|
||||
@internal */
|
||||
#if !defined(CEREAL_HAS_NOEXCEPT)
|
||||
#if defined(__clang__)
|
||||
#if __has_feature(cxx_noexcept)
|
||||
#define CEREAL_HAS_NOEXCEPT
|
||||
#endif
|
||||
#else // NOT clang
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
|
||||
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#define CEREAL_HAS_NOEXCEPT
|
||||
#endif // end GCC/MSVC check
|
||||
#endif // end NOT clang block
|
||||
|
||||
#ifndef CEREAL_NOEXCEPT
|
||||
#ifdef CEREAL_HAS_NOEXCEPT
|
||||
#define CEREAL_NOEXCEPT noexcept
|
||||
#else
|
||||
#define CEREAL_NOEXCEPT
|
||||
#endif // end CEREAL_HAS_NOEXCEPT
|
||||
#endif // end !defined(CEREAL_HAS_NOEXCEPT)
|
||||
#endif // ifndef CEREAL_NOEXCEPT
|
||||
|
||||
// ######################################################################
|
||||
//! Checks if C++17 is available
|
||||
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
#define CEREAL_HAS_CPP17
|
||||
#endif
|
||||
|
||||
//! Checks if C++14 is available
|
||||
#if __cplusplus >= 201402L
|
||||
#define CEREAL_HAS_CPP14
|
||||
#endif
|
||||
|
||||
// ######################################################################
|
||||
//! Defines the CEREAL_ALIGNOF macro to use instead of alignof
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define CEREAL_ALIGNOF __alignof
|
||||
#else // not MSVC 2013 or older
|
||||
#define CEREAL_ALIGNOF alignof
|
||||
#endif // end MSVC check
|
||||
|
||||
#endif // CEREAL_MACROS_HPP_
|
||||
@@ -0,0 +1,139 @@
|
||||
/*! \file specialize.hpp
|
||||
\brief Serialization disambiguation */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_SPECIALIZE_HPP_
|
||||
#define CEREAL_SPECIALIZE_HPP_
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// Forward declaration of access class that users can become friends with
|
||||
class access;
|
||||
|
||||
// ######################################################################
|
||||
//! A specifier used in conjunction with cereal::specialize to disambiguate
|
||||
//! serialization in special cases
|
||||
/*! @relates specialize
|
||||
@ingroup Access */
|
||||
enum class specialization
|
||||
{
|
||||
member_serialize, //!< Force the use of a member serialize function
|
||||
member_load_save, //!< Force the use of a member load/save pair
|
||||
member_load_save_minimal, //!< Force the use of a member minimal load/save pair
|
||||
non_member_serialize, //!< Force the use of a non-member serialize function
|
||||
non_member_load_save, //!< Force the use of a non-member load/save pair
|
||||
non_member_load_save_minimal //!< Force the use of a non-member minimal load/save pair
|
||||
};
|
||||
|
||||
//! A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class
|
||||
/*! cereal attempts to figure out which method of serialization (member vs. non-member serialize
|
||||
or load/save pair) at compile time. If for some reason cereal cannot find a non-ambiguous way
|
||||
of serializing a type, it will produce a static assertion complaining about this.
|
||||
|
||||
This can happen because you have both a serialize and load/save pair, or even because a base
|
||||
class has a serialize (public or private with friend access) and a derived class does not
|
||||
overwrite this due to choosing some other serialization type.
|
||||
|
||||
Specializing this class will tell cereal to explicitly use the serialization type you specify
|
||||
and it will not complain about ambiguity in its compile time selection. However, if cereal detects
|
||||
an ambiguity in specializations, it will continue to issue a static assertion.
|
||||
|
||||
@code{.cpp}
|
||||
class MyParent
|
||||
{
|
||||
friend class cereal::access;
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar ) {}
|
||||
};
|
||||
|
||||
// Although serialize is private in MyParent, to cereal::access it will look public,
|
||||
// even through MyDerived
|
||||
class MyDerived : public MyParent
|
||||
{
|
||||
public:
|
||||
template <class Archive>
|
||||
void load( Archive & ar ) {}
|
||||
|
||||
template <class Archive>
|
||||
void save( Archive & ar ) {}
|
||||
};
|
||||
|
||||
// The load/save pair in MyDerived is ambiguous because serialize in MyParent can
|
||||
// be accessed from cereal::access. This looks the same as making serialize public
|
||||
// in MyParent, making it seem as though MyDerived has both a serialize and a load/save pair.
|
||||
// cereal will complain about this at compile time unless we disambiguate:
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// This struct specialization will tell cereal which is the right way to serialize the ambiguity
|
||||
template <class Archive> struct specialize<Archive, MyDerived, cereal::specialization::member_load_save> {};
|
||||
|
||||
// If we only had a disambiguation for a specific archive type, it would look something like this
|
||||
template <> struct specialize<cereal::BinaryOutputArchive, MyDerived, cereal::specialization::member_load_save> {};
|
||||
}
|
||||
@endcode
|
||||
|
||||
You can also choose to use the macros CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES or
|
||||
CEREAL_SPECIALIZE_FOR_ARCHIVE if you want to type a little bit less.
|
||||
|
||||
@tparam T The type to specialize the serialization for
|
||||
@tparam S The specialization type to use for T
|
||||
@ingroup Access */
|
||||
template <class Archive, class T, specialization S>
|
||||
struct specialize : public std::false_type {};
|
||||
|
||||
//! Convenient macro for performing specialization for all archive types
|
||||
/*! This performs specialization for the specific type for all types of archives.
|
||||
This macro should be placed at the global namespace.
|
||||
|
||||
@code{cpp}
|
||||
struct MyType {};
|
||||
CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( MyType, cereal::specialization::member_load_save );
|
||||
@endcode
|
||||
|
||||
@relates specialize
|
||||
@ingroup Access */
|
||||
#define CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Type, Specialization ) \
|
||||
namespace cereal { template <class Archive> struct specialize<Archive, Type, Specialization> {}; }
|
||||
|
||||
//! Convenient macro for performing specialization for a single archive type
|
||||
/*! This performs specialization for the specific type for a single type of archive.
|
||||
This macro should be placed at the global namespace.
|
||||
|
||||
@code{cpp}
|
||||
struct MyType {};
|
||||
CEREAL_SPECIALIZE_FOR_ARCHIVE( cereal::XMLInputArchive, MyType, cereal::specialization::member_load_save );
|
||||
@endcode
|
||||
|
||||
@relates specialize
|
||||
@ingroup Access */
|
||||
#define CEREAL_SPECIALIZE_FOR_ARCHIVE( Archive, Type, Specialization ) \
|
||||
namespace cereal { template <> struct specialize<Archive, Type, Specialization> {}; }
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<array\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,7 +30,7 @@
|
||||
#ifndef CEREAL_TYPES_ARRAY_HPP_
|
||||
#define CEREAL_TYPES_ARRAY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace cereal
|
||||
@@ -38,28 +38,28 @@ namespace cereal
|
||||
//! Saving for std::array primitive types
|
||||
//! using binary serialization, if supported
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>()
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
save( Archive & ar, std::array<T, N> const & array )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
|
||||
{
|
||||
ar( binary_data( array.data(), N * sizeof(T) ) );
|
||||
ar( binary_data( array.data(), sizeof(array) ) );
|
||||
}
|
||||
|
||||
//! Loading for std::array primitive types
|
||||
//! using binary serialization, if supported
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>()
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
load( Archive & ar, std::array<T, N> & array )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
|
||||
{
|
||||
ar( binary_data( array.data(), N * sizeof(T) ) );
|
||||
ar( binary_data( array.data(), sizeof(array) ) );
|
||||
}
|
||||
|
||||
//! Saving for std::array all other types
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>()
|
||||
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
save( Archive & ar, std::array<T, N> const & array )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
|
||||
{
|
||||
for( auto const & i : array )
|
||||
ar( i );
|
||||
@@ -67,9 +67,9 @@ namespace cereal
|
||||
|
||||
//! Loading for std::array all other types
|
||||
template <class Archive, class T, size_t N> inline
|
||||
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>()
|
||||
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
load( Archive & ar, std::array<T, N> & array )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
|
||||
{
|
||||
for( auto & i : array )
|
||||
ar( i );
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*! \file atomic.hpp
|
||||
\brief Support for types found in \<atomic\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_ATOMIC_HPP_
|
||||
#define CEREAL_TYPES_ATOMIC_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <atomic>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serializing (save) for std::atomic
|
||||
template <class Archive, class T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::atomic<T> const & a )
|
||||
{
|
||||
ar( CEREAL_NVP_("atomic_data", a.load()) );
|
||||
}
|
||||
|
||||
//! Serializing (load) for std::atomic
|
||||
template <class Archive, class T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::atomic<T> & a )
|
||||
{
|
||||
T tmp;
|
||||
ar( CEREAL_NVP_("atomic_data", tmp) );
|
||||
a.store( tmp );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_ATOMIC_HPP_
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for base classes (virtual and non-virtual)
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,14 +30,44 @@
|
||||
#ifndef CEREAL_TYPES_BASE_CLASS_HPP_
|
||||
#define CEREAL_TYPES_BASE_CLASS_HPP_
|
||||
|
||||
#include "cereal/details/traits.hpp"
|
||||
#include "cereal/details/polymorphic_impl_fwd.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace base_class_detail
|
||||
{
|
||||
//! Used to register polymorphic relations and avoid the need to include
|
||||
//! polymorphic.hpp when no polymorphism is used
|
||||
/*! @internal */
|
||||
template <class Base, class Derived, bool IsPolymorphic = std::is_polymorphic<Base>::value>
|
||||
struct RegisterPolymorphicBaseClass
|
||||
{
|
||||
static void bind()
|
||||
{ }
|
||||
};
|
||||
|
||||
//! Polymorphic version
|
||||
/*! @internal */
|
||||
template <class Base, class Derived>
|
||||
struct RegisterPolymorphicBaseClass<Base, Derived, true>
|
||||
{
|
||||
static void bind()
|
||||
{ detail::RegisterPolymorphicCaster<Base, Derived>::bind(); }
|
||||
};
|
||||
}
|
||||
|
||||
//! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
|
||||
/*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
|
||||
using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
|
||||
using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
|
||||
|
||||
This also automatically registers polymorphic relation between the base and derived class, assuming they
|
||||
are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
|
||||
see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
|
||||
polymorphism (cereal/types/polymorphic.hpp).
|
||||
|
||||
\sa virtual_base_class
|
||||
|
||||
|
||||
@code{.cpp}
|
||||
struct MyBase
|
||||
{
|
||||
@@ -67,12 +97,15 @@ namespace cereal
|
||||
};
|
||||
@endcode */
|
||||
template<class Base>
|
||||
struct base_class
|
||||
struct base_class : private traits::detail::BaseCastBase
|
||||
{
|
||||
template<class Derived>
|
||||
base_class(Derived const * derived) :
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{ }
|
||||
{
|
||||
static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" );
|
||||
base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
|
||||
}
|
||||
|
||||
Base * base_ptr;
|
||||
};
|
||||
@@ -86,11 +119,16 @@ namespace cereal
|
||||
where virtual inheritance does not take place, though it may be slightly faster to utilize
|
||||
cereal::base_class<> if you do not need to worry about virtual inheritance.
|
||||
|
||||
This also automatically registers polymorphic relation between the base and derived class, assuming they
|
||||
are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
|
||||
see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
|
||||
polymorphism (cereal/types/polymorphic.hpp).
|
||||
|
||||
\sa base_class
|
||||
|
||||
@code{.cpp}
|
||||
struct MyBase
|
||||
{
|
||||
{
|
||||
int x;
|
||||
|
||||
template <class Archive>
|
||||
@@ -137,25 +175,29 @@ namespace cereal
|
||||
ar( a );
|
||||
|
||||
// Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is
|
||||
// serialized as we traverse the inheritance heirarchy. This means that there will be one copy
|
||||
// serialized as we traverse the inheritance heirarchy. This means that there will be one copy
|
||||
// each of the variables x, y, z, and a
|
||||
|
||||
// If we had chosen to use static_cast<> instead, cereal would perform no tracking and
|
||||
// assume that every base class should be serialized (in this case leading to a duplicate
|
||||
// serialization of MyBase due to diamond inheritance
|
||||
};
|
||||
};
|
||||
}
|
||||
@endcode */
|
||||
template<class Base>
|
||||
struct virtual_base_class
|
||||
struct virtual_base_class : private traits::detail::BaseCastBase
|
||||
{
|
||||
template<class Derived>
|
||||
virtual_base_class(Derived const * derived) :
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{ }
|
||||
{
|
||||
static_assert( std::is_base_of<Base, Derived>::value, "Can only use virtual_base_class on a valid base class" );
|
||||
base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
|
||||
}
|
||||
|
||||
Base * base_ptr;
|
||||
};
|
||||
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_BASE_CLASS_HPP_
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<bitset\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,7 +30,8 @@
|
||||
#ifndef CEREAL_TYPES_BITSET_HPP_
|
||||
#define CEREAL_TYPES_BITSET_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/types/string.hpp"
|
||||
#include <bitset>
|
||||
|
||||
namespace cereal
|
||||
@@ -43,66 +44,129 @@ namespace cereal
|
||||
{
|
||||
ulong,
|
||||
ullong,
|
||||
string
|
||||
string,
|
||||
bits
|
||||
};
|
||||
}
|
||||
|
||||
//! Serializing (save) for std::bitset
|
||||
template <class Archive, size_t N> inline
|
||||
void save( Archive & ar, std::bitset<N> const & bits )
|
||||
//! Serializing (save) for std::bitset when BinaryData optimization supported
|
||||
template <class Archive, size_t N,
|
||||
traits::EnableIf<traits::is_output_serializable<BinaryData<std::uint32_t>, Archive>::value>
|
||||
= traits::sfinae> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
|
||||
{
|
||||
ar( CEREAL_NVP_("type", bitset_detail::type::bits) );
|
||||
|
||||
// Serialize 8 bit chunks
|
||||
std::uint8_t chunk = 0;
|
||||
std::uint8_t mask = 0x80;
|
||||
|
||||
// Set each chunk using a rotating mask for the current bit
|
||||
for( std::size_t i = 0; i < N; ++i )
|
||||
{
|
||||
if( bits[i] )
|
||||
chunk |= mask;
|
||||
|
||||
mask = static_cast<std::uint8_t>(mask >> 1);
|
||||
|
||||
// output current chunk when mask is empty (8 bits)
|
||||
if( mask == 0 )
|
||||
{
|
||||
ar( chunk );
|
||||
chunk = 0;
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
// serialize remainder, if it exists
|
||||
if( mask != 0x80 )
|
||||
ar( chunk );
|
||||
}
|
||||
|
||||
//! Serializing (save) for std::bitset when BinaryData is not supported
|
||||
template <class Archive, size_t N,
|
||||
traits::DisableIf<traits::is_output_serializable<BinaryData<std::uint32_t>, Archive>::value>
|
||||
= traits::sfinae> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const b = bits.to_ulong();
|
||||
ar( _CEREAL_NVP("type", bitset_detail::type::ulong) );
|
||||
ar( _CEREAL_NVP("data", b) );
|
||||
ar( CEREAL_NVP_("type", bitset_detail::type::ulong) );
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
}
|
||||
catch( std::overflow_error const & e )
|
||||
catch( std::overflow_error const & )
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const b = bits.to_ullong();
|
||||
ar( _CEREAL_NVP("type", bitset_detail::type::ullong) );
|
||||
ar( _CEREAL_NVP("data", b) );
|
||||
ar( CEREAL_NVP_("type", bitset_detail::type::ullong) );
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
}
|
||||
catch( std::overflow_error const & e )
|
||||
catch( std::overflow_error const & )
|
||||
{
|
||||
ar( _CEREAL_NVP("type", bitset_detail::type::string) );
|
||||
ar( _CEREAL_NVP("data", bits.to_string()) );
|
||||
ar( CEREAL_NVP_("type", bitset_detail::type::string) );
|
||||
ar( CEREAL_NVP_("data", bits.to_string()) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Serializing (load) for std::bitset
|
||||
template <class Archive, size_t N> inline
|
||||
void load( Archive & ar, std::bitset<N> & bits )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::bitset<N> & bits )
|
||||
{
|
||||
bitset_detail::type t;
|
||||
ar( t );
|
||||
ar( CEREAL_NVP_("type", t) );
|
||||
|
||||
switch( t )
|
||||
{
|
||||
case bitset_detail::type::ulong:
|
||||
{
|
||||
unsigned long b;
|
||||
ar( b );
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
bits = std::bitset<N>( b );
|
||||
break;
|
||||
}
|
||||
case bitset_detail::type::ullong:
|
||||
{
|
||||
unsigned long long b;
|
||||
ar( b );
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
bits = std::bitset<N>( b );
|
||||
break;
|
||||
}
|
||||
case bitset_detail::type::string:
|
||||
{
|
||||
std::string b;
|
||||
ar( b );
|
||||
ar( CEREAL_NVP_("data", b) );
|
||||
bits = std::bitset<N>( b );
|
||||
break;
|
||||
}
|
||||
case bitset_detail::type::bits:
|
||||
{
|
||||
// Normally we would use BinaryData to route this at compile time,
|
||||
// but doing this at runtime doesn't break any old serialization
|
||||
std::uint8_t chunk = 0;
|
||||
std::uint8_t mask = 0;
|
||||
|
||||
bits.reset();
|
||||
|
||||
// Load one chunk at a time, rotating through the chunk
|
||||
// to set bits in the bitset
|
||||
for( std::size_t i = 0; i < N; ++i )
|
||||
{
|
||||
if( mask == 0 )
|
||||
{
|
||||
ar( chunk );
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
if( chunk & mask )
|
||||
bits[i] = 1;
|
||||
|
||||
mask = static_cast<std::uint8_t>(mask >> 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Exception("Invalid bitset data representation");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for boost::variant
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,77 +30,135 @@
|
||||
#ifndef CEREAL_TYPES_BOOST_VARIANT_HPP_
|
||||
#define CEREAL_TYPES_BOOST_VARIANT_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/mpl/size.hpp>
|
||||
//! @internal
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1911
|
||||
#define CEREAL_CONSTEXPR_LAMBDA
|
||||
#else // MSVC 2017 or newer, all other compilers
|
||||
#define CEREAL_CONSTEXPR_LAMBDA constexpr
|
||||
#endif
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <boost/variant/variant_fwd.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace variant_detail
|
||||
namespace boost_variant_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive>
|
||||
struct variant_save_visitor : boost::static_visitor<>
|
||||
{
|
||||
variant_save_visitor(Archive & ar) : ar(ar) {}
|
||||
variant_save_visitor(Archive & ar_) : ar(ar_) {}
|
||||
|
||||
template<class T>
|
||||
void operator()(T const & value) const
|
||||
{
|
||||
ar( _CEREAL_NVP("data", value) );
|
||||
}
|
||||
void operator()(T const & value) const
|
||||
{
|
||||
ar( CEREAL_NVP_("data", value) );
|
||||
}
|
||||
|
||||
Archive & ar;
|
||||
};
|
||||
|
||||
//! @internal
|
||||
template<int N, class Variant, class ... Args, class Archive>
|
||||
typename std::enable_if<N == boost::mpl::size<typename Variant::types>::value, void>::type
|
||||
load_variant(Archive & ar, int target, Variant & variant)
|
||||
template <class Archive, class T>
|
||||
struct LoadAndConstructLoadWrapper
|
||||
{
|
||||
throw ::cereal::Exception("Error traversing variant during load");
|
||||
}
|
||||
using ST = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
|
||||
|
||||
LoadAndConstructLoadWrapper() :
|
||||
construct( reinterpret_cast<T *>( &st ) )
|
||||
{ }
|
||||
|
||||
~LoadAndConstructLoadWrapper()
|
||||
{
|
||||
if (construct.itsValid)
|
||||
{
|
||||
construct->~T();
|
||||
}
|
||||
}
|
||||
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
|
||||
{
|
||||
::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
|
||||
}
|
||||
|
||||
ST st;
|
||||
::cereal::construct<T> construct;
|
||||
};
|
||||
|
||||
//! @internal
|
||||
template<int N, class Variant, class H, class ... T, class Archive>
|
||||
typename std::enable_if<N < boost::mpl::size<typename Variant::types>::value, void>::type
|
||||
load_variant(Archive & ar, int target, Variant & variant)
|
||||
{
|
||||
if(N == target)
|
||||
{
|
||||
H value;
|
||||
ar( value );
|
||||
variant = value;
|
||||
}
|
||||
else
|
||||
load_variant<N+1, Variant, T...>(ar, target, variant);
|
||||
}
|
||||
template <class T> struct load_variant_wrapper;
|
||||
|
||||
} // namespace variant_detail
|
||||
//! Avoid serializing variant void_ type
|
||||
/*! @internal */
|
||||
template <>
|
||||
struct load_variant_wrapper<boost::detail::variant::void_>
|
||||
{
|
||||
template <class Variant, class Archive>
|
||||
static void load_variant( Archive &, Variant & )
|
||||
{ }
|
||||
};
|
||||
|
||||
//! @internal
|
||||
template <class T>
|
||||
struct load_variant_wrapper
|
||||
{
|
||||
// default constructible
|
||||
template <class Archive, class Variant>
|
||||
static void load_variant_impl( Archive & ar, Variant & variant, std::true_type )
|
||||
{
|
||||
T value;
|
||||
ar( CEREAL_NVP_("data", value) );
|
||||
variant = std::move(value);
|
||||
}
|
||||
|
||||
// not default constructible
|
||||
template<class Variant, class Archive>
|
||||
static void load_variant_impl(Archive & ar, Variant & variant, std::false_type )
|
||||
{
|
||||
LoadAndConstructLoadWrapper<Archive, T> loadWrapper;
|
||||
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
variant = std::move(*loadWrapper.construct.ptr());
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template<class Variant, class Archive>
|
||||
static void load_variant(Archive & ar, Variant & variant)
|
||||
{
|
||||
load_variant_impl( ar, variant, typename std::is_default_constructible<T>::type() );
|
||||
}
|
||||
};
|
||||
} // namespace boost_variant_detail
|
||||
|
||||
//! Saving for boost::variant
|
||||
template <class Archive, typename... VariantTypes> inline
|
||||
void save( Archive & ar, boost::variant<VariantTypes...> const & variant )
|
||||
template <class Archive, typename ... VariantTypes> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
|
||||
{
|
||||
int32_t which = variant.which();
|
||||
ar( _CEREAL_NVP("which", which) );
|
||||
variant_detail::variant_save_visitor<Archive> visitor(ar);
|
||||
ar( CEREAL_NVP_("which", which) );
|
||||
boost_variant_detail::variant_save_visitor<Archive> visitor(ar);
|
||||
variant.apply_visitor(visitor);
|
||||
}
|
||||
|
||||
//! Loading for boost::variant
|
||||
template <class Archive, typename... VariantTypes> inline
|
||||
void load( Archive & ar, boost::variant<VariantTypes...> & variant )
|
||||
template <class Archive, typename ... VariantTypes> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
|
||||
{
|
||||
typedef typename boost::variant<VariantTypes...>::types types;
|
||||
|
||||
int32_t which;
|
||||
ar( which );
|
||||
if(which >= boost::mpl::size<types>::value)
|
||||
ar( CEREAL_NVP_("which", which) );
|
||||
|
||||
using LoadFuncType = void(*)(Archive &, boost::variant<VariantTypes...> &);
|
||||
CEREAL_CONSTEXPR_LAMBDA LoadFuncType loadFuncArray[] = {&boost_variant_detail::load_variant_wrapper<VariantTypes>::load_variant...};
|
||||
|
||||
if(which >= int32_t(sizeof(loadFuncArray)/sizeof(loadFuncArray[0])))
|
||||
throw Exception("Invalid 'which' selector when deserializing boost::variant");
|
||||
|
||||
variant_detail::load_variant<0, boost::variant<VariantTypes...>, VariantTypes...>(ar, which, variant);
|
||||
loadFuncArray[which](ar, variant);
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#undef CEREAL_CONSTEXPR_LAMBDA
|
||||
|
||||
#endif // CEREAL_TYPES_BOOST_VARIANT_HPP_
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<chrono\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -36,38 +36,37 @@ namespace cereal
|
||||
{
|
||||
//! Saving std::chrono::duration
|
||||
template <class Archive, class R, class P> inline
|
||||
void save( Archive & ar, std::chrono::duration<R, P> const & dur )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> const & dur )
|
||||
{
|
||||
ar( _CEREAL_NVP("count", dur.count()) );
|
||||
ar( CEREAL_NVP_("count", dur.count()) );
|
||||
}
|
||||
|
||||
//! Loading std::chrono::duration
|
||||
template <class Archive, class R, class P> inline
|
||||
void load( Archive & ar, std::chrono::duration<R, P> & dur )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> & dur )
|
||||
{
|
||||
R count;
|
||||
ar( count );
|
||||
ar( CEREAL_NVP_("count", count) );
|
||||
|
||||
dur = std::chrono::duration<R, P>{count};
|
||||
}
|
||||
|
||||
//! Saving std::chrono::time_point
|
||||
template <class Archive, class C, class D> inline
|
||||
void save( Archive & ar, std::chrono::time_point<C, D> const & dur )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> const & dur )
|
||||
{
|
||||
ar( _CEREAL_NVP("time_since_epoch", dur.time_since_epoch()) );
|
||||
ar( CEREAL_NVP_("time_since_epoch", dur.time_since_epoch()) );
|
||||
}
|
||||
|
||||
//! Loading std::chrono::time_point
|
||||
template <class Archive, class C, class D> inline
|
||||
void load( Archive & ar, std::chrono::time_point<C, D> & dur )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> & dur )
|
||||
{
|
||||
D elapsed;
|
||||
ar( elapsed );
|
||||
ar( CEREAL_NVP_("time_since_epoch", elapsed) );
|
||||
|
||||
dur = std::chrono::time_point<C, D>{elapsed};
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_CHRONO_HPP_
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support common types - always included automatically
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,37 +30,21 @@
|
||||
#ifndef CEREAL_TYPES_COMMON_HPP_
|
||||
#define CEREAL_TYPES_COMMON_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serialization for enum types
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<std::is_enum<T>::value, void>::type
|
||||
serialize(Archive & ar, T & t)
|
||||
{
|
||||
ar( reinterpret_cast<typename std::underlying_type<T>::type &>(t) );
|
||||
}
|
||||
|
||||
//! Serialization for raw pointers
|
||||
/*! This exists only to throw a static_assert to let users know we don't support raw pointers. */
|
||||
template <class Archive, class T> inline
|
||||
void serialize( Archive &, T * & )
|
||||
{
|
||||
static_assert(!sizeof(T), "Cereal does not support serializing raw pointers - please use a smart pointer");
|
||||
}
|
||||
|
||||
namespace common_detail
|
||||
{
|
||||
//! Serialization for arrays if BinaryData is supported
|
||||
//! Serialization for arrays if BinaryData is supported and we are arithmetic
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
void serializeArray( Archive & ar, T & array, std::true_type /* binary_supported */ )
|
||||
{
|
||||
ar( binary_data( array, traits::sizeof_array<T>() * sizeof(typename std::remove_all_extents<T>::type) ) );
|
||||
ar( binary_data( array, sizeof(array) ) );
|
||||
}
|
||||
|
||||
//! Serialization for arrays if BinaryData is not supported
|
||||
//! Serialization for arrays if BinaryData is not supported or we are not arithmetic
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
void serializeArray( Archive & ar, T & array, std::false_type /* binary_supported */ )
|
||||
@@ -68,15 +52,77 @@ namespace cereal
|
||||
for( auto & i : array )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
//! Gets the underlying type of an enum
|
||||
/*! @internal */
|
||||
template <class T, bool IsEnum>
|
||||
struct enum_underlying_type : std::false_type {};
|
||||
|
||||
//! Gets the underlying type of an enum
|
||||
/*! Specialization for when we actually have an enum
|
||||
@internal */
|
||||
template <class T>
|
||||
struct enum_underlying_type<T, true> { using type = typename std::underlying_type<T>::type; };
|
||||
} // anon namespace
|
||||
|
||||
//! Checks if a type is an enum
|
||||
/*! This is needed over simply calling std::is_enum because the type
|
||||
traits checking at compile time will attempt to call something like
|
||||
load_minimal with a special NoConvertRef struct that wraps up the true type.
|
||||
|
||||
This will strip away any of that and also expose the true underlying type.
|
||||
@internal */
|
||||
template <class T>
|
||||
class is_enum
|
||||
{
|
||||
private:
|
||||
using DecayedT = typename std::decay<T>::type;
|
||||
using StrippedT = typename ::cereal::traits::strip_minimal<DecayedT>::type;
|
||||
|
||||
public:
|
||||
static const bool value = std::is_enum<StrippedT>::value;
|
||||
using type = StrippedT;
|
||||
using base_type = typename enum_underlying_type<StrippedT, value>::type;
|
||||
};
|
||||
}
|
||||
|
||||
//! Saving for enum types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<common_detail::is_enum<T>::value,
|
||||
typename common_detail::is_enum<T>::base_type>::type
|
||||
CEREAL_SAVE_MINIMAL_FUNCTION_NAME( Archive const &, T const & t )
|
||||
{
|
||||
return static_cast<typename common_detail::is_enum<T>::base_type>(t);
|
||||
}
|
||||
|
||||
//! Loading for enum types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<common_detail::is_enum<T>::value, void>::type
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME( Archive const &, T && t,
|
||||
typename common_detail::is_enum<T>::base_type const & value )
|
||||
{
|
||||
t = reinterpret_cast<typename common_detail::is_enum<T>::type const &>( value );
|
||||
}
|
||||
|
||||
//! Serialization for raw pointers
|
||||
/*! This exists only to throw a static_assert to let users know we don't support raw pointers. */
|
||||
template <class Archive, class T> inline
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive &, T * & )
|
||||
{
|
||||
static_assert(cereal::traits::detail::delay_static_assert<T>::value,
|
||||
"Cereal does not support serializing raw pointers - please use a smart pointer");
|
||||
}
|
||||
|
||||
//! Serialization for C style arrays
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_array<T>::value, void>::type
|
||||
serialize(Archive & ar, T & array)
|
||||
CEREAL_SERIALIZE_FUNCTION_NAME(Archive & ar, T & array)
|
||||
{
|
||||
common_detail::serializeArray( ar, array,
|
||||
std::integral_constant<bool, traits::is_output_serializable<BinaryData<T>, Archive>()>() );
|
||||
std::integral_constant<bool, traits::is_output_serializable<BinaryData<T>, Archive>::value &&
|
||||
std::is_arithmetic<typename std::remove_all_extents<T>::type>::value>() );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<complex\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -36,18 +36,19 @@ namespace cereal
|
||||
{
|
||||
//! Serializing (save) for std::complex
|
||||
template <class Archive, class T> inline
|
||||
void save( Archive & ar, std::complex<T> const & comp )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::complex<T> const & comp )
|
||||
{
|
||||
ar( _CEREAL_NVP("real", comp.real()),
|
||||
_CEREAL_NVP("imag", comp.imag()) );
|
||||
ar( CEREAL_NVP_("real", comp.real()),
|
||||
CEREAL_NVP_("imag", comp.imag()) );
|
||||
}
|
||||
|
||||
//! Serializing (load) for std::complex
|
||||
template <class Archive, class T> inline
|
||||
void load( Archive & ar, std::complex<T> & bits )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::complex<T> & bits )
|
||||
{
|
||||
T real, imag;
|
||||
ar( real, imag );
|
||||
ar( CEREAL_NVP_("real", real),
|
||||
CEREAL_NVP_("imag", imag) );
|
||||
bits = {real, imag};
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*! \file pair_associative_container.hpp
|
||||
\brief Support for the PairAssociativeContainer refinement of the
|
||||
AssociativeContainer concept.
|
||||
\ingroup TypeConcepts */
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_CONCEPTS_PAIR_ASSOCIATIVE_CONTAINER_HPP_
|
||||
#define CEREAL_CONCEPTS_PAIR_ASSOCIATIVE_CONTAINER_HPP_
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std-like pair associative containers
|
||||
template <class Archive, template <typename...> class Map, typename... Args, typename = typename Map<Args...>::mapped_type> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, Map<Args...> const & map )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(map.size()) ) );
|
||||
|
||||
for( const auto & i : map )
|
||||
ar( make_map_item(i.first, i.second) );
|
||||
}
|
||||
|
||||
//! Loading for std-like pair associative containers
|
||||
template <class Archive, template <typename...> class Map, typename... Args, typename = typename Map<Args...>::mapped_type> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, Map<Args...> & map )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
map.clear();
|
||||
|
||||
auto hint = map.begin();
|
||||
for( size_t i = 0; i < size; ++i )
|
||||
{
|
||||
typename Map<Args...>::key_type key;
|
||||
typename Map<Args...>::mapped_type value;
|
||||
|
||||
ar( make_map_item(key, value) );
|
||||
#ifdef CEREAL_OLDER_GCC
|
||||
hint = map.insert( hint, std::make_pair(std::move(key), std::move(value)) );
|
||||
#else // NOT CEREAL_OLDER_GCC
|
||||
hint = map.emplace_hint( hint, std::move( key ), std::move( value ) );
|
||||
#endif // NOT CEREAL_OLDER_GCC
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_CONCEPTS_PAIR_ASSOCIATIVE_CONTAINER_HPP_
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<deque\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,14 +30,14 @@
|
||||
#ifndef CEREAL_TYPES_DEQUE_HPP_
|
||||
#define CEREAL_TYPES_DEQUE_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <deque>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::deque
|
||||
template <class Archive, class T, class A> inline
|
||||
void save( Archive & ar, std::deque<T, A> const & deque )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::deque<T, A> const & deque )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(deque.size()) ) );
|
||||
|
||||
@@ -47,12 +47,12 @@ namespace cereal
|
||||
|
||||
//! Loading for std::deque
|
||||
template <class Archive, class T, class A> inline
|
||||
void load( Archive & ar, std::deque<T, A> & deque )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::deque<T, A> & deque )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
deque.resize( size );
|
||||
deque.resize( static_cast<size_t>( size ) );
|
||||
|
||||
for( auto & i : deque )
|
||||
ar( i );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<forward_list\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,14 +30,14 @@
|
||||
#ifndef CEREAL_TYPES_FORWARD_LIST_HPP_
|
||||
#define CEREAL_TYPES_FORWARD_LIST_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <forward_list>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::forward_list all other types
|
||||
template <class Archive, class T, class A> inline
|
||||
void save( Archive & ar, std::forward_list<T, A> const & forward_list )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> const & forward_list )
|
||||
{
|
||||
// write the size - note that this is slow because we need to traverse
|
||||
// the entire list. there are ways we could avoid this but this was chosen
|
||||
@@ -53,12 +53,12 @@ namespace cereal
|
||||
|
||||
//! Loading for std::forward_list all other types from
|
||||
template <class Archive, class T, class A>
|
||||
void load( Archive & ar, std::forward_list<T, A> & forward_list )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> & forward_list )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
forward_list.resize( size );
|
||||
forward_list.resize( static_cast<size_t>( size ) );
|
||||
|
||||
for( auto & i : forward_list )
|
||||
ar( i );
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*! \file functional.hpp
|
||||
\brief Support for types found in \<functional\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2016, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_FUNCTIONAL_HPP_
|
||||
#define CEREAL_TYPES_FUNCTIONAL_HPP_
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::less
|
||||
template <class Archive, class T> inline
|
||||
void serialize( Archive &, std::less<T> & )
|
||||
{ }
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_FUNCTIONAL_HPP_
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<list\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,14 +30,14 @@
|
||||
#ifndef CEREAL_TYPES_LIST_HPP_
|
||||
#define CEREAL_TYPES_LIST_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <list>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::list
|
||||
template <class Archive, class T, class A> inline
|
||||
void save( Archive & ar, std::list<T, A> const & list )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::list<T, A> const & list )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(list.size()) ) );
|
||||
|
||||
@@ -47,12 +47,12 @@ namespace cereal
|
||||
|
||||
//! Loading for std::list
|
||||
template <class Archive, class T, class A> inline
|
||||
void load( Archive & ar, std::list<T, A> & list )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::list<T, A> & list )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
list.resize( size );
|
||||
list.resize( static_cast<size_t>( size ) );
|
||||
|
||||
for( auto & i : list )
|
||||
ar( i );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<map\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,75 +30,7 @@
|
||||
#ifndef CEREAL_TYPES_MAP_HPP_
|
||||
#define CEREAL_TYPES_MAP_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/types/concepts/pair_associative_container.hpp"
|
||||
#include <map>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace map_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void save( Archive & ar, MapT const & map )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(map.size()) ) );
|
||||
|
||||
for( const auto & i : map )
|
||||
{
|
||||
ar( make_map_item(i.first, i.second) );
|
||||
}
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void load( Archive & ar, MapT & map )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
map.clear();
|
||||
|
||||
auto hint = map.begin();
|
||||
for( size_t i = 0; i < size; ++i )
|
||||
{
|
||||
typename MapT::key_type key;
|
||||
typename MapT::mapped_type value;
|
||||
|
||||
ar( make_map_item(key, value) );
|
||||
hint = map.insert(hint, {key, value} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::map
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void save( Archive & ar, std::map<K, T, C, A> const & map )
|
||||
{
|
||||
map_detail::save( ar, map );
|
||||
}
|
||||
|
||||
//! Loading for std::map
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void load( Archive & ar, std::map<K, T, C, A> & map )
|
||||
{
|
||||
map_detail::load( ar, map );
|
||||
}
|
||||
|
||||
//! Saving for std::multimap
|
||||
/*! @note serialization for this type is not guaranteed to preserve ordering */
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void save( Archive & ar, std::multimap<K, T, C, A> const & multimap )
|
||||
{
|
||||
map_detail::save( ar, multimap );
|
||||
}
|
||||
|
||||
//! Loading for std::multimap
|
||||
/*! @note serialization for this type is not guaranteed to preserve ordering */
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void load( Archive & ar, std::multimap<K, T, C, A> & multimap )
|
||||
{
|
||||
map_detail::load( ar, multimap );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_MAP_HPP_
|
||||
|
||||
+261
-72
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<memory\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,8 +30,9 @@
|
||||
#ifndef CEREAL_TYPES_SHARED_PTR_HPP_
|
||||
#define CEREAL_TYPES_SHARED_PTR_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
@@ -45,6 +46,9 @@ namespace cereal
|
||||
{
|
||||
PtrWrapper(T && p) : ptr(std::forward<T>(p)) {}
|
||||
T & ptr;
|
||||
|
||||
PtrWrapper( PtrWrapper const & ) = default;
|
||||
PtrWrapper & operator=( PtrWrapper const & ) = delete;
|
||||
};
|
||||
|
||||
//! Make a PtrWrapper
|
||||
@@ -54,57 +58,199 @@ namespace cereal
|
||||
{
|
||||
return {std::forward<T>(t)};
|
||||
}
|
||||
}
|
||||
|
||||
//! A struct that acts as a wrapper around calling load_andor_construct
|
||||
/*! The purpose of this is to allow a load_and_construct call to properly enter into the
|
||||
'data' NVP of the ptr_wrapper
|
||||
@internal */
|
||||
template <class Archive, class T>
|
||||
struct LoadAndConstructLoadWrapper
|
||||
{
|
||||
LoadAndConstructLoadWrapper( T * ptr ) :
|
||||
construct( ptr )
|
||||
{ }
|
||||
|
||||
//! Constructor for embedding an early call for restoring shared_from_this
|
||||
template <class F>
|
||||
LoadAndConstructLoadWrapper( T * ptr, F && sharedFromThisFunc ) :
|
||||
construct( ptr, sharedFromThisFunc )
|
||||
{ }
|
||||
|
||||
inline void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
|
||||
{
|
||||
::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
|
||||
}
|
||||
|
||||
::cereal::construct<T> construct;
|
||||
};
|
||||
|
||||
//! A helper struct for saving and restoring the state of types that derive from
|
||||
//! std::enable_shared_from_this
|
||||
/*! This special struct is necessary because when a user uses load_and_construct,
|
||||
the weak_ptr (or whatever implementation defined variant) that allows
|
||||
enable_shared_from_this to function correctly will not be initialized properly.
|
||||
|
||||
This internal weak_ptr can also be modified by the shared_ptr that is created
|
||||
during the serialization of a polymorphic pointer, where cereal creates a
|
||||
wrapper shared_ptr out of a void pointer to the real data.
|
||||
|
||||
In the case of load_and_construct, this happens because it is the allocation
|
||||
of shared_ptr that perform this initialization, which we let happen on a buffer
|
||||
of memory (aligned_storage). This buffer is then used for placement new
|
||||
later on, effectively overwriting any initialized weak_ptr with a default
|
||||
initialized one, eventually leading to issues when the user calls shared_from_this.
|
||||
|
||||
To get around these issues, we will store the memory for the enable_shared_from_this
|
||||
portion of the class and replace it after whatever happens to modify it (e.g. the
|
||||
user performing construction or the wrapper shared_ptr in saving).
|
||||
|
||||
Note that this goes into undefined behavior territory, but as of the initial writing
|
||||
of this, all standard library implementations of std::enable_shared_from_this are
|
||||
compatible with this memory manipulation. It is entirely possible that this may someday
|
||||
break or may not work with convoluted use cases.
|
||||
|
||||
Example usage:
|
||||
|
||||
@code{.cpp}
|
||||
T * myActualPointer;
|
||||
{
|
||||
EnableSharedStateHelper<T> helper( myActualPointer ); // save the state
|
||||
std::shared_ptr<T> myPtr( myActualPointer ); // modifies the internal weak_ptr
|
||||
// helper restores state when it goes out of scope
|
||||
}
|
||||
@endcode
|
||||
|
||||
When possible, this is designed to be used in an RAII fashion - it will save state on
|
||||
construction and restore it on destruction. The restore can be done at an earlier time
|
||||
(e.g. after construct() is called in load_and_construct) in which case the destructor will
|
||||
do nothing. Performing the restore immediately following construct() allows a user to call
|
||||
shared_from_this within their load_and_construct function.
|
||||
|
||||
@tparam T Type pointed to by shared_ptr
|
||||
@internal */
|
||||
template <class T>
|
||||
class EnableSharedStateHelper
|
||||
{
|
||||
// typedefs for parent type and storage type
|
||||
using BaseType = typename ::cereal::traits::get_shared_from_this_base<T>::type;
|
||||
using ParentType = std::enable_shared_from_this<BaseType>;
|
||||
using StorageType = typename std::aligned_storage<sizeof(ParentType), CEREAL_ALIGNOF(ParentType)>::type;
|
||||
|
||||
public:
|
||||
//! Saves the state of some type inheriting from enable_shared_from_this
|
||||
/*! @param ptr The raw pointer held by the shared_ptr */
|
||||
inline EnableSharedStateHelper( T * ptr ) :
|
||||
itsPtr( static_cast<ParentType *>( ptr ) ),
|
||||
itsState(),
|
||||
itsRestored( false )
|
||||
{
|
||||
std::memcpy( &itsState, itsPtr, sizeof(ParentType) );
|
||||
}
|
||||
|
||||
//! Restores the state of the held pointer (can only be done once)
|
||||
inline void restore()
|
||||
{
|
||||
if( !itsRestored )
|
||||
{
|
||||
// void * cast needed when type has no trivial copy-assignment
|
||||
std::memcpy( static_cast<void *>(itsPtr), &itsState, sizeof(ParentType) );
|
||||
itsRestored = true;
|
||||
}
|
||||
}
|
||||
|
||||
//! Restores the state of the held pointer if not done previously
|
||||
inline ~EnableSharedStateHelper()
|
||||
{
|
||||
restore();
|
||||
}
|
||||
|
||||
private:
|
||||
ParentType * itsPtr;
|
||||
StorageType itsState;
|
||||
bool itsRestored;
|
||||
}; // end EnableSharedStateHelper
|
||||
|
||||
//! Performs loading and construction for a shared pointer that is derived from
|
||||
//! std::enable_shared_from_this
|
||||
/*! @param ar The archive
|
||||
@param ptr Raw pointer held by the shared_ptr
|
||||
@internal */
|
||||
template <class Archive, class T> inline
|
||||
void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::true_type /* has_shared_from_this */ )
|
||||
{
|
||||
memory_detail::EnableSharedStateHelper<T> state( ptr );
|
||||
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr, [&](){ state.restore(); } );
|
||||
|
||||
// let the user perform their initialization, shared state will be restored as soon as construct()
|
||||
// is called
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
}
|
||||
|
||||
//! Performs loading and construction for a shared pointer that is NOT derived from
|
||||
//! std::enable_shared_from_this
|
||||
/*! This is the typical case, where we simply pass the load wrapper to the
|
||||
archive.
|
||||
|
||||
@param ar The archive
|
||||
@param ptr Raw pointer held by the shared_ptr
|
||||
@internal */
|
||||
template <class Archive, class T> inline
|
||||
void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::false_type /* has_shared_from_this */ )
|
||||
{
|
||||
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
}
|
||||
} // end namespace memory_detail
|
||||
|
||||
//! Saving std::shared_ptr for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
save( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
{
|
||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr, case when no user load and allocate for non polymorphic types
|
||||
//! Loading std::shared_ptr, case when no user load and construct for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
load( Archive & ar, std::shared_ptr<T> & ptr )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
|
||||
{
|
||||
ar( memory_detail::make_ptr_wrapper( ptr ) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
//! Saving std::weak_ptr for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
save( Archive & ar, std::weak_ptr<T> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
|
||||
{
|
||||
auto sptr = ptr.lock();
|
||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
|
||||
auto const sptr = ptr.lock();
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
|
||||
}
|
||||
|
||||
//! Loading std::weak_ptr for non polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
load( Archive & ar, std::weak_ptr<T> & ptr )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
|
||||
{
|
||||
std::shared_ptr<T> sptr;
|
||||
ar( memory_detail::make_ptr_wrapper( sptr ) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
|
||||
ptr = sptr;
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr for non polymorphic types
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
save( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
{
|
||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when user provides load_and_allocate for non polymorphic types
|
||||
//! Loading std::unique_ptr, case when user provides load_and_construct for non polymorphic types
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
|
||||
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||
{
|
||||
ar( memory_detail::make_ptr_wrapper( ptr ) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
@@ -113,70 +259,92 @@ namespace cereal
|
||||
//! Saving std::shared_ptr (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
void save( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
uint32_t id = ar.registerSharedPointer( ptr.get() );
|
||||
ar( _CEREAL_NVP("id", id) );
|
||||
ar( CEREAL_NVP_("id", id) );
|
||||
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
ar( _CEREAL_NVP("data", *ptr) );
|
||||
ar( CEREAL_NVP_("data", *ptr) );
|
||||
}
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr, case when user load and allocate (wrapper implementation)
|
||||
//! Loading std::shared_ptr, case when user load and construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<traits::has_load_and_allocate<T, Archive>(), void>::type
|
||||
load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
||||
typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
uint32_t id;
|
||||
|
||||
ar( id );
|
||||
ar( CEREAL_NVP_("id", id) );
|
||||
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
|
||||
ar.registerSharedPointer(id, ptr);
|
||||
// Storage type for the pointer - since we can't default construct this type,
|
||||
// we'll allocate it using std::aligned_storage and use a custom deleter
|
||||
using ST = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
|
||||
|
||||
// Valid flag - set to true once construction finishes
|
||||
// This prevents us from calling the destructor on
|
||||
// uninitialized data.
|
||||
auto valid = std::make_shared<bool>( false );
|
||||
|
||||
// Allocate our storage, which we will treat as
|
||||
// uninitialized until initialized with placement new
|
||||
using NonConstT = typename std::remove_const<T>::type;
|
||||
std::shared_ptr<NonConstT> ptr(reinterpret_cast<NonConstT *>(new ST()),
|
||||
[=]( NonConstT * t )
|
||||
{
|
||||
if( *valid )
|
||||
t->~T();
|
||||
|
||||
delete reinterpret_cast<ST *>( t );
|
||||
} );
|
||||
|
||||
// Register the pointer
|
||||
ar.registerSharedPointer( id, ptr );
|
||||
|
||||
// Perform the actual loading and allocation
|
||||
memory_detail::loadAndConstructSharedPtr( ar, ptr.get(), typename ::cereal::traits::has_shared_from_this<NonConstT>::type() );
|
||||
|
||||
// Mark pointer as valid (initialized)
|
||||
*valid = true;
|
||||
wrapper.ptr = std::move(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||
}
|
||||
wrapper.ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr, case when no user load and allocate (wrapper implementation)
|
||||
//! Loading std::shared_ptr, case when no user load and construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!traits::has_load_and_allocate<T, Archive>(), void>::type
|
||||
load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
||||
typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
uint32_t id;
|
||||
|
||||
ar( id );
|
||||
ar( CEREAL_NVP_("id", id) );
|
||||
|
||||
if( id & detail::msb_32bit )
|
||||
{
|
||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
|
||||
ar( *ptr );
|
||||
ar.registerSharedPointer(id, ptr);
|
||||
using NonConstT = typename std::remove_const<T>::type;
|
||||
std::shared_ptr<NonConstT> ptr( detail::Construct<NonConstT, Archive>::load_andor_construct() );
|
||||
ar.registerSharedPointer( id, ptr );
|
||||
ar( CEREAL_NVP_("data", *ptr) );
|
||||
wrapper.ptr = std::move(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||
}
|
||||
wrapper.ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T, class D> inline
|
||||
void save( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
|
||||
{
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
@@ -185,52 +353,73 @@ namespace cereal
|
||||
// 1 == not null
|
||||
|
||||
if( !ptr )
|
||||
ar( _CEREAL_NVP("valid", uint8_t(0)) );
|
||||
ar( CEREAL_NVP_("valid", uint8_t(0)) );
|
||||
else
|
||||
{
|
||||
ar( _CEREAL_NVP("valid", uint8_t(1)) );
|
||||
ar( _CEREAL_NVP("data", *ptr) );
|
||||
ar( CEREAL_NVP_("valid", uint8_t(1)) );
|
||||
ar( CEREAL_NVP_("data", *ptr) );
|
||||
}
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when user provides load_and_allocate (wrapper implementation)
|
||||
//! Loading std::unique_ptr, case when user provides load_and_construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<traits::has_load_and_allocate<T, Archive>(), void>::type
|
||||
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||
typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||
{
|
||||
uint8_t isValid;
|
||||
ar( isValid );
|
||||
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
if( isValid )
|
||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
|
||||
else
|
||||
ptr.reset( nullptr );
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when no load_and_allocate (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<!traits::has_load_and_allocate<T, Archive>(), void>::type
|
||||
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||
{
|
||||
uint8_t isValid;
|
||||
ar( isValid );
|
||||
ar( CEREAL_NVP_("valid", isValid) );
|
||||
|
||||
auto & ptr = wrapper.ptr;
|
||||
|
||||
if( isValid )
|
||||
{
|
||||
ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
|
||||
ar( *ptr );
|
||||
using NonConstT = typename std::remove_const<T>::type;
|
||||
// Storage type for the pointer - since we can't default construct this type,
|
||||
// we'll allocate it using std::aligned_storage
|
||||
using ST = typename std::aligned_storage<sizeof(NonConstT), CEREAL_ALIGNOF(NonConstT)>::type;
|
||||
|
||||
// Allocate storage - note the ST type so that deleter is correct if
|
||||
// an exception is thrown before we are initialized
|
||||
std::unique_ptr<ST> stPtr( new ST() );
|
||||
|
||||
// Use wrapper to enter into "data" nvp of ptr_wrapper
|
||||
memory_detail::LoadAndConstructLoadWrapper<Archive, NonConstT> loadWrapper( reinterpret_cast<NonConstT *>( stPtr.get() ) );
|
||||
|
||||
// Initialize storage
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
|
||||
// Transfer ownership to correct unique_ptr type
|
||||
ptr.reset( reinterpret_cast<T *>( stPtr.release() ) );
|
||||
}
|
||||
else
|
||||
ptr.reset( nullptr );
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when no load_and_construct (wrapper implementation)
|
||||
/*! @internal */
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
|
||||
{
|
||||
uint8_t isValid;
|
||||
ar( CEREAL_NVP_("valid", isValid) );
|
||||
|
||||
if( isValid )
|
||||
{
|
||||
using NonConstT = typename std::remove_const<T>::type;
|
||||
std::unique_ptr<NonConstT, D> ptr( detail::Construct<NonConstT, Archive>::load_andor_construct() );
|
||||
ar( CEREAL_NVP_( "data", *ptr ) );
|
||||
wrapper.ptr = std::move(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr.reset( nullptr );
|
||||
wrapper.ptr.reset( nullptr );
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// automatically include polymorphic support
|
||||
#include "cereal/types/polymorphic.hpp"
|
||||
|
||||
#endif // CEREAL_TYPES_SHARED_PTR_HPP_
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*! \file optional.hpp
|
||||
\brief Support for std::optional
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2017, Juan Pedro Bolivar Puente
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_STD_OPTIONAL_
|
||||
#define CEREAL_TYPES_STD_OPTIONAL_
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <optional>
|
||||
|
||||
namespace cereal {
|
||||
//! Saving for std::optional
|
||||
template <class Archive, typename T> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME(Archive& ar, const std::optional<T>& optional)
|
||||
{
|
||||
if(!optional) {
|
||||
ar(CEREAL_NVP_("nullopt", true));
|
||||
} else {
|
||||
ar(CEREAL_NVP_("nullopt", false),
|
||||
CEREAL_NVP_("data", *optional));
|
||||
}
|
||||
}
|
||||
|
||||
//! Loading for std::optional
|
||||
template <class Archive, typename T> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, std::optional<T>& optional)
|
||||
{
|
||||
bool nullopt;
|
||||
ar(CEREAL_NVP_("nullopt", nullopt));
|
||||
|
||||
if (nullopt) {
|
||||
optional = std::nullopt;
|
||||
} else {
|
||||
T value;
|
||||
ar(CEREAL_NVP_("data", value));
|
||||
optional = std::move(value);
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_STD_OPTIONAL_
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for pointers to polymorphic base classes
|
||||
\ingroup OtherTypes */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,39 +30,65 @@
|
||||
#ifndef CEREAL_TYPES_POLYMORPHIC_HPP_
|
||||
#define CEREAL_TYPES_POLYMORPHIC_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/types/memory.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/types/memory.hpp"
|
||||
|
||||
#include <cereal/details/util.hpp>
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include <cereal/details/traits.hpp>
|
||||
#include <cereal/details/polymorphic_impl.hpp>
|
||||
#include "cereal/details/util.hpp"
|
||||
#include "cereal/details/helpers.hpp"
|
||||
#include "cereal/details/traits.hpp"
|
||||
#include "cereal/details/polymorphic_impl.hpp"
|
||||
|
||||
//! Registers a polymorphic type with cereal
|
||||
/*! Polymorphic types must be registered before pointers
|
||||
to them can be serialized. This also assumes that
|
||||
all relevent archives have also previously been
|
||||
registered. Registration for archives is usually done
|
||||
in the header file in which they are defined. This means
|
||||
that type registration needs to happen after specific
|
||||
archives to be used are included.
|
||||
#ifdef _MSC_VER
|
||||
#define CEREAL_STATIC_CONSTEXPR static
|
||||
#else
|
||||
#define CEREAL_STATIC_CONSTEXPR static constexpr
|
||||
#endif
|
||||
|
||||
//! Registers a derived polymorphic type with cereal
|
||||
/*! Polymorphic types must be registered before smart
|
||||
pointers to them can be serialized. Note that base
|
||||
classes do not need to be registered.
|
||||
|
||||
Registering a type lets cereal know how to properly
|
||||
serialize it when a pointer to a base object is
|
||||
serialize it when a smart pointer to a base object is
|
||||
used in conjunction with a derived class.
|
||||
|
||||
This assumes that all relevant archives have also
|
||||
previously been registered. Registration for archives
|
||||
is usually done in the header file in which they are
|
||||
defined. This means that type registration needs to
|
||||
happen after specific archives to be used are included.
|
||||
|
||||
It is recommended that type registration be done in
|
||||
the header file in which the type is declared.
|
||||
|
||||
Registration can also be placed in a source file,
|
||||
but this may require the use of the
|
||||
CEREAL_REGISTER_DYNAMIC_INIT macro (see below).
|
||||
|
||||
Registration may be called repeatedly for the same
|
||||
type in different translation units to add support
|
||||
for additional archives if they are not initially
|
||||
available (included and registered).
|
||||
|
||||
When building serialization support as a DLL on
|
||||
Windows, registration must happen in the header file.
|
||||
On Linux and Mac things should still work properly
|
||||
if placed in a source file, but see the above comments
|
||||
on registering in source files.
|
||||
|
||||
Polymorphic support in cereal requires RTTI to be
|
||||
enabled */
|
||||
#define CEREAL_REGISTER_TYPE(T) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template <> \
|
||||
struct binding_name<T> \
|
||||
{ \
|
||||
static constexpr char const * name() { return #T; }; \
|
||||
}; \
|
||||
} } /* end namespaces */ \
|
||||
CEREAL_BIND_TO_ARCHIVES(T);
|
||||
#define CEREAL_REGISTER_TYPE(...) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template <> \
|
||||
struct binding_name<__VA_ARGS__> \
|
||||
{ \
|
||||
CEREAL_STATIC_CONSTEXPR char const * name() { return #__VA_ARGS__; } \
|
||||
}; \
|
||||
} } /* end namespaces */ \
|
||||
CEREAL_BIND_TO_ARCHIVES(__VA_ARGS__)
|
||||
|
||||
//! Registers a polymorphic type with cereal, giving it a
|
||||
//! user defined name
|
||||
@@ -70,19 +96,101 @@
|
||||
CEREAL_REGISTER_TYPE (the name of the type) may not be
|
||||
suitable. This macro allows any name to be associated
|
||||
with the type. The name should be unique */
|
||||
#define CEREAL_REGISTER_TYPE_WITH_NAME(T, Name) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template <> \
|
||||
struct binding_name<T> \
|
||||
{ static constexpr char const * name() { return Name; }; }; \
|
||||
} } /* end namespaces */ \
|
||||
CEREAL_BIND_TO_ARCHIVES(T);
|
||||
#define CEREAL_REGISTER_TYPE_WITH_NAME(T, Name) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template <> \
|
||||
struct binding_name<T> \
|
||||
{ CEREAL_STATIC_CONSTEXPR char const * name() { return Name; } }; \
|
||||
} } /* end namespaces */ \
|
||||
CEREAL_BIND_TO_ARCHIVES(T)
|
||||
|
||||
//! Registers the base-derived relationship for a polymorphic type
|
||||
/*! When polymorphic serialization occurs, cereal needs to know how to
|
||||
properly cast between derived and base types for the polymorphic
|
||||
type. Normally this happens automatically whenever cereal::base_class
|
||||
or cereal::virtual_base_class are used to serialize a base class. In
|
||||
cases where neither of these is ever called but a base class still
|
||||
exists, this explicit registration is required.
|
||||
|
||||
The Derived class should be the most derived type that will be serialized,
|
||||
and the Base type any possible base that has not been covered under a base
|
||||
class serialization that will be used to store a Derived pointer.
|
||||
|
||||
Placement of this is the same as for CEREAL_REGISTER_TYPE. */
|
||||
#define CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, Derived) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
template <> \
|
||||
struct PolymorphicRelation<Base, Derived> \
|
||||
{ static void bind() { RegisterPolymorphicCaster<Base, Derived>::bind(); } }; \
|
||||
} } /* end namespaces */
|
||||
|
||||
//! Adds a way to force initialization of a translation unit containing
|
||||
//! calls to CEREAL_REGISTER_TYPE
|
||||
/*! In C++, dynamic initialization of non-local variables of a translation
|
||||
unit may be deferred until "the first odr-use of any function or variable
|
||||
defined in the same translation unit as the variable to be initialized."
|
||||
|
||||
Informally, odr-use means that your program takes the address of or binds
|
||||
a reference directly to an object, which must have a definition.
|
||||
|
||||
Since polymorphic type support in cereal relies on the dynamic
|
||||
initialization of certain global objects happening before
|
||||
serialization is performed, it is important to ensure that something
|
||||
from files that call CEREAL_REGISTER_TYPE is odr-used before serialization
|
||||
occurs, otherwise the registration will never take place. This may often
|
||||
be the case when serialization is built as a shared library external from
|
||||
your main program.
|
||||
|
||||
This macro, with any name of your choosing, should be placed into the
|
||||
source file that contains calls to CEREAL_REGISTER_TYPE.
|
||||
|
||||
Its counterpart, CEREAL_FORCE_DYNAMIC_INIT, should be placed in its
|
||||
associated header file such that it is included in the translation units
|
||||
(source files) in which you want the registration to appear.
|
||||
|
||||
@relates CEREAL_FORCE_DYNAMIC_INIT
|
||||
*/
|
||||
#define CEREAL_REGISTER_DYNAMIC_INIT(LibName) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
void CEREAL_DLL_EXPORT dynamic_init_dummy_##LibName() {} \
|
||||
} } /* end namespaces */
|
||||
|
||||
//! Forces dynamic initialization of polymorphic support in a
|
||||
//! previously registered source file
|
||||
/*! @sa CEREAL_REGISTER_DYNAMIC_INIT
|
||||
|
||||
See CEREAL_REGISTER_DYNAMIC_INIT for detailed explanation
|
||||
of how this macro should be used. The name used should
|
||||
match that for CEREAL_REGISTER_DYNAMIC_INIT. */
|
||||
#define CEREAL_FORCE_DYNAMIC_INIT(LibName) \
|
||||
namespace cereal { \
|
||||
namespace detail { \
|
||||
void CEREAL_DLL_EXPORT dynamic_init_dummy_##LibName(); \
|
||||
} /* end detail */ \
|
||||
} /* end cereal */ \
|
||||
namespace { \
|
||||
struct dynamic_init_##LibName { \
|
||||
dynamic_init_##LibName() { \
|
||||
::cereal::detail::dynamic_init_dummy_##LibName(); \
|
||||
} \
|
||||
} dynamic_init_instance_##LibName; \
|
||||
} /* end anonymous namespace */
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace polymorphic_detail
|
||||
{
|
||||
//! Error message used for unregistered polymorphic types
|
||||
/*! @internal */
|
||||
#define UNREGISTERED_POLYMORPHIC_EXCEPTION(LoadSave, Name) \
|
||||
throw cereal::Exception("Trying to " #LoadSave " an unregistered polymorphic type (" + Name + ").\n" \
|
||||
"Make sure your type is registered with CEREAL_REGISTER_TYPE and that the archive " \
|
||||
"you are using was included (and registered with CEREAL_REGISTER_ARCHIVE) prior to calling CEREAL_REGISTER_TYPE.\n" \
|
||||
"If your type is already registered and you still see this error, you may need to use CEREAL_REGISTER_DYNAMIC_INIT.");
|
||||
|
||||
//! Get an input binding from the given archive by deserializing the type meta data
|
||||
/*! @internal */
|
||||
template<class Archive> inline
|
||||
@@ -92,39 +200,44 @@ namespace cereal
|
||||
if(nameid == 0)
|
||||
{
|
||||
typename ::cereal::detail::InputBindingMap<Archive>::Serializers emptySerializers;
|
||||
emptySerializers.shared_ptr = [](void*, std::shared_ptr<void> & ptr) { ptr.reset(); };
|
||||
emptySerializers.unique_ptr = [](void*, std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> & ptr) { ptr.reset( nullptr ); };
|
||||
emptySerializers.shared_ptr = [](void*, std::shared_ptr<void> & ptr, std::type_info const &) { ptr.reset(); };
|
||||
emptySerializers.unique_ptr = [](void*, std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> & ptr, std::type_info const &) { ptr.reset( nullptr ); };
|
||||
return emptySerializers;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
if(nameid & detail::msb_32bit)
|
||||
{
|
||||
ar( name );
|
||||
ar( CEREAL_NVP_("polymorphic_name", name) );
|
||||
ar.registerPolymorphicName(nameid, name);
|
||||
}
|
||||
else
|
||||
name = ar.getPolymorphicName(nameid);
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::InputBindingMap<Archive>>::getInstance().map;
|
||||
auto const & bindingMap = detail::StaticObject<detail::InputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(name);
|
||||
if(binding == bindingMap.end())
|
||||
throw cereal::Exception("Trying to load an unregistered polymorphic type (" + name + ")");
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(load, name)
|
||||
return binding->second;
|
||||
}
|
||||
|
||||
//! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||
/*! This check lets us try and skip doing polymorphic machinery if we can get away with
|
||||
using the derived class serialize function
|
||||
|
||||
Note that on MSVC 2013 preview, is_default_constructible<T> returns true for abstract classes with
|
||||
default constructors, but on clang/gcc this will return false. So we also need to check for that here.
|
||||
@internal */
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
typename std::enable_if<(traits::is_default_constructible<T>::value
|
||||
|| traits::has_load_and_construct<T, Archive>::value)
|
||||
&& !std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
{
|
||||
ar( memory_detail::make_ptr_wrapper(ptr) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -135,12 +248,14 @@ namespace cereal
|
||||
using the derived class serialize function
|
||||
@internal */
|
||||
template<class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
typename std::enable_if<(traits::is_default_constructible<T>::value
|
||||
|| traits::has_load_and_construct<T, Archive>::value)
|
||||
&& !std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
{
|
||||
ar( memory_detail::make_ptr_wrapper(ptr) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -153,11 +268,13 @@ namespace cereal
|
||||
this was a polymorphic type serialized by its proper pointer type
|
||||
@internal */
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
typename std::enable_if<(!traits::is_default_constructible<T>::value
|
||||
&& !traits::has_load_and_construct<T, Archive>::value)
|
||||
|| std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
|
||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -168,11 +285,13 @@ namespace cereal
|
||||
this was a polymorphic type serialized by its proper pointer type
|
||||
@internal */
|
||||
template<class Archive, class T, class D> inline
|
||||
typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
typename std::enable_if<(!traits::is_default_constructible<T>::value
|
||||
&& !traits::has_load_and_construct<T, Archive>::value)
|
||||
|| std::is_abstract<T>::value, bool>::type
|
||||
serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
|
||||
{
|
||||
if(nameid & detail::msb2_32bit)
|
||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
|
||||
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
|
||||
return false;
|
||||
}
|
||||
} // polymorphic_detail
|
||||
@@ -183,38 +302,39 @@ namespace cereal
|
||||
//! Saving std::shared_ptr for polymorphic types, abstract
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
|
||||
save( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( _CEREAL_NVP("id", std::uint32_t(0)) );
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||
static std::type_info const & tinfo = typeid(T);
|
||||
// ptrinfo can never be equal to T info since we can't have an instance
|
||||
// of an abstract object
|
||||
// this implies we need to do the lookup
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.shared_ptr(&ar, ptr.get());
|
||||
binding->second.shared_ptr(&ar, ptr.get(), tinfo);
|
||||
}
|
||||
|
||||
//! Saving std::shared_ptr for polymorphic types, not abstract
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
|
||||
save( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( _CEREAL_NVP("id", std::uint32_t(0)) );
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -225,29 +345,29 @@ namespace cereal
|
||||
{
|
||||
// The 2nd msb signals that the following pointer does not need to be
|
||||
// cast with our polymorphic machinery
|
||||
ar( _CEREAL_NVP("id", detail::msb2_32bit) );
|
||||
ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
|
||||
|
||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.shared_ptr(&ar, ptr.get());
|
||||
binding->second.shared_ptr(&ar, ptr.get(), tinfo);
|
||||
}
|
||||
|
||||
//! Loading std::shared_ptr for polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
load( Archive & ar, std::shared_ptr<T> & ptr )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
|
||||
{
|
||||
std::uint32_t nameid;
|
||||
ar( nameid );
|
||||
ar( CEREAL_NVP_("polymorphic_id", nameid) );
|
||||
|
||||
// Check to see if we can skip all of this polymorphism business
|
||||
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
|
||||
@@ -255,64 +375,65 @@ namespace cereal
|
||||
|
||||
auto binding = polymorphic_detail::getInputBinding(ar, nameid);
|
||||
std::shared_ptr<void> result;
|
||||
binding.shared_ptr(&ar, result);
|
||||
binding.shared_ptr(&ar, result, typeid(T));
|
||||
ptr = std::static_pointer_cast<T>(result);
|
||||
}
|
||||
|
||||
//! Saving std::weak_ptr for polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
save( Archive & ar, std::weak_ptr<T> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
|
||||
{
|
||||
auto const sptr = ptr.lock();
|
||||
ar( _CEREAL_NVP("locked_ptr", sptr) );
|
||||
ar( CEREAL_NVP_("locked_ptr", sptr) );
|
||||
}
|
||||
|
||||
//! Loading std::weak_ptr for polymorphic types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
load( Archive & ar, std::weak_ptr<T> & ptr )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
|
||||
{
|
||||
std::shared_ptr<T> sptr;
|
||||
ar( sptr );
|
||||
ar( CEREAL_NVP_("locked_ptr", sptr) );
|
||||
ptr = sptr;
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr for polymorphic types that are abstract
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
|
||||
save( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( _CEREAL_NVP("id", std::uint32_t(0)) );
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||
static std::type_info const & tinfo = typeid(T);
|
||||
// ptrinfo can never be equal to T info since we can't have an instance
|
||||
// of an abstract object
|
||||
// this implies we need to do the lookup
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.unique_ptr(&ar, ptr.get());
|
||||
binding->second.unique_ptr(&ar, ptr.get(), tinfo);
|
||||
}
|
||||
|
||||
//! Saving std::unique_ptr for polymorphic types, not abstract
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
|
||||
save( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
|
||||
{
|
||||
if(!ptr)
|
||||
{
|
||||
// same behavior as nullptr in memory implementation
|
||||
ar( _CEREAL_NVP("id", std::uint32_t(0)) );
|
||||
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -323,29 +444,29 @@ namespace cereal
|
||||
{
|
||||
// The 2nd msb signals that the following pointer does not need to be
|
||||
// cast with our polymorphic machinery
|
||||
ar( _CEREAL_NVP("id", detail::msb2_32bit) );
|
||||
ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
|
||||
|
||||
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||
|
||||
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||
if(binding == bindingMap.end())
|
||||
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
|
||||
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
|
||||
|
||||
binding->second.unique_ptr(&ar, ptr.get());
|
||||
binding->second.unique_ptr(&ar, ptr.get(), tinfo);
|
||||
}
|
||||
|
||||
//! Loading std::unique_ptr, case when user provides load_and_allocate for polymorphic types
|
||||
//! Loading std::unique_ptr, case when user provides load_and_construct for polymorphic types
|
||||
template <class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||
{
|
||||
std::uint32_t nameid;
|
||||
ar( nameid );
|
||||
ar( CEREAL_NVP_("polymorphic_id", nameid) );
|
||||
|
||||
// Check to see if we can skip all of this polymorphism business
|
||||
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
|
||||
@@ -353,8 +474,10 @@ namespace cereal
|
||||
|
||||
auto binding = polymorphic_detail::getInputBinding(ar, nameid);
|
||||
std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> result;
|
||||
binding.unique_ptr(&ar, result);
|
||||
binding.unique_ptr(&ar, result, typeid(T));
|
||||
ptr.reset(static_cast<T*>(result.release()));
|
||||
}
|
||||
|
||||
#undef UNREGISTERED_POLYMORPHIC_EXCEPTION
|
||||
} // namespace cereal
|
||||
#endif // CEREAL_TYPES_POLYMORPHIC_HPP_
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<queue\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,11 +30,13 @@
|
||||
#ifndef CEREAL_TYPES_QUEUE_HPP_
|
||||
#define CEREAL_TYPES_QUEUE_HPP_
|
||||
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include "cereal/details/helpers.hpp"
|
||||
#include <queue>
|
||||
|
||||
// The default container for queue is deque, so let's include that too
|
||||
#include <cereal/types/deque.hpp>
|
||||
#include "cereal/types/deque.hpp"
|
||||
// The default comparator for queue is less
|
||||
#include "cereal/types/functional.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
@@ -91,37 +93,37 @@ namespace cereal
|
||||
|
||||
//! Saving for std::queue
|
||||
template <class Archive, class T, class C> inline
|
||||
void save( Archive & ar, std::queue<T, C> const & queue )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::queue<T, C> const & queue )
|
||||
{
|
||||
ar( _CEREAL_NVP("container", queue_detail::container( queue )) );
|
||||
ar( CEREAL_NVP_("container", queue_detail::container( queue )) );
|
||||
}
|
||||
|
||||
//! Loading for std::queue
|
||||
template <class Archive, class T, class C> inline
|
||||
void load( Archive & ar, std::queue<T, C> & queue )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::queue<T, C> & queue )
|
||||
{
|
||||
C container;
|
||||
ar( container );
|
||||
ar( CEREAL_NVP_("container", container) );
|
||||
queue = std::queue<T, C>( std::move( container ) );
|
||||
}
|
||||
|
||||
//! Saving for std::priority_queue
|
||||
template <class Archive, class T, class C, class Comp> inline
|
||||
void save( Archive & ar, std::priority_queue<T, C, Comp> const & priority_queue )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> const & priority_queue )
|
||||
{
|
||||
ar( _CEREAL_NVP("comparator", queue_detail::comparator( priority_queue )) );
|
||||
ar( _CEREAL_NVP("container", queue_detail::container( priority_queue )) );
|
||||
ar( CEREAL_NVP_("comparator", queue_detail::comparator( priority_queue )) );
|
||||
ar( CEREAL_NVP_("container", queue_detail::container( priority_queue )) );
|
||||
}
|
||||
|
||||
//! Loading for std::priority_queue
|
||||
template <class Archive, class T, class C, class Comp> inline
|
||||
void load( Archive & ar, std::priority_queue<T, C, Comp> & priority_queue )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> & priority_queue )
|
||||
{
|
||||
Comp comparator;
|
||||
ar( comparator );
|
||||
ar( CEREAL_NVP_("comparator", comparator) );
|
||||
|
||||
C container;
|
||||
ar( container );
|
||||
ar( CEREAL_NVP_("container", container) );
|
||||
|
||||
priority_queue = std::priority_queue<T, C, Comp>( comparator, std::move( container ) );
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<set\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,7 +30,7 @@
|
||||
#ifndef CEREAL_TYPES_SET_HPP_
|
||||
#define CEREAL_TYPES_SET_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <set>
|
||||
|
||||
namespace cereal
|
||||
@@ -62,35 +62,39 @@ namespace cereal
|
||||
typename SetT::key_type key;
|
||||
|
||||
ar( key );
|
||||
hint = set.insert(hint, key );
|
||||
#ifdef CEREAL_OLDER_GCC
|
||||
hint = set.insert( hint, std::move( key ) );
|
||||
#else // NOT CEREAL_OLDER_GCC
|
||||
hint = set.emplace_hint( hint, std::move( key ) );
|
||||
#endif // NOT CEREAL_OLDER_GCC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::set
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void save( Archive & ar, std::set<K, C, A> const & set )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::set<K, C, A> const & set )
|
||||
{
|
||||
set_detail::save( ar, set );
|
||||
}
|
||||
|
||||
//! Loading for std::set
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void load( Archive & ar, std::set<K, C, A> & set )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::set<K, C, A> & set )
|
||||
{
|
||||
set_detail::load( ar, set );
|
||||
}
|
||||
|
||||
//! Saving for std::multiset
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void save( Archive & ar, std::multiset<K, C, A> const & multiset )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> const & multiset )
|
||||
{
|
||||
set_detail::save( ar, multiset );
|
||||
}
|
||||
|
||||
//! Loading for std::multiset
|
||||
template <class Archive, class K, class C, class A> inline
|
||||
void load( Archive & ar, std::multiset<K, C, A> & multiset )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> & multiset )
|
||||
{
|
||||
set_detail::load( ar, multiset );
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<stack\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,11 +30,11 @@
|
||||
#ifndef CEREAL_TYPES_STACK_HPP_
|
||||
#define CEREAL_TYPES_STACK_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <stack>
|
||||
|
||||
// The default container for stack is deque, so let's include that too
|
||||
#include <cereal/types/deque.hpp>
|
||||
#include "cereal/types/deque.hpp"
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
@@ -58,17 +58,17 @@ namespace cereal
|
||||
|
||||
//! Saving for std::stack
|
||||
template <class Archive, class T, class C> inline
|
||||
void save( Archive & ar, std::stack<T, C> const & stack )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::stack<T, C> const & stack )
|
||||
{
|
||||
ar( _CEREAL_NVP("container", stack_detail::container( stack )) );
|
||||
ar( CEREAL_NVP_("container", stack_detail::container( stack )) );
|
||||
}
|
||||
|
||||
//! Loading for std::stack
|
||||
template <class Archive, class T, class C> inline
|
||||
void load( Archive & ar, std::stack<T, C> & stack )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::stack<T, C> & stack )
|
||||
{
|
||||
C container;
|
||||
ar( container );
|
||||
ar( CEREAL_NVP_("container", container) );
|
||||
stack = std::stack<T, C>( std::move( container ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<string\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,15 +30,15 @@
|
||||
#ifndef CEREAL_TYPES_STRING_HPP_
|
||||
#define CEREAL_TYPES_STRING_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serialization for basic_string types, if binary data is supported
|
||||
template<class Archive, class CharT, class Traits, class Alloc> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<CharT>, Archive>(), void>::type
|
||||
save(Archive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<CharT>, Archive>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
{
|
||||
// Save number of chars + the data
|
||||
ar( make_size_tag( static_cast<size_type>(str.size()) ) );
|
||||
@@ -47,13 +47,13 @@ namespace cereal
|
||||
|
||||
//! Serialization for basic_string types, if binary data is supported
|
||||
template<class Archive, class CharT, class Traits, class Alloc> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<CharT>, Archive>(), void>::type
|
||||
load(Archive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<CharT>, Archive>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
str.resize(size);
|
||||
ar( binary_data( &(*str.begin()), size * sizeof(CharT) ) );
|
||||
str.resize(static_cast<std::size_t>(size));
|
||||
ar( binary_data( const_cast<CharT *>( str.data() ), static_cast<std::size_t>(size) * sizeof(CharT) ) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<tuple\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,13 +30,63 @@
|
||||
#ifndef CEREAL_TYPES_TUPLE_HPP_
|
||||
#define CEREAL_TYPES_TUPLE_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <tuple>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace tuple_detail
|
||||
{
|
||||
//! Creates a c string from a sequence of characters
|
||||
/*! The c string created will always be prefixed by "tuple_element"
|
||||
Based on code from: http://stackoverflow/a/20973438/710791
|
||||
@internal */
|
||||
template<char...Cs>
|
||||
struct char_seq_to_c_str
|
||||
{
|
||||
static const int size = 14;// Size of array for the word: tuple_element
|
||||
typedef const char (&arr_type)[sizeof...(Cs) + size];
|
||||
static const char str[sizeof...(Cs) + size];
|
||||
};
|
||||
|
||||
// the word tuple_element plus a number
|
||||
//! @internal
|
||||
template<char...Cs>
|
||||
const char char_seq_to_c_str<Cs...>::str[sizeof...(Cs) + size] =
|
||||
{'t','u','p','l','e','_','e','l','e','m','e','n','t', Cs..., '\0'};
|
||||
|
||||
//! Converts a number into a sequence of characters
|
||||
/*! @tparam Q The quotient of dividing the original number by 10
|
||||
@tparam R The remainder of dividing the original number by 10
|
||||
@tparam C The sequence built so far
|
||||
@internal */
|
||||
template <size_t Q, size_t R, char ... C>
|
||||
struct to_string_impl
|
||||
{
|
||||
using type = typename to_string_impl<Q/10, Q%10, static_cast<char>(R+std::size_t{'0'}), C...>::type;
|
||||
};
|
||||
|
||||
//! Base case with no quotient
|
||||
/*! @internal */
|
||||
template <size_t R, char ... C>
|
||||
struct to_string_impl<0, R, C...>
|
||||
{
|
||||
using type = char_seq_to_c_str<static_cast<char>(R+std::size_t{'0'}), C...>;
|
||||
};
|
||||
|
||||
//! Generates a c string for a given index of a tuple
|
||||
/*! Example use:
|
||||
@code{cpp}
|
||||
tuple_element_name<3>::c_str();// returns "tuple_element3"
|
||||
@endcode
|
||||
@internal */
|
||||
template<size_t T>
|
||||
struct tuple_element_name
|
||||
{
|
||||
using type = typename to_string_impl<T/10, T%10>::type;
|
||||
static const typename type::arr_type c_str(){ return type::str; }
|
||||
};
|
||||
|
||||
// unwinds a tuple to save it
|
||||
//! @internal
|
||||
template <size_t Height>
|
||||
@@ -45,8 +95,9 @@ namespace cereal
|
||||
template <class Archive, class ... Types> inline
|
||||
static void apply( Archive & ar, std::tuple<Types...> & tuple )
|
||||
{
|
||||
ar( _CEREAL_NVP("tuple_element", std::get<Height - 1>( tuple )) );
|
||||
serialize<Height - 1>::template apply( ar, tuple );
|
||||
ar( CEREAL_NVP_(tuple_element_name<Height - 1>::c_str(),
|
||||
std::get<Height - 1>( tuple )) );
|
||||
}
|
||||
};
|
||||
|
||||
@@ -63,7 +114,7 @@ namespace cereal
|
||||
|
||||
//! Serializing for std::tuple
|
||||
template <class Archive, class ... Types> inline
|
||||
void serialize( Archive & ar, std::tuple<Types...> & tuple )
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::tuple<Types...> & tuple )
|
||||
{
|
||||
tuple_detail::serialize<std::tuple_size<std::tuple<Types...>>::value>::template apply( ar, tuple );
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<unordered_map\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,71 +30,7 @@
|
||||
#ifndef CEREAL_TYPES_UNORDERED_MAP_HPP_
|
||||
#define CEREAL_TYPES_UNORDERED_MAP_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/types/concepts/pair_associative_container.hpp"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace unordered_map_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void save( Archive & ar, MapT const & map )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(map.size()) ) );
|
||||
|
||||
for( const auto & i : map )
|
||||
ar( make_map_item(i.first, i.second) );
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void load( Archive & ar, MapT & map )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
map.clear();
|
||||
map.reserve( size );
|
||||
|
||||
for( size_type i = 0; i < size; ++i )
|
||||
{
|
||||
typename MapT::key_type key;
|
||||
typename MapT::mapped_type value;
|
||||
|
||||
ar( make_map_item(key, value) );
|
||||
map.insert( {key, value} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_map
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void save( Archive & ar, std::unordered_map<K, T, H, KE, A> const & unordered_map )
|
||||
{
|
||||
unordered_map_detail::save( ar, unordered_map );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_map
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void load( Archive & ar, std::unordered_map<K, T, H, KE, A> & unordered_map )
|
||||
{
|
||||
unordered_map_detail::load( ar, unordered_map );
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_multimap
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void save( Archive & ar, std::unordered_multimap<K, T, H, KE, A> const & unordered_multimap )
|
||||
{
|
||||
unordered_map_detail::save( ar, unordered_multimap );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_multimap
|
||||
template <class Archive, class K, class T, class H, class KE, class A> inline
|
||||
void load( Archive & ar, std::unordered_multimap<K, T, H, KE, A> & unordered_multimap )
|
||||
{
|
||||
unordered_map_detail::load( ar, unordered_multimap );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_UNORDERED_MAP_HPP_
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<unordered_set\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,7 +30,7 @@
|
||||
#ifndef CEREAL_TYPES_UNORDERED_SET_HPP_
|
||||
#define CEREAL_TYPES_UNORDERED_SET_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <unordered_set>
|
||||
|
||||
namespace cereal
|
||||
@@ -55,42 +55,42 @@ namespace cereal
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
set.clear();
|
||||
set.reserve( size );
|
||||
set.reserve( static_cast<std::size_t>( size ) );
|
||||
|
||||
for( size_type i = 0; i < size; ++i )
|
||||
{
|
||||
typename SetT::key_type key;
|
||||
|
||||
ar( key );
|
||||
set.insert( key );
|
||||
set.emplace( std::move( key ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_set
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void save( Archive & ar, std::unordered_set<K, H, KE, A> const & unordered_set )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> const & unordered_set )
|
||||
{
|
||||
unordered_set_detail::save( ar, unordered_set );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_set
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void load( Archive & ar, std::unordered_set<K, H, KE, A> & unordered_set )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> & unordered_set )
|
||||
{
|
||||
unordered_set_detail::load( ar, unordered_set );
|
||||
}
|
||||
|
||||
//! Saving for std::unordered_multiset
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void save( Archive & ar, std::unordered_multiset<K, H, KE, A> const & unordered_multiset )
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> const & unordered_multiset )
|
||||
{
|
||||
unordered_set_detail::save( ar, unordered_multiset );
|
||||
}
|
||||
|
||||
//! Loading for std::unordered_multiset
|
||||
template <class Archive, class K, class H, class KE, class A> inline
|
||||
void load( Archive & ar, std::unordered_multiset<K, H, KE, A> & unordered_multiset )
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> & unordered_multiset )
|
||||
{
|
||||
unordered_set_detail::load( ar, unordered_multiset );
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<utility\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,17 +30,17 @@
|
||||
#ifndef CEREAL_TYPES_UTILITY_HPP_
|
||||
#define CEREAL_TYPES_UTILITY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serializing for std::pair
|
||||
template <class Archive, class T1, class T2> inline
|
||||
void serialize( Archive & ar, std::pair<T1, T2> & pair )
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::pair<T1, T2> & pair )
|
||||
{
|
||||
ar( _CEREAL_NVP("first", pair.first),
|
||||
_CEREAL_NVP("second", pair.second) );
|
||||
ar( CEREAL_NVP_("first", pair.first),
|
||||
CEREAL_NVP_("second", pair.second) );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*! \file valarray.hpp
|
||||
\brief Support for types found in \<valarray\>
|
||||
\ingroup STLSupport */
|
||||
|
||||
/*
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_TYPES_VALARRAY_HPP_
|
||||
#define CEREAL_TYPES_VALARRAY_HPP_
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <valarray>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Saving for std::valarray arithmetic types, using binary serialization, if supported
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::valarray<T> const & valarray )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(valarray.size()) ) ); // number of elements
|
||||
ar( binary_data( &valarray[0], valarray.size() * sizeof(T) ) ); // &valarray[0] ok since guaranteed contiguous
|
||||
}
|
||||
|
||||
//! Loading for std::valarray arithmetic types, using binary serialization, if supported
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::valarray<T> & valarray )
|
||||
{
|
||||
size_type valarraySize;
|
||||
ar( make_size_tag( valarraySize ) );
|
||||
|
||||
valarray.resize( static_cast<std::size_t>( valarraySize ) );
|
||||
ar( binary_data( &valarray[0], static_cast<std::size_t>( valarraySize ) * sizeof(T) ) );
|
||||
}
|
||||
|
||||
//! Saving for std::valarray all other types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::valarray<T> const & valarray )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(valarray.size()) ) ); // number of elements
|
||||
for(auto && v : valarray)
|
||||
ar(v);
|
||||
}
|
||||
|
||||
//! Loading for std::valarray all other types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::valarray<T> & valarray )
|
||||
{
|
||||
size_type valarraySize;
|
||||
ar( make_size_tag( valarraySize ) );
|
||||
|
||||
valarray.resize( static_cast<size_t>( valarraySize ) );
|
||||
for(auto && v : valarray)
|
||||
ar(v);
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_VALARRAY_HPP_
|
||||
@@ -0,0 +1,109 @@
|
||||
/*! \file variant.hpp
|
||||
\brief Support for std::variant
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2014, 2017, Randolph Voorhies, Shane Grant, Juan Pedro
|
||||
Bolivar Puente. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_TYPES_STD_VARIANT_HPP_
|
||||
#define CEREAL_TYPES_STD_VARIANT_HPP_
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <variant>
|
||||
#include <cstdint>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace variant_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive>
|
||||
struct variant_save_visitor
|
||||
{
|
||||
variant_save_visitor(Archive & ar_) : ar(ar_) {}
|
||||
|
||||
template<class T>
|
||||
void operator()(T const & value) const
|
||||
{
|
||||
ar( CEREAL_NVP_("data", value) );
|
||||
}
|
||||
|
||||
Archive & ar;
|
||||
};
|
||||
|
||||
//! @internal
|
||||
template<int N, class Variant, class ... Args, class Archive>
|
||||
typename std::enable_if<N == std::variant_size_v<Variant>, void>::type
|
||||
load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
|
||||
{
|
||||
throw ::cereal::Exception("Error traversing variant during load");
|
||||
}
|
||||
//! @internal
|
||||
template<int N, class Variant, class H, class ... T, class Archive>
|
||||
typename std::enable_if<N < std::variant_size_v<Variant>, void>::type
|
||||
load_variant(Archive & ar, int target, Variant & variant)
|
||||
{
|
||||
if(N == target)
|
||||
{
|
||||
H value;
|
||||
ar( CEREAL_NVP_("data", value) );
|
||||
variant = std::move(value);
|
||||
}
|
||||
else
|
||||
load_variant<N+1, Variant, T...>(ar, target, variant);
|
||||
}
|
||||
|
||||
} // namespace variant_detail
|
||||
|
||||
//! Saving for std::variant
|
||||
template <class Archive, typename VariantType1, typename... VariantTypes> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::variant<VariantType1, VariantTypes...> const & variant )
|
||||
{
|
||||
std::int32_t index = static_cast<std::int32_t>(variant.index());
|
||||
ar( CEREAL_NVP_("index", index) );
|
||||
variant_detail::variant_save_visitor<Archive> visitor(ar);
|
||||
std::visit(visitor, variant);
|
||||
}
|
||||
|
||||
//! Loading for std::variant
|
||||
template <class Archive, typename... VariantTypes> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::variant<VariantTypes...> & variant )
|
||||
{
|
||||
using variant_t = typename std::variant<VariantTypes...>;
|
||||
|
||||
std::int32_t index;
|
||||
ar( CEREAL_NVP_("index", index) );
|
||||
if(index >= static_cast<std::int32_t>(std::variant_size_v<variant_t>))
|
||||
throw Exception("Invalid 'index' selector when deserializing std::variant");
|
||||
|
||||
variant_detail::load_variant<0, variant_t, VariantTypes...>(ar, index, variant);
|
||||
}
|
||||
|
||||
//! Serializing a std::monostate
|
||||
template <class Archive>
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive &, std::monostate const & ) {}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_TYPES_STD_VARIANT_HPP_
|
||||
@@ -2,7 +2,7 @@
|
||||
\brief Support for types found in \<vector\>
|
||||
\ingroup STLSupport */
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,16 +30,16 @@
|
||||
#ifndef CEREAL_TYPES_VECTOR_HPP_
|
||||
#define CEREAL_TYPES_VECTOR_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serialization for std::vectors of arithmetic (but not bool) using binary serialization, if supported
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>()
|
||||
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
|
||||
save( Archive & ar, std::vector<T, A> const & vector )
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
|
||||
ar( binary_data( vector.data(), vector.size() * sizeof(T) ) );
|
||||
@@ -47,42 +47,65 @@ namespace cereal
|
||||
|
||||
//! Serialization for std::vectors of arithmetic (but not bool) using binary serialization, if supported
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>()
|
||||
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
&& std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
|
||||
load( Archive & ar, std::vector<T, A> & vector )
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
|
||||
{
|
||||
size_type vectorSize;
|
||||
ar( make_size_tag( vectorSize ) );
|
||||
|
||||
vector.resize( vectorSize );
|
||||
ar( binary_data( vector.data(), vectorSize * sizeof(T) ) );
|
||||
vector.resize( static_cast<std::size_t>( vectorSize ) );
|
||||
ar( binary_data( vector.data(), static_cast<std::size_t>( vectorSize ) * sizeof(T) ) );
|
||||
}
|
||||
|
||||
//! Serialization for non-arithmetic (and bool) vector types
|
||||
//! Serialization for non-arithmetic vector types
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>()
|
||||
|| !std::is_arithmetic<T>::value
|
||||
|| std::is_same<T, bool>::value, void>::type
|
||||
save( Archive & ar, std::vector<T, A> const & vector )
|
||||
typename std::enable_if<(!traits::is_output_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value) && !std::is_same<T, bool>::value, void>::type
|
||||
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
|
||||
for( auto it = vector.begin(), end = vector.end(); it != end; ++it )
|
||||
ar( *it );
|
||||
for(auto && v : vector)
|
||||
ar( v );
|
||||
}
|
||||
|
||||
//! Serialization for non-arithmetic (and bool) vector types
|
||||
//! Serialization for non-arithmetic vector types
|
||||
template <class Archive, class T, class A> inline
|
||||
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>()
|
||||
|| !std::is_arithmetic<T>::value
|
||||
|| std::is_same<T, bool>::value, void>::type
|
||||
load( Archive & ar, std::vector<T, A> & vector )
|
||||
typename std::enable_if<(!traits::is_input_serializable<BinaryData<T>, Archive>::value
|
||||
|| !std::is_arithmetic<T>::value) && !std::is_same<T, bool>::value, void>::type
|
||||
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
vector.resize( size );
|
||||
for( auto it = vector.begin(), end = vector.end(); it != end; ++it )
|
||||
ar( *it );
|
||||
vector.resize( static_cast<std::size_t>( size ) );
|
||||
for(auto && v : vector)
|
||||
ar( v );
|
||||
}
|
||||
|
||||
//! Serialization for bool vector types
|
||||
template <class Archive, class A> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<bool, A> const & vector )
|
||||
{
|
||||
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
|
||||
for(const auto v : vector)
|
||||
ar( static_cast<bool>(v) );
|
||||
}
|
||||
|
||||
//! Serialization for bool vector types
|
||||
template <class Archive, class A> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<bool, A> & vector )
|
||||
{
|
||||
size_type size;
|
||||
ar( make_size_tag( size ) );
|
||||
|
||||
vector.resize( static_cast<std::size_t>( size ) );
|
||||
for(auto v : vector)
|
||||
{
|
||||
bool b;
|
||||
ar( b );
|
||||
v = b;
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*! \file version.hpp
|
||||
\brief Macros to detect cereal version
|
||||
|
||||
These macros can assist in determining the version of cereal. Be
|
||||
warned that cereal is not guaranteed to be compatible across
|
||||
different versions. For more information on releases of cereal,
|
||||
see https://github.com/USCiLab/cereal/releases.
|
||||
|
||||
\ingroup utility */
|
||||
/*
|
||||
Copyright (c) 2018, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CEREAL_VERSION_HPP_
|
||||
#define CEREAL_VERSION_HPP_
|
||||
|
||||
//! The major version
|
||||
#define CEREAL_VERSION_MAJOR 1
|
||||
//! The minor version
|
||||
#define CEREAL_VERSION_MINOR 3
|
||||
//! The patch version
|
||||
#define CEREAL_VERSION_PATCH 0
|
||||
|
||||
//! The full version as a single number
|
||||
#define CEREAL_VERSION (CEREAL_VERSION_MAJOR * 10000 \
|
||||
+ CEREAL_VERSION_MINOR * 100 \
|
||||
+ CEREAL_VERSION_PATCH)
|
||||
|
||||
#endif // CEREAL_VERSION_HPP_
|
||||
@@ -0,0 +1,17 @@
|
||||
add_subdirectory(sandbox_shared_lib)
|
||||
|
||||
add_executable(sandbox sandbox.cpp)
|
||||
add_executable(sandbox_json sandbox_json.cpp)
|
||||
add_executable(sandbox_rtti sandbox_rtti.cpp)
|
||||
|
||||
add_executable(sandbox_vs sandbox_vs.cpp)
|
||||
target_link_libraries(sandbox_vs sandbox_vs_dll)
|
||||
include_directories(sandbox_shared_lib)
|
||||
|
||||
if((Boost_FOUND) AND NOT SKIP_PERFORMANCE_COMPARISON)
|
||||
add_executable(performance performance.cpp)
|
||||
if(MSVC)
|
||||
set_target_properties(performance PROPERTIES COMPILE_DEFINITIONS "BOOST_SERIALIZATION_DYN_LINK")
|
||||
endif()
|
||||
target_link_libraries(performance ${Boost_LIBRARIES})
|
||||
endif()
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
Copyright (c) 2014, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -24,6 +24,14 @@
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4244 4267)
|
||||
#endif
|
||||
|
||||
// fix for old versions of boost + deprecated auto_ptr
|
||||
#define BOOST_NO_AUTO_PTR
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
@@ -131,16 +139,26 @@ struct binary
|
||||
some data. Result is output to standard out.
|
||||
|
||||
@tparam SerializationT The serialization struct that has all save and load functions
|
||||
@tparam DataT The type of data to test
|
||||
@tparam DataTCereal The type of data to test for cereal
|
||||
@tparam DataTBoost The type of data to test for boost
|
||||
@param name The name for this test
|
||||
@param data The data to serialize
|
||||
@param data The data to serialize for cereal
|
||||
@param data The data to serialize for boost
|
||||
@param numAverages The number of times to average
|
||||
@param validateData Whether data should be validated (input == output) */
|
||||
template <class SerializationT, class DataT>
|
||||
template <class SerializationT, class DataTCereal, class DataTBoost>
|
||||
void test( std::string const & name,
|
||||
DataT const & data,
|
||||
DataTCereal const & dataC,
|
||||
DataTBoost const & dataB,
|
||||
size_t numAverages = 100,
|
||||
bool validateData = false )
|
||||
bool validateData = false );
|
||||
|
||||
template <class SerializationT, class DataTCereal, class DataTBoost>
|
||||
void test( std::string const & name,
|
||||
DataTCereal const & dataC,
|
||||
DataTBoost const & dataB,
|
||||
size_t numAverages,
|
||||
bool /*validateData*/ )
|
||||
{
|
||||
std::cout << "-----------------------------------" << std::endl;
|
||||
std::cout << "Running test: " << name << std::endl;
|
||||
@@ -159,31 +177,25 @@ void test( std::string const & name,
|
||||
// Boost
|
||||
{
|
||||
std::ostringstream os;
|
||||
auto saveResult = saveData<DataT>( data, {SerializationT::boost::template save<DataT>}, os );
|
||||
auto saveResult = saveData<DataTBoost>( dataB, {SerializationT::boost::template save<DataTBoost>}, os );
|
||||
totalBoostSave += saveResult;
|
||||
if(!boostSize)
|
||||
boostSize = os.tellp();
|
||||
|
||||
auto loadResult = loadData<DataT>( os, {SerializationT::boost::template load<DataT>} );
|
||||
auto loadResult = loadData<DataTBoost>( os, {SerializationT::boost::template load<DataTBoost>} );
|
||||
totalBoostLoad += loadResult.second;
|
||||
|
||||
if( validateData )
|
||||
; // TODO
|
||||
}
|
||||
|
||||
// Cereal
|
||||
{
|
||||
std::ostringstream os;
|
||||
auto saveResult = saveData<DataT>( data, {SerializationT::cereal::template save<DataT>}, os );
|
||||
auto saveResult = saveData<DataTCereal>( dataC, {SerializationT::cereal::template save<DataTCereal>}, os );
|
||||
totalCerealSave += saveResult;
|
||||
if(!cerealSize)
|
||||
cerealSize = os.tellp();
|
||||
|
||||
auto loadResult = loadData<DataT>( os, {SerializationT::cereal::template load<DataT>} );
|
||||
auto loadResult = loadData<DataTCereal>( os, {SerializationT::cereal::template load<DataTCereal>} );
|
||||
totalCerealLoad += loadResult.second;
|
||||
|
||||
if( validateData )
|
||||
; // TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,16 +228,30 @@ void test( std::string const & name,
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template <class SerializationT, class DataT>
|
||||
void test( std::string const & name,
|
||||
DataT const & data,
|
||||
size_t numAverages = 100,
|
||||
bool validateData = false )
|
||||
{
|
||||
return test<SerializationT, DataT, DataT>( name, data, data, numAverages, validateData );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
random_value(std::mt19937 & gen)
|
||||
{ return std::uniform_real_distribution<T>(-10000.0, 10000.0)(gen); }
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
typename std::enable_if<std::is_integral<T>::value && sizeof(T) != sizeof(char), T>::type
|
||||
random_value(std::mt19937 & gen)
|
||||
{ return std::uniform_int_distribution<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen); }
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(char), T>::type
|
||||
random_value(std::mt19937 & gen)
|
||||
{ return static_cast<T>( std::uniform_int_distribution<int64_t>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen) ); }
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type
|
||||
random_value(std::mt19937 & gen)
|
||||
@@ -241,7 +267,8 @@ std::basic_string<C> random_basic_string(std::mt19937 & gen, size_t maxSize = 30
|
||||
{
|
||||
std::basic_string<C> s(std::uniform_int_distribution<int>(3, maxSize)(gen), ' ');
|
||||
for(C & c : s)
|
||||
c = std::uniform_int_distribution<C>(' ', '~')(gen);
|
||||
c = static_cast<C>( std::uniform_int_distribution<int>( '~', '~' )(gen) );
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -254,7 +281,7 @@ std::string random_binary_string(std::mt19937 & gen)
|
||||
return s;
|
||||
}
|
||||
|
||||
struct PoDStruct
|
||||
struct PoDStructCereal
|
||||
{
|
||||
int32_t a;
|
||||
int64_t b;
|
||||
@@ -265,18 +292,26 @@ struct PoDStruct
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar(a, b, c, d);
|
||||
};
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar, const unsigned int version )
|
||||
{
|
||||
ar & a & b & c & d;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct PoDChild : virtual PoDStruct
|
||||
struct PoDStructBoost
|
||||
{
|
||||
PoDChild() : v(1024)
|
||||
int32_t a;
|
||||
int64_t b;
|
||||
float c;
|
||||
double d;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar, const unsigned int /*version*/ )
|
||||
{
|
||||
ar & a & b & c & d;
|
||||
}
|
||||
};
|
||||
|
||||
struct PoDChildCereal : virtual PoDStructCereal
|
||||
{
|
||||
PoDChildCereal() : v(1024)
|
||||
{ }
|
||||
|
||||
std::vector<float> v;
|
||||
@@ -284,15 +319,23 @@ struct PoDChild : virtual PoDStruct
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::virtual_base_class<PoDStruct>(this), v );
|
||||
};
|
||||
ar( cereal::virtual_base_class<PoDStructCereal>(this), v );
|
||||
}
|
||||
};
|
||||
|
||||
struct PoDChildBoost : virtual PoDStructBoost
|
||||
{
|
||||
PoDChildBoost() : v(1024)
|
||||
{ }
|
||||
|
||||
std::vector<float> v;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar, const unsigned int version )
|
||||
void serialize( Archive & ar, const unsigned int /*version*/ )
|
||||
{
|
||||
ar & boost::serialization::base_object<PoDStruct>(*this);
|
||||
ar & boost::serialization::base_object<PoDStructBoost>(*this);
|
||||
ar & v;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
@@ -304,13 +347,13 @@ int main()
|
||||
const bool randomize = false;
|
||||
|
||||
//########################################
|
||||
auto vectorDoubleTest = [&](size_t s, bool randomize)
|
||||
auto vectorDoubleTest = [&](size_t s, bool randomize_)
|
||||
{
|
||||
std::ostringstream name;
|
||||
name << "Vector(double) size " << s;
|
||||
|
||||
std::vector<double> data(s);
|
||||
if(randomize)
|
||||
if(randomize_)
|
||||
for( auto & d : data )
|
||||
d = rngD();
|
||||
|
||||
@@ -323,13 +366,13 @@ int main()
|
||||
vectorDoubleTest(1024*1024, randomize); // 8MB
|
||||
|
||||
//########################################
|
||||
auto vectorCharTest = [&](size_t s, bool randomize)
|
||||
auto vectorCharTest = [&](size_t s, bool randomize_)
|
||||
{
|
||||
std::ostringstream name;
|
||||
name << "Vector(uint8_t) size " << s;
|
||||
|
||||
std::vector<uint8_t> data(s);
|
||||
if(randomize)
|
||||
if(randomize_)
|
||||
for( auto & d : data )
|
||||
d = rngC();
|
||||
|
||||
@@ -344,8 +387,9 @@ int main()
|
||||
std::ostringstream name;
|
||||
name << "Vector(PoDStruct) size " << s;
|
||||
|
||||
std::vector<PoDStruct> data(s);
|
||||
test<binary>( name.str(), data );
|
||||
std::vector<PoDStructCereal> dataC(s);
|
||||
std::vector<PoDStructBoost> dataB(s);
|
||||
test<binary>( name.str(), dataC, dataB );
|
||||
};
|
||||
|
||||
vectorPoDStructTest(1);
|
||||
@@ -360,8 +404,9 @@ int main()
|
||||
std::ostringstream name;
|
||||
name << "Vector(PoDChild) size " << s;
|
||||
|
||||
std::vector<PoDChild> data(s);
|
||||
test<binary>( name.str(), data );
|
||||
std::vector<PoDChildCereal> dataC(s);
|
||||
std::vector<PoDChildBoost> dataB(s);
|
||||
test<binary>( name.str(), dataC, dataB );
|
||||
};
|
||||
|
||||
vectorPoDChildTest(1024);
|
||||
@@ -406,10 +451,14 @@ int main()
|
||||
std::ostringstream name;
|
||||
name << "Map(PoDStruct) size " <<s;
|
||||
|
||||
std::map<std::string, PoDStruct> m;
|
||||
std::map<std::string, PoDStructCereal> mC;
|
||||
std::map<std::string, PoDStructBoost> mB;
|
||||
for(size_t i=0; i<s; ++i)
|
||||
m[std::to_string(i)] = {};
|
||||
test<binary>(name.str(), m);
|
||||
{
|
||||
mC[std::to_string( i )] = PoDStructCereal();
|
||||
mB[std::to_string( i )] = PoDStructBoost();
|
||||
}
|
||||
test<binary>(name.str(), mC, mB);
|
||||
};
|
||||
|
||||
mapPoDStructTest(1024);
|
||||
@@ -417,3 +466,7 @@ int main()
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user