mirror of
https://github.com/fmtlib/fmt.git
synced 2025-12-31 11:18:15 +01:00
Compare commits
6276 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cf9f38ede | ||
|
|
4946bdb729 | ||
|
|
01a5b56f0d | ||
|
|
cb6fdf2191 | ||
|
|
f841ae61e2 | ||
|
|
a3d05d70ce | ||
|
|
41539c29f3 | ||
|
|
aabe63910c | ||
|
|
f90090be2c | ||
|
|
9ff9c695db | ||
|
|
06ad1224eb | ||
|
|
5f0572acdc | ||
|
|
898d438571 | ||
|
|
937b7c5c10 | ||
|
|
01914f0389 | ||
|
|
c43da35701 | ||
|
|
8303d140a1 | ||
|
|
b0b3dc5ff9 | ||
|
|
586ea06f02 | ||
|
|
5750f434fa | ||
|
|
bfbdc2be9a | ||
|
|
87e0072673 | ||
|
|
d57040f949 | ||
|
|
21aa0956d4 | ||
|
|
3f864a4505 | ||
|
|
093b39ca5e | ||
|
|
2c3a5698ef | ||
|
|
fc1b0f3486 | ||
|
|
1d066890c7 | ||
|
|
dad3237514 | ||
|
|
880e1494dc | ||
|
|
e3ddede6c4 | ||
|
|
e9ec4fdc88 | ||
|
|
feb72126b4 | ||
|
|
8d517e54c9 | ||
|
|
563fc74ae4 | ||
|
|
3e04222d53 | ||
|
|
853df39d0a | ||
|
|
11742a09c7 | ||
|
|
da24fac101 | ||
|
|
5fa4bdd758 | ||
|
|
3c8aad8df7 | ||
|
|
0e8aad961d | ||
|
|
debe784aab | ||
|
|
f6d1125676 | ||
|
|
73d0d3f75d | ||
|
|
08f60f1efc | ||
|
|
faf3f84085 | ||
|
|
f3a41441df | ||
|
|
3f33cb21d2 | ||
|
|
b07a90386e | ||
|
|
a6fba51773 | ||
|
|
25e2929988 | ||
|
|
00ab2e98b5 | ||
|
|
a3ef285aec | ||
|
|
28d1abc9d2 | ||
|
|
90704b9efd | ||
|
|
86dae01c23 | ||
|
|
d8a79eafdc | ||
|
|
7c3d0152e5 | ||
|
|
7c50da5385 | ||
|
|
873670ba3f | ||
|
|
735d4cc05e | ||
|
|
141380172f | ||
|
|
4302d74293 | ||
|
|
0f51ea79d3 | ||
|
|
9600fee020 | ||
|
|
47a66c5ecc | ||
|
|
385c01dc7b | ||
|
|
df249d8ad3 | ||
|
|
dfad80d1c5 | ||
|
|
536cabd562 | ||
|
|
b1a054706e | ||
|
|
bfd95392c7 | ||
|
|
9ced61bca4 | ||
|
|
75e5be6adc | ||
|
|
a169d7fa46 | ||
|
|
a6c45dfea8 | ||
|
|
a35389b3c2 | ||
|
|
5a3576acc8 | ||
|
|
542600013f | ||
|
|
720da57bab | ||
|
|
680db66c3a | ||
|
|
56ce41ef63 | ||
|
|
cf50e4d6a4 | ||
|
|
6580d7b808 | ||
|
|
7e73566ce7 | ||
|
|
8523dba2dc | ||
|
|
e3d3b24fc1 | ||
|
|
1521bba701 | ||
|
|
00649552a8 | ||
|
|
4b8e2838f0 | ||
|
|
7d4662f7ab | ||
|
|
27110bc474 | ||
|
|
68f3153762 | ||
|
|
168df9a064 | ||
|
|
4daa3d591f | ||
|
|
e9eaa27e5a | ||
|
|
2b6a786e35 | ||
|
|
a16ff5787b | ||
|
|
601be1cbe7 | ||
|
|
58c185b634 | ||
|
|
a0a9ba2afc | ||
|
|
cc2ba8f9ed | ||
|
|
a18d42b208 | ||
|
|
4046f97278 | ||
|
|
6bdc12a199 | ||
|
|
786a4b0968 | ||
|
|
2cb3b7c64b | ||
|
|
e9cba69057 | ||
|
|
02537548f3 | ||
|
|
c68c5fa7c7 | ||
|
|
22701d5f63 | ||
|
|
e62c41ffb0 | ||
|
|
18792893d8 | ||
|
|
c90bc91862 | ||
|
|
c95722ad62 | ||
|
|
db06b0df87 | ||
|
|
b9ec48d9ca | ||
|
|
3faf6f181e | ||
|
|
d64b100a30 | ||
|
|
ff9ee0461a | ||
|
|
1c5883bef0 | ||
|
|
cacc3108c5 | ||
|
|
fade652ade | ||
|
|
96dca569a1 | ||
|
|
891c9a73ae | ||
|
|
9282222b7d | ||
|
|
e5b20ff0d0 | ||
|
|
ff92223549 | ||
|
|
80c4d42c66 | ||
|
|
3b70966df5 | ||
|
|
05226c4bd9 | ||
|
|
c283b458a5 | ||
|
|
fe79932c26 | ||
|
|
23fcf1942a | ||
|
|
3f296e3d4a | ||
|
|
a197a994c5 | ||
|
|
6d43c755bc | ||
|
|
1f87b1c58d | ||
|
|
ed8f8be70d | ||
|
|
55a0a9cd62 | ||
|
|
5c926d9ff9 | ||
|
|
8b024662d4 | ||
|
|
2f1424be90 | ||
|
|
239aa6911b | ||
|
|
497df6db61 | ||
|
|
a25e594f6a | ||
|
|
503dff93ec | ||
|
|
3374a95b50 | ||
|
|
0e62e5dc7c | ||
|
|
7ce013971b | ||
|
|
07e70151d5 | ||
|
|
4197727712 | ||
|
|
527e98e3f8 | ||
|
|
8a19b2db77 | ||
|
|
e97df46ae1 | ||
|
|
39f1e0903a | ||
|
|
d832830f60 | ||
|
|
b329ff194f | ||
|
|
2af403ce64 | ||
|
|
b7513b1d00 | ||
|
|
761d35f763 | ||
|
|
545dc4148a | ||
|
|
3f5e45dd33 | ||
|
|
2e3b6fbd9f | ||
|
|
a0328e1f9f | ||
|
|
de28ef5f86 | ||
|
|
2d5e561a6b | ||
|
|
6537fb439c | ||
|
|
50aac2ac92 | ||
|
|
538d8777e5 | ||
|
|
0335312320 | ||
|
|
463fe65f17 | ||
|
|
1782a6eac0 | ||
|
|
b52fb98846 | ||
|
|
b6a6ec7f1c | ||
|
|
89999f1672 | ||
|
|
b90b4bc981 | ||
|
|
a1d6f9a973 | ||
|
|
689ec7a087 | ||
|
|
28143dc99d | ||
|
|
1bde49e545 | ||
|
|
f924d16e47 | ||
|
|
ab8f9d5b08 | ||
|
|
6f62db098a | ||
|
|
ab44ee7521 | ||
|
|
0d4e7e3fee | ||
|
|
8ee89546ff | ||
|
|
a5deb96bf5 | ||
|
|
61a241f03f | ||
|
|
ff82d8d2b5 | ||
|
|
0cc20f5639 | ||
|
|
2ba6785d8f | ||
|
|
5644e7507c | ||
|
|
5345cfe6b3 | ||
|
|
3e9fdb3a1f | ||
|
|
3ada4aed20 | ||
|
|
b37be85bf1 | ||
|
|
70643b2511 | ||
|
|
967e2d177d | ||
|
|
02c5d637c5 | ||
|
|
047bf75c24 | ||
|
|
2d3ba32e79 | ||
|
|
6c90b31fbd | ||
|
|
9408c2ae8c | ||
|
|
cc3ff1529d | ||
|
|
158893b384 | ||
|
|
f5a16a484b | ||
|
|
cad876be4c | ||
|
|
debf6f8285 | ||
|
|
35f4fab4c4 | ||
|
|
ff8f324786 | ||
|
|
bd48715d81 | ||
|
|
57d6df62f7 | ||
|
|
8ed4a9dcc1 | ||
|
|
f288f45e46 | ||
|
|
5bf577ca58 | ||
|
|
b6de66819e | ||
|
|
6870e4b06b | ||
|
|
5cdef76034 | ||
|
|
a2c290bc34 | ||
|
|
f1e3016c13 | ||
|
|
106dc8fd64 | ||
|
|
c3344e21e2 | ||
|
|
5f438c967e | ||
|
|
2a257798d4 | ||
|
|
22d50c1a9c | ||
|
|
1cc10ab68f | ||
|
|
6aaf7f4b79 | ||
|
|
b4d1d7f8e6 | ||
|
|
1e0771c70a | ||
|
|
3df47a4677 | ||
|
|
b4aea98b55 | ||
|
|
565461a0d3 | ||
|
|
e2b7238707 | ||
|
|
1e0c6cdc3b | ||
|
|
a8bcf81f72 | ||
|
|
15694c9a84 | ||
|
|
4cae2da0d0 | ||
|
|
79e5ae919c | ||
|
|
894b71da85 | ||
|
|
7a6a2a79ed | ||
|
|
387395fc7c | ||
|
|
6a88415499 | ||
|
|
9a2aae37d4 | ||
|
|
8803768363 | ||
|
|
4fa533c70e | ||
|
|
d980dd7171 | ||
|
|
4eed488c66 | ||
|
|
a6ecd25b80 | ||
|
|
9f29345ea0 | ||
|
|
4986b4c0ef | ||
|
|
a5f4d9820c | ||
|
|
bc3af51272 | ||
|
|
60740b7c24 | ||
|
|
9ef160d309 | ||
|
|
0b80978c27 | ||
|
|
4f39d88650 | ||
|
|
a86b1acf6a | ||
|
|
c9ef07bc4e | ||
|
|
8c4cfab57a | ||
|
|
7e3aa6d982 | ||
|
|
7c66216008 | ||
|
|
1416edabbb | ||
|
|
d4aeca9922 | ||
|
|
eee93ddffa | ||
|
|
b310a0d48b | ||
|
|
985c3399d1 | ||
|
|
4a55b0d5fd | ||
|
|
64a6c84592 | ||
|
|
66920feeee | ||
|
|
f4dad85c3a | ||
|
|
db4becabed | ||
|
|
fec2cc7af1 | ||
|
|
621e9c17c5 | ||
|
|
bca7040556 | ||
|
|
8c4b17fe64 | ||
|
|
516a2e2049 | ||
|
|
6797f0c39a | ||
|
|
db496b47c1 | ||
|
|
8eda3c8e90 | ||
|
|
53316903e6 | ||
|
|
8a484ad577 | ||
|
|
b446cc9e67 | ||
|
|
0204dd359d | ||
|
|
d8876b7787 | ||
|
|
c0fab5e2f7 | ||
|
|
64313e915c | ||
|
|
8e3da9da2c | ||
|
|
2a2f73f7c1 | ||
|
|
6dd9194abd | ||
|
|
a017bba062 | ||
|
|
5eb023cd56 | ||
|
|
f213d83306 | ||
|
|
b3ccc2d210 | ||
|
|
7477dda28d | ||
|
|
e582d377c2 | ||
|
|
cd8d01d8cd | ||
|
|
377cf203e3 | ||
|
|
5a0a37340c | ||
|
|
bbf8b3bd01 | ||
|
|
a3f3f2ec9a | ||
|
|
e3676ca309 | ||
|
|
0379bf3a5d | ||
|
|
c59ee969f3 | ||
|
|
1a79bbfa83 | ||
|
|
89af1ad77d | ||
|
|
0e741e0daa | ||
|
|
d1acc667c1 | ||
|
|
4fb7008c90 | ||
|
|
589898e28b | ||
|
|
62382e3650 | ||
|
|
94b8bc8eae | ||
|
|
020af729dd | ||
|
|
fb07b37c5b | ||
|
|
3135421257 | ||
|
|
993f56cff6 | ||
|
|
c6c830e203 | ||
|
|
b906c321f0 | ||
|
|
f8c0c8ee78 | ||
|
|
c71d03fcb0 | ||
|
|
50a8c3e9bf | ||
|
|
98314319ad | ||
|
|
0ce49aeb4a | ||
|
|
bf870ae3d1 | ||
|
|
c98518351e | ||
|
|
9f0c0c468b | ||
|
|
9f269062a7 | ||
|
|
15f939c3de | ||
|
|
928a07bb04 | ||
|
|
7891699737 | ||
|
|
58aba5a3de | ||
|
|
5ee14d3508 | ||
|
|
b9c0e4dd82 | ||
|
|
8445327c84 | ||
|
|
8a06cee826 | ||
|
|
1db2274966 | ||
|
|
34ead4b39e | ||
|
|
3bf26009e4 | ||
|
|
d326c7298a | ||
|
|
6e462b89aa | ||
|
|
aff640c32f | ||
|
|
e23fb6a8b4 | ||
|
|
16b3542f7e | ||
|
|
29d7e58059 | ||
|
|
919f7c5e7f | ||
|
|
a80d668a52 | ||
|
|
707d7d923a | ||
|
|
de6ed8df8b | ||
|
|
ffdc3fdbd9 | ||
|
|
0c02813791 | ||
|
|
f8581bcecf | ||
|
|
31b3c325f6 | ||
|
|
52b32081f9 | ||
|
|
0b0b09f401 | ||
|
|
4173a6315a | ||
|
|
4239dfe081 | ||
|
|
ba36a04811 | ||
|
|
f6b4a23b83 | ||
|
|
42d3d703b5 | ||
|
|
9fcd9c4c12 | ||
|
|
7f157dca0a | ||
|
|
524ca1c715 | ||
|
|
bdc45eef76 | ||
|
|
439b6d7212 | ||
|
|
3cc32fdc8b | ||
|
|
0c9fce2ffe | ||
|
|
b47d662e71 | ||
|
|
e84297f255 | ||
|
|
0ad234ad13 | ||
|
|
de684ef776 | ||
|
|
447c6cbf44 | ||
|
|
bc8d32e964 | ||
|
|
0f87d6ffa6 | ||
|
|
808ea0191a | ||
|
|
55e76e6c20 | ||
|
|
8757f1f8d6 | ||
|
|
9228f349a5 | ||
|
|
e10643add2 | ||
|
|
f29a7e7970 | ||
|
|
f97deb0d7d | ||
|
|
3541353512 | ||
|
|
5ef93a9f80 | ||
|
|
c9102619da | ||
|
|
58d792b6d3 | ||
|
|
25adca5666 | ||
|
|
1408f1824d | ||
|
|
3fe4641d3a | ||
|
|
33e7ed1eb5 | ||
|
|
6a192f8d34 | ||
|
|
92cdbbae06 | ||
|
|
13038f37e8 | ||
|
|
6725225750 | ||
|
|
e60ff504ea | ||
|
|
ccea338070 | ||
|
|
92227c77a4 | ||
|
|
486838f26f | ||
|
|
a43391199f | ||
|
|
7a8b54a0ef | ||
|
|
b50e685db9 | ||
|
|
e314776c2e | ||
|
|
2208143acc | ||
|
|
a96259701e | ||
|
|
232c6bc481 | ||
|
|
503e183b9e | ||
|
|
e50c8b6bd8 | ||
|
|
9d946a2fc4 | ||
|
|
c4f6fa7135 | ||
|
|
10f12fd3d2 | ||
|
|
24c1f886af | ||
|
|
0041a40c13 | ||
|
|
686339f7c1 | ||
|
|
e355c116f9 | ||
|
|
707bb5b369 | ||
|
|
6f68c62cb5 | ||
|
|
d059fe42a8 | ||
|
|
43c5b34749 | ||
|
|
e89568e6cb | ||
|
|
f5bf6f7781 | ||
|
|
bd9af9a9f1 | ||
|
|
1652108905 | ||
|
|
84f6131825 | ||
|
|
dedc17c1c9 | ||
|
|
5d0adb6d74 | ||
|
|
3f251fc9c9 | ||
|
|
1930ed4bfa | ||
|
|
26d07e49b2 | ||
|
|
949d5d1795 | ||
|
|
53186535d5 | ||
|
|
602e3c3d11 | ||
|
|
2952130cbc | ||
|
|
1e94a463ed | ||
|
|
a34120329a | ||
|
|
0fae326c42 | ||
|
|
8b1fcf5cc1 | ||
|
|
ec46c3de97 | ||
|
|
2d9d32c62b | ||
|
|
4703ade76d | ||
|
|
52e7b25f95 | ||
|
|
b61c8c3d23 | ||
|
|
bbf44cc000 | ||
|
|
06948fa710 | ||
|
|
d9899492c1 | ||
|
|
ff72f553e3 | ||
|
|
7f951f2502 | ||
|
|
7ae102bd66 | ||
|
|
edde973126 | ||
|
|
b1efe8516e | ||
|
|
2c0d9e9409 | ||
|
|
18a9676d95 | ||
|
|
af8cd4e404 | ||
|
|
514b6955d2 | ||
|
|
ac96773230 | ||
|
|
c00149f5e2 | ||
|
|
71244e07de | ||
|
|
a57b0194a6 | ||
|
|
febd8ed5fe | ||
|
|
0434026a95 | ||
|
|
0882bfef2a | ||
|
|
2a2048a785 | ||
|
|
ea1187f4c8 | ||
|
|
1334eedaf5 | ||
|
|
709169a4d8 | ||
|
|
2bf1b3004e | ||
|
|
8687315e86 | ||
|
|
98dd673cf8 | ||
|
|
a245a8d4b9 | ||
|
|
e0b66e8f83 | ||
|
|
794df69c8c | ||
|
|
1d9df9ce1c | ||
|
|
c4ea903250 | ||
|
|
3e3062c13b | ||
|
|
b998b47116 | ||
|
|
bff1de15e7 | ||
|
|
90932dd20d | ||
|
|
232c5e8547 | ||
|
|
26cdd1cb30 | ||
|
|
ad34d4df95 | ||
|
|
f796264449 | ||
|
|
28673d9699 | ||
|
|
a5c1b5d440 | ||
|
|
cc4d1245b8 | ||
|
|
18a325f370 | ||
|
|
a1337aa8aa | ||
|
|
51a690ab15 | ||
|
|
f332a81b72 | ||
|
|
33a1de57af | ||
|
|
c7252b3344 | ||
|
|
3f71b60668 | ||
|
|
215ce4d979 | ||
|
|
89f3a810ec | ||
|
|
1f170d3fe0 | ||
|
|
d175db8f5b | ||
|
|
a8cfc0cc2c | ||
|
|
65e278b286 | ||
|
|
3620c174a6 | ||
|
|
702b6f3788 | ||
|
|
ed21034a10 | ||
|
|
76d57f93db | ||
|
|
6ceef04dfe | ||
|
|
ab6b257a39 | ||
|
|
077e4ae746 | ||
|
|
d4a8d26c55 | ||
|
|
b5c8fd783c | ||
|
|
735a613821 | ||
|
|
a6e6e9c3c9 | ||
|
|
e6d4f927cc | ||
|
|
8de3e87da1 | ||
|
|
46d2acb3ba | ||
|
|
fad0222a0c | ||
|
|
d1cab6a9ae | ||
|
|
fcb6a452d6 | ||
|
|
72928661ed | ||
|
|
d6ec6b7e27 | ||
|
|
e845fc572e | ||
|
|
2bf811b1d9 | ||
|
|
9653eed8e7 | ||
|
|
9b5d1826d4 | ||
|
|
fe741daaab | ||
|
|
0f6e716548 | ||
|
|
a3d95971be | ||
|
|
7bd11b5cdf | ||
|
|
21372bc0b2 | ||
|
|
a0495e3eb5 | ||
|
|
cba5e8615a | ||
|
|
e9609dec1a | ||
|
|
6ebbaf4b4d | ||
|
|
4e31d2dc61 | ||
|
|
fcc0b49978 | ||
|
|
0560c334fb | ||
|
|
db9365a11b | ||
|
|
5c445bc42c | ||
|
|
94f96d112d | ||
|
|
6abc1204f3 | ||
|
|
a9b8517638 | ||
|
|
fba06f0ee1 | ||
|
|
598e518085 | ||
|
|
0a555818d7 | ||
|
|
966a1b3d44 | ||
|
|
adb8e27db0 | ||
|
|
2c84fa9ac9 | ||
|
|
8da0240dbc | ||
|
|
83bf142378 | ||
|
|
595e54919b | ||
|
|
c636967c5c | ||
|
|
2392367efc | ||
|
|
06f8e02fb3 | ||
|
|
c71d08fc22 | ||
|
|
d9b90029bf | ||
|
|
c0029b9847 | ||
|
|
1ac9b317f2 | ||
|
|
f68dee5351 | ||
|
|
fb9ee2ed65 | ||
|
|
d29ceaf915 | ||
|
|
9b12491c19 | ||
|
|
ab29ef37d9 | ||
|
|
97117cbb51 | ||
|
|
886237ae7b | ||
|
|
904f2a5c20 | ||
|
|
dab1a65d2c | ||
|
|
509d018101 | ||
|
|
75ab3bc2a0 | ||
|
|
871538d3ab | ||
|
|
250456d5a3 | ||
|
|
38ba3d3993 | ||
|
|
0714113974 | ||
|
|
dd3b3f937b | ||
|
|
03d14c3beb | ||
|
|
416ac0fc7b | ||
|
|
596add8993 | ||
|
|
a10e032148 | ||
|
|
febeb51bde | ||
|
|
f18c2b65c4 | ||
|
|
e3910b8a9c | ||
|
|
34b85678f9 | ||
|
|
e5c07c8356 | ||
|
|
933d8ba352 | ||
|
|
e7ba467e9b | ||
|
|
91a859ee4a | ||
|
|
6180442ed8 | ||
|
|
418c5d0949 | ||
|
|
aafdde7ef8 | ||
|
|
d2ecfcfc45 | ||
|
|
26b249435e | ||
|
|
4f330567e1 | ||
|
|
1992746249 | ||
|
|
a4d42c44f4 | ||
|
|
ddd8a54230 | ||
|
|
fcd3e1e19c | ||
|
|
dc401b1c28 | ||
|
|
f7c5588c46 | ||
|
|
a4e40677af | ||
|
|
3479828e1d | ||
|
|
191b0cb486 | ||
|
|
e80f4a9b72 | ||
|
|
022d8efec9 | ||
|
|
ca8eeb09ee | ||
|
|
cddb41f633 | ||
|
|
0b0a05770f | ||
|
|
caa97da1f5 | ||
|
|
cf9833f40b | ||
|
|
b6638f9c29 | ||
|
|
d903460137 | ||
|
|
ba2fbf6e1f | ||
|
|
6e49bb887a | ||
|
|
e0f3e85076 | ||
|
|
4fc3fce9cb | ||
|
|
d6427ae7b2 | ||
|
|
3d6869065b | ||
|
|
551aa8d510 | ||
|
|
9e07045f50 | ||
|
|
5735048b2d | ||
|
|
33eba1049d | ||
|
|
43ab964c47 | ||
|
|
728f9bc388 | ||
|
|
e721046e27 | ||
|
|
552842c4ff | ||
|
|
2c38766fd5 | ||
|
|
c8f1b4e744 | ||
|
|
529dcd11fe | ||
|
|
1441c660bf | ||
|
|
ecd1559732 | ||
|
|
a57a63dc0f | ||
|
|
8691f21b45 | ||
|
|
7e4fac3f4f | ||
|
|
4a368625e8 | ||
|
|
f4e1ec81e2 | ||
|
|
89c0d10105 | ||
|
|
12ef9e09d1 | ||
|
|
5afa681388 | ||
|
|
cc13102031 | ||
|
|
8ee6c94014 | ||
|
|
766300b3c6 | ||
|
|
4115219ede | ||
|
|
95076981f7 | ||
|
|
1752d7fbbb | ||
|
|
1768bf9714 | ||
|
|
fc723fd6c7 | ||
|
|
b81761068b | ||
|
|
706eabd5e5 | ||
|
|
028bffa083 | ||
|
|
86741b3e1c | ||
|
|
75e892420e | ||
|
|
0b5287f8b7 | ||
|
|
a4715c48b4 | ||
|
|
8e728044f6 | ||
|
|
1f436c646e | ||
|
|
db1ee420e0 | ||
|
|
7d6ae972b9 | ||
|
|
3460b30fd5 | ||
|
|
b7809f91e2 | ||
|
|
1dc71f21ea | ||
|
|
8db8f22490 | ||
|
|
d2473b7b73 | ||
|
|
328d256c60 | ||
|
|
57593a123b | ||
|
|
10508a30ec | ||
|
|
16cec4f591 | ||
|
|
77bfd8499a | ||
|
|
3af8ac7a06 | ||
|
|
ceb406d06c | ||
|
|
19afc9c3bb | ||
|
|
6ff593b027 | ||
|
|
78420beddd | ||
|
|
a21bc7b869 | ||
|
|
97d0613ba9 | ||
|
|
04b0ae418b | ||
|
|
27dd1dcf08 | ||
|
|
3649c3954f | ||
|
|
7650ed04a3 | ||
|
|
9234fe83f9 | ||
|
|
8a8f4825a3 | ||
|
|
17062a0c9b | ||
|
|
88d3997f5e | ||
|
|
48c908453d | ||
|
|
cf1f55f798 | ||
|
|
400f6a8ee2 | ||
|
|
a3e0931ea2 | ||
|
|
51eeccd0fb | ||
|
|
f30f1fd514 | ||
|
|
f4b256c667 | ||
|
|
f746a59a5c | ||
|
|
ee0c3351a4 | ||
|
|
99735764ea | ||
|
|
aa52eb765d | ||
|
|
116a9ce488 | ||
|
|
5eb68c0ef2 | ||
|
|
550437b29e | ||
|
|
4e8640ed90 | ||
|
|
c70e7b7473 | ||
|
|
71144eeaff | ||
|
|
843e293564 | ||
|
|
f5ec5ada2b | ||
|
|
3b5f3de3b5 | ||
|
|
ca9193983b | ||
|
|
74a187288b | ||
|
|
88620e53a4 | ||
|
|
5d63e87d23 | ||
|
|
aecec01b34 | ||
|
|
5af88653eb | ||
|
|
45b772f85c | ||
|
|
53347891cf | ||
|
|
38881e5acf | ||
|
|
6c7cc6a06f | ||
|
|
365c3fbd25 | ||
|
|
c0dac83982 | ||
|
|
bb882c03bc | ||
|
|
12acd7988b | ||
|
|
c710bfa10c | ||
|
|
73f2b344b2 | ||
|
|
9f3fc6e38b | ||
|
|
c17816cb4a | ||
|
|
df6e7b22f7 | ||
|
|
c816fa6751 | ||
|
|
e281749c5d | ||
|
|
11f2f30f0b | ||
|
|
13cfaa2ab0 | ||
|
|
0861db500f | ||
|
|
dfe5b12c08 | ||
|
|
09935d8239 | ||
|
|
3bc6cc1e63 | ||
|
|
4fcc317dc9 | ||
|
|
ae1e93d34d | ||
|
|
f68f452dea | ||
|
|
ebea5736a2 | ||
|
|
ddf0b7d2b5 | ||
|
|
0166f455f6 | ||
|
|
8e42eef495 | ||
|
|
91b30e5b4e | ||
|
|
7a63e233d2 | ||
|
|
44c3fe1ebb | ||
|
|
ae181cc93d | ||
|
|
3a6fb2fcaf | ||
|
|
0879504796 | ||
|
|
34f415b56e | ||
|
|
e17bc67547 | ||
|
|
06311ed1ce | ||
|
|
e5bab8dab4 | ||
|
|
9f5f39cb50 | ||
|
|
ea581437e5 | ||
|
|
6321a97d6b | ||
|
|
4b6b32f388 | ||
|
|
1b54ba4b9d | ||
|
|
71a4a8d479 | ||
|
|
8e62172ab6 | ||
|
|
28afff363c | ||
|
|
af44c29744 | ||
|
|
a1e1eedbb5 | ||
|
|
ffce3632b7 | ||
|
|
b5669512b1 | ||
|
|
6435b169ec | ||
|
|
6f260455aa | ||
|
|
e1832bcf00 | ||
|
|
2caf1b3b91 | ||
|
|
668fe2653c | ||
|
|
06fc25f266 | ||
|
|
11ba1270ab | ||
|
|
4c5b4af04d | ||
|
|
2eb363297b | ||
|
|
0147e08225 | ||
|
|
6b68dff901 | ||
|
|
b2cde48de5 | ||
|
|
8510838db1 | ||
|
|
090ee13595 | ||
|
|
470c4e6ca8 | ||
|
|
13ec66bf78 | ||
|
|
64091b7a25 | ||
|
|
e954823531 | ||
|
|
f80a2bee1c | ||
|
|
83652dfee7 | ||
|
|
d249fd9f84 | ||
|
|
73d91351b4 | ||
|
|
fe0d910a7d | ||
|
|
f9294f0e60 | ||
|
|
c98a5a599f | ||
|
|
5f30d37102 | ||
|
|
3647feaad5 | ||
|
|
e420a58f24 | ||
|
|
ca37503f93 | ||
|
|
123e058eb3 | ||
|
|
f924d20dbd | ||
|
|
d70729215f | ||
|
|
362b40c1a3 | ||
|
|
56fa4d61f6 | ||
|
|
cacdf1439f | ||
|
|
4d766b1670 | ||
|
|
c10859f15c | ||
|
|
d0963d4823 | ||
|
|
da0f84c42c | ||
|
|
59baac522e | ||
|
|
21b0458291 | ||
|
|
df6a3564b0 | ||
|
|
7c163acfda | ||
|
|
1b55d10305 | ||
|
|
5d9d376d49 | ||
|
|
6064b85c10 | ||
|
|
deb584c0e1 | ||
|
|
297b22f585 | ||
|
|
3c9608416a | ||
|
|
0cdee904a4 | ||
|
|
7e58af4eaf | ||
|
|
f1924d3269 | ||
|
|
52174953bc | ||
|
|
b71d98774b | ||
|
|
810d1750f1 | ||
|
|
170ffb1ff8 | ||
|
|
e470ba8b7b | ||
|
|
bf98e3e4c6 | ||
|
|
fd87a23d34 | ||
|
|
b71ef65b6e | ||
|
|
c5340539f9 | ||
|
|
971f7ae768 | ||
|
|
6159e2b0ab | ||
|
|
da7a232b9e | ||
|
|
2595bf57b3 | ||
|
|
6f5d53ce08 | ||
|
|
961df829b9 | ||
|
|
401f087394 | ||
|
|
725992928b | ||
|
|
3d84b45a22 | ||
|
|
4331abed26 | ||
|
|
fc8f6ba934 | ||
|
|
58a6bd48a8 | ||
|
|
79f1506fe3 | ||
|
|
4d616479b5 | ||
|
|
cf8426cf8c | ||
|
|
e915d52162 | ||
|
|
7ba6420540 | ||
|
|
97867e279a | ||
|
|
8875cf96c2 | ||
|
|
f7ed65fa4a | ||
|
|
f34f31b321 | ||
|
|
fb66131efa | ||
|
|
6af30d8f75 | ||
|
|
c177324ba9 | ||
|
|
545d37a8b0 | ||
|
|
9f73e45ca0 | ||
|
|
a5ae9ae19d | ||
|
|
23e8109d8d | ||
|
|
679af1f5cc | ||
|
|
48d7fb265b | ||
|
|
f348d1a211 | ||
|
|
df67df7b4c | ||
|
|
17f79ac6cf | ||
|
|
dbdfc99fa1 | ||
|
|
c1d9e88402 | ||
|
|
7d73ef85f7 | ||
|
|
ae9b0b521b | ||
|
|
f73388f1ad | ||
|
|
08878044c6 | ||
|
|
1b7d9db0ce | ||
|
|
0641b844ac | ||
|
|
1e938dda20 | ||
|
|
2e5b14bf60 | ||
|
|
e0b604beb1 | ||
|
|
6c617c9670 | ||
|
|
bee495c97f | ||
|
|
794e1b6145 | ||
|
|
c7061776ab | ||
|
|
dc52d176de | ||
|
|
0e3e61cc0a | ||
|
|
800a0bb23f | ||
|
|
f2e43f967c | ||
|
|
c9287eb9f7 | ||
|
|
61f144bd61 | ||
|
|
4687f8e37e | ||
|
|
f2c55f6bb8 | ||
|
|
c9d233c0a4 | ||
|
|
242bcaec04 | ||
|
|
4e43a46993 | ||
|
|
c36ed77ff0 | ||
|
|
e2ab9ab22b | ||
|
|
0378d171f9 | ||
|
|
baea8f6906 | ||
|
|
eedfdb4c5c | ||
|
|
5dbd7fd770 | ||
|
|
7fd1802686 | ||
|
|
63ce170853 | ||
|
|
74ffea0dcf | ||
|
|
6c3b2d491e | ||
|
|
4ec9c2906b | ||
|
|
f4a7d40dca | ||
|
|
9659f22d36 | ||
|
|
068bf9bad8 | ||
|
|
50565f9853 | ||
|
|
0b39d67103 | ||
|
|
c142385033 | ||
|
|
398ddb8fec | ||
|
|
583729493c | ||
|
|
6c5bcca819 | ||
|
|
67c0c0c09c | ||
|
|
051b31531c | ||
|
|
b0569451a7 | ||
|
|
ce3161887a | ||
|
|
1a95e5d1b4 | ||
|
|
e1aac42663 | ||
|
|
1705600be3 | ||
|
|
0c345dccd2 | ||
|
|
d33731d202 | ||
|
|
c068c7c622 | ||
|
|
13fa26745d | ||
|
|
ebd5c8f994 | ||
|
|
f5ca178c12 | ||
|
|
138a64bfb1 | ||
|
|
a5bacf3fef | ||
|
|
4aa24f54cd | ||
|
|
e33c1568c3 | ||
|
|
23826669cf | ||
|
|
8e6b2541a6 | ||
|
|
4939d67a83 | ||
|
|
bd3273021b | ||
|
|
5f9058dbd4 | ||
|
|
28576b0600 | ||
|
|
5ddd0cad15 | ||
|
|
41d31512b7 | ||
|
|
44b76d88f4 | ||
|
|
3324152db4 | ||
|
|
55190dadb5 | ||
|
|
63e4b93cfc | ||
|
|
c64edcd325 | ||
|
|
8c520b4fdc | ||
|
|
2e6bb706bf | ||
|
|
a13d1b12e5 | ||
|
|
47a0eec2e8 | ||
|
|
a8bed38952 | ||
|
|
e206043d2b | ||
|
|
4a6f0be5b6 | ||
|
|
662d784157 | ||
|
|
d5823aae36 | ||
|
|
d83c1b8d4a | ||
|
|
bfba2f9e92 | ||
|
|
a3bf40838f | ||
|
|
ea1066bbe3 | ||
|
|
be57ec7ec0 | ||
|
|
305747d440 | ||
|
|
47c8f63d02 | ||
|
|
76e8f10403 | ||
|
|
18ca2248df | ||
|
|
3a25a58482 | ||
|
|
4cbf6182ea | ||
|
|
88d19f5de9 | ||
|
|
62529aad19 | ||
|
|
df62c86783 | ||
|
|
eef6dbafbf | ||
|
|
41c2433358 | ||
|
|
0a9d08fefd | ||
|
|
e450b7aeb3 | ||
|
|
c5a85f8d7d | ||
|
|
1fd093add4 | ||
|
|
c4f2de4933 | ||
|
|
d06921d8d8 | ||
|
|
fc0f84d290 | ||
|
|
86f2ec5de7 | ||
|
|
a537c39fdf | ||
|
|
7c240d52c3 | ||
|
|
f64a6a2ecd | ||
|
|
6f9a816786 | ||
|
|
e7875ae0fa | ||
|
|
3eb3aef575 | ||
|
|
56d7a8c157 | ||
|
|
968fb9d166 | ||
|
|
b5f6b36b00 | ||
|
|
44dd6c0e09 | ||
|
|
3a0f4af4e9 | ||
|
|
1ca1a4a7a9 | ||
|
|
dbd9c89b3c | ||
|
|
9cd2b87e18 | ||
|
|
d5da9cc40e | ||
|
|
3a2c50d4ac | ||
|
|
18c43a214c | ||
|
|
6b07fff0d9 | ||
|
|
9165434e5a | ||
|
|
b8f81dede5 | ||
|
|
923005bd4f | ||
|
|
afa85e46c3 | ||
|
|
6025bd7c37 | ||
|
|
5471a2426c | ||
|
|
7d757cba5d | ||
|
|
6855bd532b | ||
|
|
bbee753579 | ||
|
|
89860eb901 | ||
|
|
274ba2645b | ||
|
|
9048add999 | ||
|
|
640e0c02d4 | ||
|
|
6392dba21c | ||
|
|
9a6fd11a56 | ||
|
|
dee0dbf07f | ||
|
|
2fabb43b93 | ||
|
|
9c3c107c8c | ||
|
|
4497a2d09a | ||
|
|
81629e425c | ||
|
|
6f95000b7a | ||
|
|
573d74395b | ||
|
|
5d55375a8a | ||
|
|
71bd51e6c2 | ||
|
|
f575089243 | ||
|
|
99b9fbf8ef | ||
|
|
8f83ee2ad1 | ||
|
|
2a8a694466 | ||
|
|
04718008ab | ||
|
|
b87ea22e29 | ||
|
|
5cfd28d476 | ||
|
|
73fae91e64 | ||
|
|
6988be3878 | ||
|
|
2d1e4bb35e | ||
|
|
7f8d419115 | ||
|
|
ccc9ab7bf9 | ||
|
|
c4283ec471 | ||
|
|
c3f9a73445 | ||
|
|
06f1c0d725 | ||
|
|
ffa5b14fe3 | ||
|
|
bea7ecc710 | ||
|
|
8a39388516 | ||
|
|
dd6f657a79 | ||
|
|
c13753a70c | ||
|
|
864a8b5f38 | ||
|
|
649fe0fc8b | ||
|
|
45e124ee43 | ||
|
|
045b05d79e | ||
|
|
ec628561c2 | ||
|
|
cbb18c237a | ||
|
|
6b0082e6c7 | ||
|
|
52a99a67f7 | ||
|
|
4548d1eae2 | ||
|
|
050d41e857 | ||
|
|
1c023c0087 | ||
|
|
b35d4e40fe | ||
|
|
acaf83f40f | ||
|
|
05aa783779 | ||
|
|
05dda9490d | ||
|
|
caf4fcb207 | ||
|
|
e0d3e346d2 | ||
|
|
19276d7325 | ||
|
|
2a2c6e676f | ||
|
|
3b7f58a8b3 | ||
|
|
e9bbd4069e | ||
|
|
857cce7a83 | ||
|
|
081d5b0d8b | ||
|
|
baae1ed658 | ||
|
|
2ac6c5ca8b | ||
|
|
d9063baf22 | ||
|
|
f7542c5761 | ||
|
|
130cf54cbc | ||
|
|
8e0ca0589f | ||
|
|
bf497ac068 | ||
|
|
bb8d50f04b | ||
|
|
f76603f21e | ||
|
|
f918289363 | ||
|
|
72e883e163 | ||
|
|
b3bf23f3c4 | ||
|
|
349e1c48d1 | ||
|
|
79dbd3f192 | ||
|
|
2dd4fa8742 | ||
|
|
44f3d8a77c | ||
|
|
06b20387ae | ||
|
|
649f2460db | ||
|
|
7529af8f99 | ||
|
|
a3a74fa7f3 | ||
|
|
8ef4db4b96 | ||
|
|
492a99c964 | ||
|
|
3baaa8d899 | ||
|
|
0e01e46c11 | ||
|
|
f6ca4ea199 | ||
|
|
a8a73da7e4 | ||
|
|
aa3c5a4127 | ||
|
|
bfdf50d183 | ||
|
|
571a9b7b26 | ||
|
|
6c088be8ec | ||
|
|
016b1faede | ||
|
|
e25370093a | ||
|
|
d4987546a4 | ||
|
|
5bdce181f1 | ||
|
|
a4b7b24b7b | ||
|
|
fac60bd4f5 | ||
|
|
f5be4a8a9a | ||
|
|
84e6661517 | ||
|
|
ac3240439c | ||
|
|
8894ae87fe | ||
|
|
ca608547e5 | ||
|
|
23cf4055a0 | ||
|
|
46c8301ee9 | ||
|
|
a79a979828 | ||
|
|
457bb6a98f | ||
|
|
61aef41110 | ||
|
|
2a45fd30fe | ||
|
|
24296cff1c | ||
|
|
3d1d20a6ac | ||
|
|
0302c527c6 | ||
|
|
154eccfeb1 | ||
|
|
35dc5def30 | ||
|
|
e1fc481d65 | ||
|
|
e8259c5298 | ||
|
|
6379251554 | ||
|
|
951fd9e66f | ||
|
|
be89b9a41e | ||
|
|
28e2d3b640 | ||
|
|
f5e54359df | ||
|
|
a003ab93cf | ||
|
|
9b74160817 | ||
|
|
a21690bdfa | ||
|
|
c9efd8968c | ||
|
|
e786824053 | ||
|
|
2b20d7be6f | ||
|
|
1f38ebbdb1 | ||
|
|
e418179694 | ||
|
|
0bffed8957 | ||
|
|
cc077a5e3b | ||
|
|
a992b3d1fc | ||
|
|
af1b768cc7 | ||
|
|
2a7c45b54e | ||
|
|
bd868f3a51 | ||
|
|
bbb784fb1b | ||
|
|
6c845f57e5 | ||
|
|
a379595c5f | ||
|
|
9dfde78714 | ||
|
|
e92a705bdc | ||
|
|
5a866fe852 | ||
|
|
e150ea0cc2 | ||
|
|
29ce2ff8a8 | ||
|
|
2e1362addb | ||
|
|
e57ca2e368 | ||
|
|
4c56612c67 | ||
|
|
e1acd5f4d9 | ||
|
|
6ffee2f752 | ||
|
|
ee475d6409 | ||
|
|
ecc9141259 | ||
|
|
d424862319 | ||
|
|
3c1b3337de | ||
|
|
35fb69ebe0 | ||
|
|
f92be35c09 | ||
|
|
7a2f6ac210 | ||
|
|
744ff55549 | ||
|
|
70ae48b005 | ||
|
|
ebb10347c4 | ||
|
|
1005720169 | ||
|
|
aeb6ad4dd0 | ||
|
|
96d1fa22d4 | ||
|
|
8a4bec5cf5 | ||
|
|
eacd51c249 | ||
|
|
757564f5cd | ||
|
|
f4214ae8dd | ||
|
|
aecf80d304 | ||
|
|
503d49286d | ||
|
|
4f46cb82f3 | ||
|
|
3dec65b7fd | ||
|
|
dbabb305c3 | ||
|
|
ac0ab8eff3 | ||
|
|
40f35d6f04 | ||
|
|
31c2c5679e | ||
|
|
b2728a3170 | ||
|
|
77e0b0e228 | ||
|
|
e475859042 | ||
|
|
436c131d4c | ||
|
|
388bc296b7 | ||
|
|
95e1ea5737 | ||
|
|
fb97cb2318 | ||
|
|
dd5a9691f9 | ||
|
|
72dc4491ea | ||
|
|
9bea6ec04a | ||
|
|
661b23edeb | ||
|
|
8e87d3a8be | ||
|
|
a474916560 | ||
|
|
de4705f84d | ||
|
|
e4c8cfe38e | ||
|
|
606f85f8b2 | ||
|
|
a331dbfb65 | ||
|
|
13156e54bf | ||
|
|
9158bea1e1 | ||
|
|
dd17f89a16 | ||
|
|
1daae555b3 | ||
|
|
6ad301235f | ||
|
|
8732ad8773 | ||
|
|
5afb1821a9 | ||
|
|
a81135f2c8 | ||
|
|
dfc34821ad | ||
|
|
0765e7284c | ||
|
|
977d887a4e | ||
|
|
c86fe0b8d3 | ||
|
|
5dbe0ff954 | ||
|
|
de0757b578 | ||
|
|
8fe893c0ac | ||
|
|
0f823df46a | ||
|
|
60fd9941c0 | ||
|
|
8abfc145be | ||
|
|
686b3353aa | ||
|
|
b2106f3639 | ||
|
|
35547d6003 | ||
|
|
179c7e5a66 | ||
|
|
61fb3a15ff | ||
|
|
bd393456ed | ||
|
|
6be36af0d4 | ||
|
|
2a35eeed8a | ||
|
|
256a826d63 | ||
|
|
6369af37d3 | ||
|
|
0b8404918e | ||
|
|
171a020c82 | ||
|
|
d8f04e3995 | ||
|
|
5e988f8dfa | ||
|
|
19b17618a9 | ||
|
|
c684a06d51 | ||
|
|
abdb7fdf88 | ||
|
|
8b09fe2a0a | ||
|
|
adad18a74d | ||
|
|
858e528abd | ||
|
|
a54cb108d4 | ||
|
|
ef55d4f52e | ||
|
|
70b6a6fa44 | ||
|
|
6fe895410d | ||
|
|
d0652d225f | ||
|
|
de8d0171a2 | ||
|
|
7401fe046a | ||
|
|
08ef0d0842 | ||
|
|
d60b907f87 | ||
|
|
4ce086f731 | ||
|
|
821f8cdb45 | ||
|
|
0bf6ed7e1d | ||
|
|
e40e04face | ||
|
|
0a1c27281a | ||
|
|
2f605cc896 | ||
|
|
1d54499ac0 | ||
|
|
3c6053c535 | ||
|
|
4a392adaa7 | ||
|
|
b14913fae5 | ||
|
|
2117df299c | ||
|
|
616a493786 | ||
|
|
9a034b0d55 | ||
|
|
e0fc0e85e3 | ||
|
|
552c43aba9 | ||
|
|
d6846f4ac8 | ||
|
|
aeedac5884 | ||
|
|
eaa6307691 | ||
|
|
e82bf41a1a | ||
|
|
e077396f5a | ||
|
|
861facad0a | ||
|
|
75bfe57614 | ||
|
|
697e76ba30 | ||
|
|
a425e0ff3b | ||
|
|
c36dd825ba | ||
|
|
130b8fcdb9 | ||
|
|
a47e8419be | ||
|
|
ea49c91cd1 | ||
|
|
d7592ad8bf | ||
|
|
ebfb2e6779 | ||
|
|
5780269d57 | ||
|
|
b471192160 | ||
|
|
8f18e72df5 | ||
|
|
93d7cb12f1 | ||
|
|
0e4278717b | ||
|
|
93a30a0746 | ||
|
|
a08196b149 | ||
|
|
0398ba42ca | ||
|
|
a0b8a92e3d | ||
|
|
5cf2342aa2 | ||
|
|
fe9d39d7cb | ||
|
|
4c98561979 | ||
|
|
403b271ed7 | ||
|
|
2c991e1af6 | ||
|
|
c984df9815 | ||
|
|
fbf21ed224 | ||
|
|
575583144e | ||
|
|
e7f6888c7a | ||
|
|
39db2dfd06 | ||
|
|
9b7829e264 | ||
|
|
1e0ce567ef | ||
|
|
dde8cf3bb7 | ||
|
|
e84b00e014 | ||
|
|
b12ffea4fb | ||
|
|
f61f15cc5b | ||
|
|
192df93d7b | ||
|
|
d8973bf16b | ||
|
|
d7a8e50cb5 | ||
|
|
02cae7e48a | ||
|
|
53162142b2 | ||
|
|
5bcf0d7f97 | ||
|
|
f8c9fabd94 | ||
|
|
62ff4e1dbd | ||
|
|
f449ca0525 | ||
|
|
eafcd3c8e1 | ||
|
|
18154cc903 | ||
|
|
0de789cf29 | ||
|
|
c039389223 | ||
|
|
93e81bb5d8 | ||
|
|
e7d6eb6794 | ||
|
|
18e7a2532b | ||
|
|
0489c19dcb | ||
|
|
8ec94ac6a5 | ||
|
|
d97d8cea67 | ||
|
|
d8a2698e6c | ||
|
|
d9c19940a3 | ||
|
|
4b5ae0b0ef | ||
|
|
75f3b1c094 | ||
|
|
faf83406a9 | ||
|
|
165814d57a | ||
|
|
33f7150778 | ||
|
|
c98e5a08a4 | ||
|
|
119c6bd16f | ||
|
|
77eeb71830 | ||
|
|
13bf99f9db | ||
|
|
1d0257e4c0 | ||
|
|
4613d48fd3 | ||
|
|
4a4a2a2bd6 | ||
|
|
fce74caa15 | ||
|
|
02bf4d1c1c | ||
|
|
466e0650ec | ||
|
|
029caa8ea2 | ||
|
|
e406ddbfaf | ||
|
|
9095679536 | ||
|
|
7f46cb75b8 | ||
|
|
4e3f381058 | ||
|
|
d3c10f5167 | ||
|
|
ab956f600f | ||
|
|
97aedeab48 | ||
|
|
bce8d4ed08 | ||
|
|
a91c7b286d | ||
|
|
19c074e477 | ||
|
|
41cfc739fe | ||
|
|
f6276a2c2b | ||
|
|
6002ddf825 | ||
|
|
6549ffde8e | ||
|
|
d9bc5f1320 | ||
|
|
9c5cd998d1 | ||
|
|
93bfa05382 | ||
|
|
d8e1c4265a | ||
|
|
e1720c0e51 | ||
|
|
7f882918eb | ||
|
|
cbc7b8d5c1 | ||
|
|
050293646f | ||
|
|
3daf33837c | ||
|
|
e0748e61dd | ||
|
|
b94e1016fa | ||
|
|
98699719f8 | ||
|
|
48dfbcaa95 | ||
|
|
c644c753d7 | ||
|
|
73b7cee7fb | ||
|
|
5b8302079d | ||
|
|
3a69529e8b | ||
|
|
76f520835f | ||
|
|
507c3042d8 | ||
|
|
1741e90dec | ||
|
|
d646fd0daf | ||
|
|
b5c2f74f45 | ||
|
|
e03753c4ac | ||
|
|
6e6eb63770 | ||
|
|
3c5464ba1c | ||
|
|
655046d24f | ||
|
|
581c6292c9 | ||
|
|
7718eeeacc | ||
|
|
44e0eea94e | ||
|
|
99070899b7 | ||
|
|
05e3a9233a | ||
|
|
70db193f09 | ||
|
|
a2c05a10ec | ||
|
|
cae9bf45b9 | ||
|
|
87c066a35b | ||
|
|
9409b2e4d8 | ||
|
|
f89cd276f7 | ||
|
|
240b728d81 | ||
|
|
dfbb952b2c | ||
|
|
39971eb336 | ||
|
|
0f42c17d85 | ||
|
|
bfc0924eac | ||
|
|
676c2a107e | ||
|
|
2c80cedc39 | ||
|
|
dda53082be | ||
|
|
2622cd23e6 | ||
|
|
9e4a54fa6e | ||
|
|
9ce6480676 | ||
|
|
9121f9b1d3 | ||
|
|
b7535365b2 | ||
|
|
09ed1ddb9c | ||
|
|
0ec65d99aa | ||
|
|
71e4e02722 | ||
|
|
aad546baa5 | ||
|
|
14a69fcc54 | ||
|
|
bf34ffd33f | ||
|
|
6056e07125 | ||
|
|
aa99b86409 | ||
|
|
6ade2eb4e5 | ||
|
|
caa6974942 | ||
|
|
a73a9b6a84 | ||
|
|
72785a3aba | ||
|
|
0c3dd5ddd7 | ||
|
|
739b600f40 | ||
|
|
3710c4d38f | ||
|
|
a05ba44df8 | ||
|
|
ffb9b1d13c | ||
|
|
32190859ec | ||
|
|
8fe4d97d5e | ||
|
|
7e5a959564 | ||
|
|
9e60304869 | ||
|
|
7ad48c1f65 | ||
|
|
a921a596e7 | ||
|
|
3e762fdf5c | ||
|
|
79981a2528 | ||
|
|
bd12aaa98e | ||
|
|
b8f36207c9 | ||
|
|
d907786f04 | ||
|
|
f2355bbe5e | ||
|
|
f398c94761 | ||
|
|
4841784e82 | ||
|
|
cb72c23e9e | ||
|
|
583f2d8209 | ||
|
|
32c4390704 | ||
|
|
3a5e19fbf5 | ||
|
|
dfb857ebef | ||
|
|
9ea9b6bcb1 | ||
|
|
2b0ff62a7f | ||
|
|
d1745084e0 | ||
|
|
407e7b7b6d | ||
|
|
3cf9794755 | ||
|
|
934c8e5f76 | ||
|
|
fc96938345 | ||
|
|
f0ab112c34 | ||
|
|
9660e5b956 | ||
|
|
a585571e90 | ||
|
|
840ec8569d | ||
|
|
1dadeb8a33 | ||
|
|
275b4b3417 | ||
|
|
e004f1d699 | ||
|
|
bde1a6070d | ||
|
|
040dc2a5d4 | ||
|
|
6a186bcd66 | ||
|
|
8c56919bd2 | ||
|
|
115001a3b1 | ||
|
|
b90895412f | ||
|
|
d072f1dc69 | ||
|
|
3999fd193a | ||
|
|
c06e0b4ede | ||
|
|
1bf302a4ea | ||
|
|
f1733afd49 | ||
|
|
f61dcccc6e | ||
|
|
f9bcbdcbcf | ||
|
|
1a854b4aa5 | ||
|
|
62ceb181b1 | ||
|
|
b0c8263cb2 | ||
|
|
d24be2e95c | ||
|
|
8d50d814db | ||
|
|
115ca96e0e | ||
|
|
886491625d | ||
|
|
74c51ff37e | ||
|
|
69ffedfe52 | ||
|
|
fae6f7e081 | ||
|
|
a69e43c9d7 | ||
|
|
91c024ed33 | ||
|
|
649aa102d6 | ||
|
|
31364732dc | ||
|
|
74d55a4938 | ||
|
|
8276f1a204 | ||
|
|
81ebe70b9b | ||
|
|
3160847ebd | ||
|
|
6a95f8c7eb | ||
|
|
c7980542d3 | ||
|
|
7df30f91ae | ||
|
|
d2e89c8b08 | ||
|
|
bd19593204 | ||
|
|
fd0d0ec8df | ||
|
|
8e93434edd | ||
|
|
fc07217d85 | ||
|
|
cb7373b469 | ||
|
|
795ed8abf5 | ||
|
|
66d71a1b35 | ||
|
|
80f8d34427 | ||
|
|
64965bdc96 | ||
|
|
e1ffa7655d | ||
|
|
8c19bf3f2f | ||
|
|
f67dbc9811 | ||
|
|
cd7202e039 | ||
|
|
51d3685efe | ||
|
|
9254cfa6f0 | ||
|
|
cfb34a0607 | ||
|
|
5ad7b71381 | ||
|
|
d2c47c0df2 | ||
|
|
491c32cbd9 | ||
|
|
662adf4f33 | ||
|
|
ad91cab374 | ||
|
|
0ccaed3a6c | ||
|
|
ad719619cc | ||
|
|
6e0a5f7fba | ||
|
|
48f525d025 | ||
|
|
0b5cb18b71 | ||
|
|
4c4f99a583 | ||
|
|
3272a7a3ce | ||
|
|
a48e3355a6 | ||
|
|
afcf424294 | ||
|
|
ac85afaab6 | ||
|
|
3178bb9a26 | ||
|
|
cf58f64c54 | ||
|
|
e4e0ae3918 | ||
|
|
d65acc4e6c | ||
|
|
c9f790b061 | ||
|
|
6b8144a5ac | ||
|
|
2d66ad5d33 | ||
|
|
042af53324 | ||
|
|
192859c2b5 | ||
|
|
e2f6d7665b | ||
|
|
61844b6b67 | ||
|
|
7a752e75ff | ||
|
|
94ceb38a09 | ||
|
|
58c4c012fa | ||
|
|
c3494ae364 | ||
|
|
8ae56161c8 | ||
|
|
76705fc2ee | ||
|
|
21c2137e77 | ||
|
|
ecffca6726 | ||
|
|
3176e0fad7 | ||
|
|
1feb430faa | ||
|
|
b98ffb7dbd | ||
|
|
bac53951b8 | ||
|
|
d59b89e9cd | ||
|
|
58a5563a9f | ||
|
|
1b94271ff6 | ||
|
|
768d79a839 | ||
|
|
91ecb38a34 | ||
|
|
aec3bb5d0a | ||
|
|
29c6000137 | ||
|
|
fec5515c55 | ||
|
|
f187274d36 | ||
|
|
fc5e59fe4a | ||
|
|
d6a8704605 | ||
|
|
56c72a671c | ||
|
|
4191477b98 | ||
|
|
75383a87f9 | ||
|
|
48327a82e3 | ||
|
|
b79ed4105a | ||
|
|
64e29893cf | ||
|
|
0b0f7cfbfc | ||
|
|
40e414d823 | ||
|
|
33b4c33c5b | ||
|
|
a07411c2b9 | ||
|
|
797d82b21a | ||
|
|
a553521d6d | ||
|
|
a33701196a | ||
|
|
1f575fd5c9 | ||
|
|
c7635288f7 | ||
|
|
c8ed78e315 | ||
|
|
e07cfb2068 | ||
|
|
1dc7af5693 | ||
|
|
f7d21c3a1a | ||
|
|
a55bcb24bd | ||
|
|
30cb2b3122 | ||
|
|
cf8d3c3229 | ||
|
|
3c3cb6f6b1 | ||
|
|
91481f255c | ||
|
|
f98048b621 | ||
|
|
4a8e2949bb | ||
|
|
3a3b0709e2 | ||
|
|
e724bbea16 | ||
|
|
665d9779ec | ||
|
|
13d07c6a3d | ||
|
|
391f922acc | ||
|
|
dc59d3df3f | ||
|
|
489dabbd31 | ||
|
|
541cd21838 | ||
|
|
1f95c34381 | ||
|
|
779449fd99 | ||
|
|
fbb568bce0 | ||
|
|
36c23bd5fd | ||
|
|
9ff0f3a7d6 | ||
|
|
fd41110d38 | ||
|
|
fc23cfbf4e | ||
|
|
fd93b633b8 | ||
|
|
7fb8d33f9d | ||
|
|
8bd02e93b2 | ||
|
|
d9c1c7353a | ||
|
|
682e097bee | ||
|
|
b9087ee587 | ||
|
|
df56fdf883 | ||
|
|
90c48b8525 | ||
|
|
5a8b7cd742 | ||
|
|
36a25d75b4 | ||
|
|
6c9304b2c2 | ||
|
|
24ab9dd19e | ||
|
|
a95dc17017 | ||
|
|
5f774c0aed | ||
|
|
6567df7f24 | ||
|
|
6c6b1fbf6e | ||
|
|
9beddd08f9 | ||
|
|
6452e3c9eb | ||
|
|
756822ba39 | ||
|
|
0b2862a1e4 | ||
|
|
258000064d | ||
|
|
e9ca7ea472 | ||
|
|
81f1cc74a7 | ||
|
|
bbcb129e02 | ||
|
|
48e0a59222 | ||
|
|
bc5c7c50fd | ||
|
|
00adc7120d | ||
|
|
c48be439f1 | ||
|
|
371f9c71ca | ||
|
|
91abfcd6cf | ||
|
|
deeab54b40 | ||
|
|
688a627d6c | ||
|
|
9bb1605f10 | ||
|
|
8061d9afbe | ||
|
|
d82e1a108d | ||
|
|
defa04e730 | ||
|
|
92d36e82c4 | ||
|
|
0db43cf7fe | ||
|
|
05be7a0764 | ||
|
|
2a1b3ac629 | ||
|
|
e1d3d3a326 | ||
|
|
b761f1279e | ||
|
|
cc1926942f | ||
|
|
d5e9166f54 | ||
|
|
b31d1a75a0 | ||
|
|
c4ee726532 | ||
|
|
fa2eb2d2e3 | ||
|
|
35f72bf210 | ||
|
|
d22f00d7e4 | ||
|
|
4e8d215606 | ||
|
|
84eecb6561 | ||
|
|
55727e3b21 | ||
|
|
1010b7f148 | ||
|
|
2ac51fc448 | ||
|
|
831132293b | ||
|
|
115e00e0b9 | ||
|
|
94114b05ca | ||
|
|
d2a2320820 | ||
|
|
0c06c81da8 | ||
|
|
c12b4c0cf1 | ||
|
|
99bb5b1d17 | ||
|
|
e29c2bc60e | ||
|
|
c65e4286bf | ||
|
|
69c24e47e8 | ||
|
|
6a775e9560 | ||
|
|
51535866d0 | ||
|
|
3ef5caa9fe | ||
|
|
dccd3e6742 | ||
|
|
9cb02aaaad | ||
|
|
e6d478f8e8 | ||
|
|
2d931b1497 | ||
|
|
0506a5733d | ||
|
|
e8bd2a804d | ||
|
|
7c56e11ecf | ||
|
|
69a20db081 | ||
|
|
7a2a97c882 | ||
|
|
5682338891 | ||
|
|
f0de128449 | ||
|
|
eaa8efb950 | ||
|
|
fb991e9d3b | ||
|
|
8e47cfd1cd | ||
|
|
2471875867 | ||
|
|
b135f1c014 | ||
|
|
f61a1e8132 | ||
|
|
48b7e3dafb | ||
|
|
4bb3af7a6b | ||
|
|
d02c582b96 | ||
|
|
b59d8c3a23 | ||
|
|
232e21d51f | ||
|
|
8644654190 | ||
|
|
ba50c19e82 | ||
|
|
9d60395953 | ||
|
|
a2681aabcb | ||
|
|
bfc5767368 | ||
|
|
798d09bb70 | ||
|
|
8c7cf51395 | ||
|
|
cdfacb4345 | ||
|
|
926ddd0631 | ||
|
|
cb682f36f4 | ||
|
|
156744ad47 | ||
|
|
d9c7166cf0 | ||
|
|
11316b29af | ||
|
|
fe6eb792d5 | ||
|
|
054b1d9808 | ||
|
|
e927149f8e | ||
|
|
1761e2666a | ||
|
|
d6b568a6cc | ||
|
|
c83a5d42bb | ||
|
|
27cd68c301 | ||
|
|
08be4abb30 | ||
|
|
661b192545 | ||
|
|
d1026fa5d2 | ||
|
|
7e63b600b6 | ||
|
|
b2ea212cd1 | ||
|
|
c2fcdc54e2 | ||
|
|
2b9037a190 | ||
|
|
542785ccbf | ||
|
|
65dd2ea52c | ||
|
|
9860f67cde | ||
|
|
03b1b2838e | ||
|
|
4f9311e689 | ||
|
|
652fea45a9 | ||
|
|
1f9eae7e31 | ||
|
|
90b68783ff | ||
|
|
ce246aaf74 | ||
|
|
edeb3d8091 | ||
|
|
496aff7c33 | ||
|
|
f5cdf7cb04 | ||
|
|
440512f08d | ||
|
|
621eb80bbb | ||
|
|
5c7d315ded | ||
|
|
c6324009ba | ||
|
|
147e8ca580 | ||
|
|
6bf039d750 | ||
|
|
9730fb0156 | ||
|
|
f0903ad9df | ||
|
|
8833f386e4 | ||
|
|
5ab9d39253 | ||
|
|
af5644c274 | ||
|
|
3e28dc021c | ||
|
|
f6f920a1a8 | ||
|
|
ae963e444f | ||
|
|
358f5a7e50 | ||
|
|
f63afd161f | ||
|
|
7e4ad40171 | ||
|
|
ffb5e6a732 | ||
|
|
5d804ee7fe | ||
|
|
86e27ccb41 | ||
|
|
192f79aaae | ||
|
|
395cf0f03e | ||
|
|
fc429d18b6 | ||
|
|
ce7ecdb7af | ||
|
|
8751a03a04 | ||
|
|
c55175a589 | ||
|
|
a935ac3e60 | ||
|
|
22d31b31f0 | ||
|
|
f607e3e970 | ||
|
|
686de58886 | ||
|
|
02eb215f2f | ||
|
|
b4dc7a1d34 | ||
|
|
ef54f9aa38 | ||
|
|
288c3b928b | ||
|
|
96930161f9 | ||
|
|
b41890c1e5 | ||
|
|
e2408f37c8 | ||
|
|
db5b8993ac | ||
|
|
1c83eaf75e | ||
|
|
5379063b54 | ||
|
|
b591fc87dc | ||
|
|
17dda58391 | ||
|
|
7ffe87c0bc | ||
|
|
3c4273dd09 | ||
|
|
36d95c9fcc | ||
|
|
44abd1f483 | ||
|
|
db745986f2 | ||
|
|
8271e43e5e | ||
|
|
3f9b7433a3 | ||
|
|
71778e8b90 | ||
|
|
f024565c3f | ||
|
|
e7f31f5cdb | ||
|
|
3c61799fbf | ||
|
|
4e39e13085 | ||
|
|
ac0d9d5fe2 | ||
|
|
4ad90578f7 | ||
|
|
17ba99c1d2 | ||
|
|
3d19be282a | ||
|
|
c076a54a4d | ||
|
|
0419d23882 | ||
|
|
69396347af | ||
|
|
c51604a0e1 | ||
|
|
587dc9946d | ||
|
|
1f3d44b859 | ||
|
|
bc654faf82 | ||
|
|
26bffce66d | ||
|
|
ed18ca3eae | ||
|
|
a204b8dde7 | ||
|
|
b6b003b073 | ||
|
|
f2543b0a98 | ||
|
|
72f487562d | ||
|
|
f91f61cd13 | ||
|
|
9a1beab574 | ||
|
|
a8fe8becf4 | ||
|
|
f6bcb25e16 | ||
|
|
b4a4189d0c | ||
|
|
32d477e5f1 | ||
|
|
0b7c045a2f | ||
|
|
c10fffecdc | ||
|
|
dcfbe4a77a | ||
|
|
8c9bc070f5 | ||
|
|
5bc39d363a | ||
|
|
e3d688e79a | ||
|
|
8d4f3e91b2 | ||
|
|
0cef1f819e | ||
|
|
5c0d656401 | ||
|
|
d416a995ea | ||
|
|
3f67a12477 | ||
|
|
cc57e35974 | ||
|
|
86477f7ecc | ||
|
|
0742606f19 | ||
|
|
1ba69fb5a1 | ||
|
|
ea6f0bf0e5 | ||
|
|
1a18a2f3dd | ||
|
|
4fcacea354 | ||
|
|
cf940ae82e | ||
|
|
70dc3de053 | ||
|
|
cbc59ca893 | ||
|
|
ea3d326c63 | ||
|
|
aad44f2839 | ||
|
|
1319719a5e | ||
|
|
af5d8004fc | ||
|
|
7b96420961 | ||
|
|
a0b43bfae2 | ||
|
|
2c8cd2db34 | ||
|
|
b6d56170fc | ||
|
|
05432e570e | ||
|
|
47da218cc3 | ||
|
|
4ddab8901c | ||
|
|
d38f72aff2 | ||
|
|
15c2a3bacc | ||
|
|
532a69a639 | ||
|
|
d8e1dd4ab2 | ||
|
|
ae25f7968e | ||
|
|
ce93a66dfb | ||
|
|
6a13464059 | ||
|
|
70de324aa8 | ||
|
|
a1ea3e015b | ||
|
|
161059dd98 | ||
|
|
c4c6b42de7 | ||
|
|
21785040c7 | ||
|
|
2b6f7fc7a3 | ||
|
|
0a24a0714e | ||
|
|
ba6f89c76e | ||
|
|
5594edaf67 | ||
|
|
10e3b83a75 | ||
|
|
c48353cb75 | ||
|
|
083510f0f0 | ||
|
|
dba99bc860 | ||
|
|
c04af4bfc7 | ||
|
|
b348caa9e9 | ||
|
|
c8bd1e646e | ||
|
|
9b23e9dcb8 | ||
|
|
69f2c550ab | ||
|
|
9b62310f03 | ||
|
|
08d12f31d1 | ||
|
|
dbddb1d066 | ||
|
|
7dbe3dcded | ||
|
|
10642e6082 | ||
|
|
7b4323e1e0 | ||
|
|
f1bd6f7731 | ||
|
|
5d8eb6a1a0 | ||
|
|
8e2e4d4034 | ||
|
|
a44716f58e | ||
|
|
c71b070168 | ||
|
|
ecd6022c24 | ||
|
|
afbcf1e8ea | ||
|
|
90325d0970 | ||
|
|
e2ba01fcb0 | ||
|
|
17b362f78c | ||
|
|
a5a7e3a261 | ||
|
|
f055ebbd25 | ||
|
|
8a21e328b8 | ||
|
|
31e743d06e | ||
|
|
35c0286cd8 | ||
|
|
c7173a36a1 | ||
|
|
3e8372b96e | ||
|
|
a34a97cc1d | ||
|
|
ae1aaaee5f | ||
|
|
1557ab7644 | ||
|
|
b00a1eac75 | ||
|
|
a7aecbfcaa | ||
|
|
dfcc730cbd | ||
|
|
f7a809be6e | ||
|
|
09fde7f4b8 | ||
|
|
0014024a2c | ||
|
|
c28500556a | ||
|
|
6240d02011 | ||
|
|
925b744ae8 | ||
|
|
22b14ff252 | ||
|
|
3dc26b44d3 | ||
|
|
2e4038bf51 | ||
|
|
76336b4f63 | ||
|
|
9181983483 | ||
|
|
74097a149b | ||
|
|
21a1c53381 | ||
|
|
04eea0f0a8 | ||
|
|
35a468ed38 | ||
|
|
1882a7a2c1 | ||
|
|
f4dd1b1b8b | ||
|
|
70561ed13e | ||
|
|
cdf1a3b530 | ||
|
|
b8b037e930 | ||
|
|
5985f0a7d2 | ||
|
|
8f8a1a02d5 | ||
|
|
b02e5af52c | ||
|
|
58fb782396 | ||
|
|
4fe6129d6c | ||
|
|
c056a009de | ||
|
|
7c12118c19 | ||
|
|
2a09d468da | ||
|
|
a126b4d888 | ||
|
|
9ff91b18cd | ||
|
|
d9f045fba1 | ||
|
|
c06bef7273 | ||
|
|
3c98f1a4cd | ||
|
|
6e0f1399d7 | ||
|
|
0102101acc | ||
|
|
4ac5269b4f | ||
|
|
b6f4ceaed0 | ||
|
|
15f812dae8 | ||
|
|
6884aab49b | ||
|
|
88ec4e7061 | ||
|
|
dd3d2490ed | ||
|
|
739055ae7b | ||
|
|
dbbd711f46 | ||
|
|
98cbb6a43c | ||
|
|
214cf13f17 | ||
|
|
17a5c808da | ||
|
|
fc1783fcc6 | ||
|
|
1b193e7b37 | ||
|
|
8e59744b8d | ||
|
|
7081a6aa34 | ||
|
|
64dc8fbada | ||
|
|
fc8e3de7db | ||
|
|
57bee9fcdd | ||
|
|
dce52e491e | ||
|
|
9405a47245 | ||
|
|
495b8bf12e | ||
|
|
e221166fab | ||
|
|
035cab8da3 | ||
|
|
89c6ed12bf | ||
|
|
e462da828d | ||
|
|
79c66d66bd | ||
|
|
5d37f705f4 | ||
|
|
6bb370cec1 | ||
|
|
bb69201578 | ||
|
|
4fac7daaef | ||
|
|
3617c2795a | ||
|
|
9c0c1bcdbd | ||
|
|
187e8db1be | ||
|
|
c7f88180f6 | ||
|
|
8a2c3fb88f | ||
|
|
1164eda5af | ||
|
|
4482f6f1f0 | ||
|
|
796662a612 | ||
|
|
33ee4cc516 | ||
|
|
3bbf2c673c | ||
|
|
074c9c52ef | ||
|
|
3110ec5a23 | ||
|
|
3014b3d770 | ||
|
|
eab2ea9fc2 | ||
|
|
21ed92a6e9 | ||
|
|
04111dd1e4 | ||
|
|
817788fbf0 | ||
|
|
4511030af2 | ||
|
|
7812813a32 | ||
|
|
664cd6067d | ||
|
|
784e2a7b42 | ||
|
|
fc2a376d8e | ||
|
|
c5aafd8f90 | ||
|
|
eaddd1e3cd | ||
|
|
2d44577586 | ||
|
|
e46392ea2c | ||
|
|
c882790a2e | ||
|
|
121002d700 | ||
|
|
be51ee1ceb | ||
|
|
659de779e6 | ||
|
|
51b14b6c0c | ||
|
|
223a0fa55d | ||
|
|
ef72b471fc | ||
|
|
82246b8766 | ||
|
|
35f60377aa | ||
|
|
3a951a66cb | ||
|
|
e0136fc8bd | ||
|
|
ac1b5f3da5 | ||
|
|
fd62fba985 | ||
|
|
c652f8243a | ||
|
|
a9c7b9b8f7 | ||
|
|
e4f0564aa6 | ||
|
|
91533d3c33 | ||
|
|
0bbc9708f9 | ||
|
|
9d5b9defde | ||
|
|
215f21a038 | ||
|
|
c240d98ffd | ||
|
|
6ab73113fc | ||
|
|
713c7c7c62 | ||
|
|
9b1807a8a2 | ||
|
|
ec3b097cb9 | ||
|
|
c472a27818 | ||
|
|
201971e293 | ||
|
|
acad8cfab1 | ||
|
|
491ba2dda5 | ||
|
|
5abe9e8266 | ||
|
|
be3a3a5aed | ||
|
|
a3ab36c803 | ||
|
|
19cac63fe4 | ||
|
|
43419a4ada | ||
|
|
c089f7d497 | ||
|
|
aa5517f6b9 | ||
|
|
50140be7ae | ||
|
|
8b89454994 | ||
|
|
5380ff4d88 | ||
|
|
094b66e81d | ||
|
|
b69ae4854c | ||
|
|
0b843af56b | ||
|
|
12b1d8b14a | ||
|
|
e67f92c55c | ||
|
|
812733cc96 | ||
|
|
028f227752 | ||
|
|
5b0aa638cf | ||
|
|
6eaceb5f73 | ||
|
|
0697c5edb6 | ||
|
|
1031eedf27 | ||
|
|
90034e4c4b | ||
|
|
df40e94673 | ||
|
|
e6d5059cbb | ||
|
|
3b6e409cd8 | ||
|
|
249f03bbb7 | ||
|
|
7463c83205 | ||
|
|
1266c2b600 | ||
|
|
684e2fdc94 | ||
|
|
a1d586302f | ||
|
|
7a604cdd98 | ||
|
|
aeb54b0dd9 | ||
|
|
f88c020fc0 | ||
|
|
2eeddba756 | ||
|
|
2754546080 | ||
|
|
218cecb6d1 | ||
|
|
e9f4453b0e | ||
|
|
27c3674ce1 | ||
|
|
5dc3dd3d4a | ||
|
|
f8542cd988 | ||
|
|
4707373d33 | ||
|
|
79c00ad8f2 | ||
|
|
fbaaa5906b | ||
|
|
cde44ddb72 | ||
|
|
b04601b918 | ||
|
|
d3d30a46f0 | ||
|
|
7911d8d3f5 | ||
|
|
fbbfc3b03c | ||
|
|
509eac9575 | ||
|
|
85b38190d1 | ||
|
|
7aca36bca4 | ||
|
|
f5371a75f4 | ||
|
|
febdef43f5 | ||
|
|
f56756986b | ||
|
|
dcd282bb26 | ||
|
|
9c14474d30 | ||
|
|
1e96e01766 | ||
|
|
7e4bc94510 | ||
|
|
26c1ca4c3e | ||
|
|
1e865b3539 | ||
|
|
4a85db1ce1 | ||
|
|
0a985fd4c6 | ||
|
|
012cc709d0 | ||
|
|
d6590e3bd2 | ||
|
|
134aec40f0 | ||
|
|
48a476ae0f | ||
|
|
023c2018f7 | ||
|
|
800d4c8ac8 | ||
|
|
32865aeaab | ||
|
|
7b339795a1 | ||
|
|
ae9bbe1169 | ||
|
|
927dbd134d | ||
|
|
2a9a77dd8c | ||
|
|
1aee4bc90a | ||
|
|
e1bd6cc913 | ||
|
|
027fcaf05e | ||
|
|
716d69f27e | ||
|
|
ff7e73af66 | ||
|
|
2976e31ac9 | ||
|
|
807ee5ec31 | ||
|
|
d9a731d486 | ||
|
|
9c57357e05 | ||
|
|
2742611cad | ||
|
|
5092b198bc | ||
|
|
b4d9d82e1d | ||
|
|
d9fd695ac7 | ||
|
|
92614ecbf9 | ||
|
|
aaeca12d89 | ||
|
|
3d0c7ae385 | ||
|
|
04e3a79f76 | ||
|
|
e47e99bb09 | ||
|
|
9b6b0e403c | ||
|
|
4d1c6034eb | ||
|
|
a3348eccdd | ||
|
|
3a04481485 | ||
|
|
ad77331c04 | ||
|
|
d9ebc4e821 | ||
|
|
c00eb4f4c6 | ||
|
|
25af02f21a | ||
|
|
67cb2dad37 | ||
|
|
1aa98f8b93 | ||
|
|
a58c133821 | ||
|
|
aeee70a815 | ||
|
|
c771ba361c | ||
|
|
ab6e2272cc | ||
|
|
e4728409e7 | ||
|
|
e3ebf366a6 | ||
|
|
894faf3fed | ||
|
|
4eb97fa4e3 | ||
|
|
6b55c83252 | ||
|
|
2fe94ad7e3 | ||
|
|
3940de5952 | ||
|
|
c4d0f96a6d | ||
|
|
3b9c442689 | ||
|
|
08f98c7fac | ||
|
|
a151f955a0 | ||
|
|
42a225cbd9 | ||
|
|
bf20d19901 | ||
|
|
fc0884037e | ||
|
|
1aeed2dbca | ||
|
|
799bea4730 | ||
|
|
60cd5ea3f2 | ||
|
|
4fd9a00f35 | ||
|
|
5681563898 | ||
|
|
20931baf1d | ||
|
|
d58d19ba32 | ||
|
|
ee0659f8b6 | ||
|
|
8029bf955c | ||
|
|
2520f410c8 | ||
|
|
ee63f5f04e | ||
|
|
1aaf72fb6d | ||
|
|
c1313c2057 | ||
|
|
cb0f177c35 | ||
|
|
71677e5204 | ||
|
|
4db5723525 | ||
|
|
dc7f3ef2bb | ||
|
|
419ba86a91 | ||
|
|
6a5b4d5faf | ||
|
|
2599163b8a | ||
|
|
8ef22f7740 | ||
|
|
c0c4d1adab | ||
|
|
729a44e67d | ||
|
|
74c1118964 | ||
|
|
596508a928 | ||
|
|
043e3b3429 | ||
|
|
8b0cb944da | ||
|
|
117fc67077 | ||
|
|
c79a3841e8 | ||
|
|
5888de9f34 | ||
|
|
04b4b69b11 | ||
|
|
fd34a3d246 | ||
|
|
6d597e39c3 | ||
|
|
b9ce56d936 | ||
|
|
f889e52a15 | ||
|
|
34caecd6b6 | ||
|
|
a44c8f651b | ||
|
|
4b8bda25c0 | ||
|
|
6b5e6119ee | ||
|
|
7af1dc1d27 | ||
|
|
e77686f7a8 | ||
|
|
2207ea0b36 | ||
|
|
a212ff757f | ||
|
|
a76031e11d | ||
|
|
a7f280765c | ||
|
|
07d033ecb4 | ||
|
|
cdb4299acb | ||
|
|
7df2c82a8a | ||
|
|
6cf90d7cee | ||
|
|
2f1ad8ed3c | ||
|
|
371d8e2ee0 | ||
|
|
6397095ca4 | ||
|
|
f69a572538 | ||
|
|
11b07a56b2 | ||
|
|
b559cfd4c0 | ||
|
|
11d49491cb | ||
|
|
6ea6cf9464 | ||
|
|
9730a2af0a | ||
|
|
c2ed5f6863 | ||
|
|
7b66e72e2c | ||
|
|
d57b2a6525 | ||
|
|
bdfbd794e3 | ||
|
|
111de881fa | ||
|
|
d6e882ed84 | ||
|
|
f488eed101 | ||
|
|
652c3653bb | ||
|
|
fb19faa31b | ||
|
|
07211701f4 | ||
|
|
bba0a9d962 | ||
|
|
f1794a8853 | ||
|
|
0544a2279b | ||
|
|
5c222f0561 | ||
|
|
3def950b84 | ||
|
|
63fe2d5bd2 | ||
|
|
561834650a | ||
|
|
f20f50368f | ||
|
|
00235d8a99 | ||
|
|
2038bf6183 | ||
|
|
e41ac1f875 | ||
|
|
8465869d7b | ||
|
|
3d53d1539d | ||
|
|
20e4ef8b4c | ||
|
|
c4a3c2342a | ||
|
|
7a0d301753 | ||
|
|
f2b03facd9 | ||
|
|
02ad5e11da | ||
|
|
d141cdbeb0 | ||
|
|
cfc05e05f0 | ||
|
|
8ea312633b | ||
|
|
e461f3dbbe | ||
|
|
54014e42e3 | ||
|
|
3e7a29cc92 | ||
|
|
00a57a9f8f | ||
|
|
1d7384530e | ||
|
|
889bbf27a2 | ||
|
|
5f8473914c | ||
|
|
785908ee37 | ||
|
|
fbb70eec5c | ||
|
|
002bb759ff | ||
|
|
a3f762c5aa | ||
|
|
c3c27e5ab5 | ||
|
|
c6b1f181aa | ||
|
|
94564b058e | ||
|
|
0fc73a2a85 | ||
|
|
3156fcf5f4 | ||
|
|
f85fb9fdff | ||
|
|
0bc3d664e3 | ||
|
|
e5c46e13e8 | ||
|
|
49a3b58c8b | ||
|
|
d0c8d45a2e | ||
|
|
c9a10631cb | ||
|
|
3bd806f12f | ||
|
|
fd16bcb20c | ||
|
|
5221242f6e | ||
|
|
31a5f0d399 | ||
|
|
102a4d492a | ||
|
|
f68508b6ce | ||
|
|
9e8b86fd2d | ||
|
|
92fec0f050 | ||
|
|
4749cc930a | ||
|
|
78a0ba0a6a | ||
|
|
7a39837d96 | ||
|
|
55b6e92db5 | ||
|
|
69dc3a8535 | ||
|
|
27f4cdd586 | ||
|
|
70d61a0ae3 | ||
|
|
427b534054 | ||
|
|
e421d52713 | ||
|
|
a59678f376 | ||
|
|
c98254c3d7 | ||
|
|
c123a72844 | ||
|
|
3c8fad126c | ||
|
|
f28cf3302d | ||
|
|
55010a9d3a | ||
|
|
0193e7c428 | ||
|
|
3423d75475 | ||
|
|
f6b5cc9f84 | ||
|
|
59a298f124 | ||
|
|
36c2948225 | ||
|
|
c9fe1fa5ba | ||
|
|
dccddc2bdb | ||
|
|
0e36681b8e | ||
|
|
1de80f5b22 | ||
|
|
2039dce75f | ||
|
|
d551b88a6d | ||
|
|
16c3514d01 | ||
|
|
206000a017 | ||
|
|
76ee490468 | ||
|
|
e77b22d6da | ||
|
|
07039f4b19 | ||
|
|
4678192c88 | ||
|
|
7c3d3dfa29 | ||
|
|
ef826b86cb | ||
|
|
5223f552c8 | ||
|
|
cfde93afe0 | ||
|
|
986a5a6c2c | ||
|
|
7c8b35ff32 | ||
|
|
3eeb084e71 | ||
|
|
2ac0bfe59e | ||
|
|
024741b476 | ||
|
|
f4c95f6dd9 | ||
|
|
d4fbeacc33 | ||
|
|
0eef389ddb | ||
|
|
e27b1ce50c | ||
|
|
9f8b6daca2 | ||
|
|
6060bcfc8a | ||
|
|
ff9673463c | ||
|
|
1085cc2178 | ||
|
|
11addaa16e | ||
|
|
760ca5ccc0 | ||
|
|
290d3f8b61 | ||
|
|
aa09e0f5dd | ||
|
|
d142579e97 | ||
|
|
f286139d22 | ||
|
|
7b9d69b827 | ||
|
|
cbd861f188 | ||
|
|
faf972f039 | ||
|
|
622d1c0423 | ||
|
|
634c948769 | ||
|
|
a04e3a2dc8 | ||
|
|
87876d5474 | ||
|
|
d338d66324 | ||
|
|
272660e704 | ||
|
|
5a95c5ae2c | ||
|
|
70e67ae018 | ||
|
|
ad97258915 | ||
|
|
ed2a6377e7 | ||
|
|
9976869549 | ||
|
|
8c1b22ba6d | ||
|
|
2dba1cfac1 | ||
|
|
d7ba6c3ea8 | ||
|
|
bf9904ee4d | ||
|
|
577bce9029 | ||
|
|
ba4c7f193b | ||
|
|
e9e89b355b | ||
|
|
9bb406d78d | ||
|
|
11a14db286 | ||
|
|
832ec098fc | ||
|
|
486a80e8ef | ||
|
|
19d45f4b31 | ||
|
|
5a2b88f6e9 | ||
|
|
00a39ad5f8 | ||
|
|
ff37e41625 | ||
|
|
0901176fe4 | ||
|
|
a9a9018191 | ||
|
|
4a7801c3ec | ||
|
|
517578f80e | ||
|
|
85442ed045 | ||
|
|
6a12b13a85 | ||
|
|
1cfe3c7382 | ||
|
|
c06014792b | ||
|
|
6fe04871f4 | ||
|
|
9d67988aed | ||
|
|
765b451edd | ||
|
|
17c993c753 | ||
|
|
dde6937319 | ||
|
|
272b0f36b3 | ||
|
|
126c8cb46b | ||
|
|
98b9ff47a1 | ||
|
|
ece4b4b33a | ||
|
|
a70a4ae053 | ||
|
|
7612f18dc8 | ||
|
|
b9f2c27661 | ||
|
|
4e21baff43 | ||
|
|
683ef11ab9 | ||
|
|
ca466374bd | ||
|
|
5a2a185682 | ||
|
|
ee52a6dc40 | ||
|
|
82607efb57 | ||
|
|
35a2c2a743 | ||
|
|
b955e7a6b2 | ||
|
|
883d9595c5 | ||
|
|
1f308a3cea | ||
|
|
1cd9899cf3 | ||
|
|
069131dc25 | ||
|
|
dd8f38fcbb | ||
|
|
a216f2562d | ||
|
|
0c0926395d | ||
|
|
bc13c6de39 | ||
|
|
8ec0b9e33b | ||
|
|
b99c2bd345 | ||
|
|
c04a24399a | ||
|
|
b099a56f9f | ||
|
|
703005c8ba | ||
|
|
51f0178625 | ||
|
|
5d59dcf66e | ||
|
|
c242dd402c | ||
|
|
2216e0b779 | ||
|
|
1c83a49be9 | ||
|
|
2617384d8e | ||
|
|
34b8acaef7 | ||
|
|
6326c18906 | ||
|
|
5c4b0c86fb | ||
|
|
00149c0b6a | ||
|
|
c5c968cb22 | ||
|
|
128cbdeb2f | ||
|
|
18af1dc460 | ||
|
|
d1e6f0f8c6 | ||
|
|
5a0d99fa0b | ||
|
|
6e2e6b796f | ||
|
|
24b677d053 | ||
|
|
63271a51c4 | ||
|
|
61b4c923d7 | ||
|
|
2a2e4c5801 | ||
|
|
be48f4d657 | ||
|
|
13e652939b | ||
|
|
71fb113818 | ||
|
|
08d22503bb | ||
|
|
56f518a98f | ||
|
|
b7f2933744 | ||
|
|
7483dfc652 | ||
|
|
95c358f721 | ||
|
|
39c3c4ec22 | ||
|
|
e9c1c415b8 | ||
|
|
21d93bfd33 | ||
|
|
9a92eb4158 | ||
|
|
0dd91e20d5 | ||
|
|
ce14eafc24 | ||
|
|
8d70c0edab | ||
|
|
813ac49543 | ||
|
|
4ab01fb198 | ||
|
|
d5036b11b1 | ||
|
|
2581946231 | ||
|
|
b35db4e006 | ||
|
|
d35f1ad5c1 | ||
|
|
8f1902c05a | ||
|
|
6469b9037c | ||
|
|
7d4c92fb00 | ||
|
|
0763d8cadf | ||
|
|
5466373a11 | ||
|
|
588bdb5404 | ||
|
|
54f22a3eef | ||
|
|
ea94d6d93c | ||
|
|
57280762b6 | ||
|
|
ced3037523 | ||
|
|
dd2bc998ab | ||
|
|
08da1adcf6 | ||
|
|
3be0cc2087 | ||
|
|
9648bdce30 | ||
|
|
d1aebdbde0 | ||
|
|
8f0fadfaaa | ||
|
|
02896dabee | ||
|
|
0036a1d195 | ||
|
|
2a9b314627 | ||
|
|
2165bef4ca | ||
|
|
4862930845 | ||
|
|
3207a8bbbf | ||
|
|
6214f15a0c | ||
|
|
cd2c78fb8a | ||
|
|
4211d86539 | ||
|
|
39f28424ca | ||
|
|
84feeb0f36 | ||
|
|
2665afb515 | ||
|
|
d0abe7c246 | ||
|
|
50fb0b5eae | ||
|
|
16f2ef91ab | ||
|
|
4b885c8633 | ||
|
|
5238055f40 | ||
|
|
9ac088f376 | ||
|
|
849c9f6168 | ||
|
|
23892caf53 | ||
|
|
8e6390c32c | ||
|
|
51a33713fc | ||
|
|
9c3af11a92 | ||
|
|
9d7b53cb9b | ||
|
|
f0095ccd34 | ||
|
|
4f0eadfce4 | ||
|
|
400b953fbb | ||
|
|
38bcc04a11 | ||
|
|
c738c3431f | ||
|
|
ed7c4320f6 | ||
|
|
9155e2de4c | ||
|
|
38127d9ec0 | ||
|
|
c9c0e5077d | ||
|
|
ccf4ccde23 | ||
|
|
e96a92f869 | ||
|
|
fd43e4dcbc | ||
|
|
3d51ccdaae | ||
|
|
833377ff1e | ||
|
|
53ca0cbe75 | ||
|
|
342973b349 | ||
|
|
355be4b13f | ||
|
|
0cd0fb9184 | ||
|
|
d1a6e5603f | ||
|
|
84a36b99bf | ||
|
|
ab7c33ede0 | ||
|
|
77258f6069 | ||
|
|
d23e315ea2 | ||
|
|
f085c3d7a0 | ||
|
|
69bdc20a3c | ||
|
|
847aac4315 | ||
|
|
39818e7979 | ||
|
|
0e6f989b0d | ||
|
|
1678ed6235 | ||
|
|
ca821982ee | ||
|
|
ce6e7d8620 | ||
|
|
fc56af14c2 | ||
|
|
bb006f9735 | ||
|
|
6956b10b2d | ||
|
|
b4f9a05894 | ||
|
|
8f9ddf452d | ||
|
|
dacd1356e4 | ||
|
|
d3c523e0d2 | ||
|
|
2c25df089f | ||
|
|
553022dc56 | ||
|
|
8a040d187a | ||
|
|
064cac2bf9 | ||
|
|
5b2c740ad8 | ||
|
|
b9ab5c8836 | ||
|
|
c47f211296 | ||
|
|
54d3b1710e | ||
|
|
128f007b25 | ||
|
|
841aad95b4 | ||
|
|
1d4199f46b | ||
|
|
c5d4fcb119 | ||
|
|
6271406233 | ||
|
|
52bd62c72f | ||
|
|
f4bbc54cc4 | ||
|
|
d8910af80d | ||
|
|
9260114162 | ||
|
|
24c9751558 | ||
|
|
a1c6bfd77b | ||
|
|
42eccac454 | ||
|
|
aec504344a | ||
|
|
0b41145443 | ||
|
|
00f3d16b12 | ||
|
|
99c2f7a349 | ||
|
|
b441532396 | ||
|
|
1dbadb6527 | ||
|
|
09dbad47e1 | ||
|
|
e2facffe4d | ||
|
|
273d8865e3 | ||
|
|
5a8bf1f6a3 | ||
|
|
78776ee4e2 | ||
|
|
266107f57c | ||
|
|
2e0d64cf2f | ||
|
|
95da484727 | ||
|
|
06b3a1000c | ||
|
|
dac42f52b2 | ||
|
|
7c43f8b896 | ||
|
|
c62e4c30f4 | ||
|
|
0d6b70d96b | ||
|
|
15c10b0c66 | ||
|
|
308510eb4f | ||
|
|
afe23e7f10 | ||
|
|
b49af043d7 | ||
|
|
14848875bf | ||
|
|
7d8c34018e | ||
|
|
b966afcc7a | ||
|
|
ec5315a987 | ||
|
|
4f8778bab9 | ||
|
|
e2d87548f8 | ||
|
|
f7151d384b | ||
|
|
0fb8ef8f79 | ||
|
|
1b23e25f95 | ||
|
|
35c71ff536 | ||
|
|
243d8bebd1 | ||
|
|
9b34681d97 | ||
|
|
4dc7170d21 | ||
|
|
9cb347b4b2 | ||
|
|
0f85a4683a | ||
|
|
417e1cee9e | ||
|
|
f7e900e12e | ||
|
|
d9661c8f3b | ||
|
|
14a2a64df4 | ||
|
|
6ae402fd0b | ||
|
|
a6408a3b09 | ||
|
|
1147782c79 | ||
|
|
2f3f3862fa | ||
|
|
d0bded5988 | ||
|
|
8308f52c2a | ||
|
|
6151d0dc1e | ||
|
|
5a1127b726 | ||
|
|
b8ff3c1820 | ||
|
|
c8d8b88223 | ||
|
|
d28101878a | ||
|
|
bac14ef985 | ||
|
|
8f9db3fcb8 | ||
|
|
af567538a0 | ||
|
|
cdf877d4b1 | ||
|
|
eef4ba9c02 | ||
|
|
a1ea8a82c3 | ||
|
|
a457e16360 | ||
|
|
05bc87a66f | ||
|
|
605b603735 | ||
|
|
85ba271639 | ||
|
|
d9835737f0 | ||
|
|
f9e0e90441 | ||
|
|
60f5d24411 | ||
|
|
30e1302e73 | ||
|
|
87c5cd46ac | ||
|
|
6a9016ea60 | ||
|
|
6e1fc01752 | ||
|
|
e718ec3e93 | ||
|
|
772aeca338 | ||
|
|
684b5b0e40 | ||
|
|
d8b9254301 | ||
|
|
835b910e7d | ||
|
|
578874033a | ||
|
|
640acba850 | ||
|
|
d8e1c9f175 | ||
|
|
2797588be1 | ||
|
|
e8eff3b8fd | ||
|
|
ab0f7d7fdc | ||
|
|
29cc8282b1 | ||
|
|
3f69af3aaf | ||
|
|
499047e132 | ||
|
|
78c67157c1 | ||
|
|
b31bc2dc9f | ||
|
|
95e1aa2dc5 | ||
|
|
7e72673d87 | ||
|
|
13b117b5bc | ||
|
|
ee0fed639c | ||
|
|
c5979d564e | ||
|
|
e6ef927e6b | ||
|
|
58aa04573f | ||
|
|
1980ca8c4e | ||
|
|
2a25e2bf4d | ||
|
|
b0b56b4379 | ||
|
|
373262f9fb | ||
|
|
ce519e939b | ||
|
|
acef0bb51a | ||
|
|
8bf28e6bb1 | ||
|
|
9c418bc468 | ||
|
|
456efa4666 | ||
|
|
80dc7cceb8 | ||
|
|
7fd535c6ae | ||
|
|
b4b8917caf | ||
|
|
e4f2cf455e | ||
|
|
6972b5f3d2 | ||
|
|
ac35208115 | ||
|
|
532e846b86 | ||
|
|
f8c2f8480a | ||
|
|
0fe0b15e71 | ||
|
|
061e364b25 | ||
|
|
018688da2a | ||
|
|
9ec5592bb5 | ||
|
|
cdc5ef6710 | ||
|
|
c9dd1eb97d | ||
|
|
d09b5c1453 | ||
|
|
bbd6ed5bc5 | ||
|
|
a750bf3ac6 | ||
|
|
1256541d7a | ||
|
|
4fa4c9248f | ||
|
|
aa89e380d9 | ||
|
|
5a37e182de | ||
|
|
fa43fd1444 | ||
|
|
3551f5d118 | ||
|
|
e737672614 | ||
|
|
25a41b80fc | ||
|
|
9293f7072e | ||
|
|
c20874c28f | ||
|
|
5de0bc1d4f | ||
|
|
a6fafe2f01 | ||
|
|
33f9a6d360 | ||
|
|
aabe0a8473 | ||
|
|
1f4a76d2c8 | ||
|
|
4a6eadbde0 | ||
|
|
683a74501f | ||
|
|
f43416e1d7 | ||
|
|
5a493560f5 | ||
|
|
9ed0a98178 | ||
|
|
dac753b81e | ||
|
|
119f7dc3d6 | ||
|
|
22a68d1613 | ||
|
|
d0110b7e35 | ||
|
|
3f4839ce3d | ||
|
|
7bdf0628b1 | ||
|
|
fc1355114d | ||
|
|
926233bde8 | ||
|
|
0683fa7d1d | ||
|
|
6ce207b9a5 | ||
|
|
07b1c1a15f | ||
|
|
58992761cf | ||
|
|
b8957f50c3 | ||
|
|
df66516ed3 | ||
|
|
a57baa69a5 | ||
|
|
85534a1397 | ||
|
|
a2fa5d6288 | ||
|
|
cd3003683d | ||
|
|
d1ef29d679 | ||
|
|
5f41bb0f77 | ||
|
|
a58a6b27c3 | ||
|
|
a036cc97b7 | ||
|
|
38c7def47a | ||
|
|
5533641319 | ||
|
|
55dfdd9299 | ||
|
|
2c734c9bca | ||
|
|
6cdd1be93e | ||
|
|
bcc20b29df | ||
|
|
befd7d4a2f | ||
|
|
f8640d4050 | ||
|
|
f81c14aa1e | ||
|
|
5555651ce0 | ||
|
|
b268f8815d | ||
|
|
aa9b09a9e3 | ||
|
|
986fa00406 | ||
|
|
7abc3c01e0 | ||
|
|
6d14f78115 | ||
|
|
9534b9fe69 | ||
|
|
60dc273513 | ||
|
|
b5dac0f0f8 | ||
|
|
a07627b1f8 | ||
|
|
1b8f499ee1 | ||
|
|
f428d286a1 | ||
|
|
beb248b6ac | ||
|
|
1936dddc3c | ||
|
|
14f6bd0f4e | ||
|
|
e01d26e1a4 | ||
|
|
e528d919a8 | ||
|
|
4881677268 | ||
|
|
3302fd1088 | ||
|
|
4c2d637203 | ||
|
|
beaff39618 | ||
|
|
ffa0a0834a | ||
|
|
038057eb3e | ||
|
|
5bedcb665b | ||
|
|
2435ea4113 | ||
|
|
8c6215f5de | ||
|
|
10ebe6cb48 | ||
|
|
1ac50fcb5a | ||
|
|
e098be8e88 | ||
|
|
8cf0afaf1c | ||
|
|
e29f93e8a8 | ||
|
|
4e8d000f76 | ||
|
|
7787792e8d | ||
|
|
6ee5e507c7 | ||
|
|
06ee32d1b5 | ||
|
|
86bb7fe614 | ||
|
|
959a9f5cad | ||
|
|
4f7df299ea | ||
|
|
b3ab0bc7e3 | ||
|
|
701ed6c874 | ||
|
|
8f2131cf2d | ||
|
|
32c4af8f0d | ||
|
|
295a60ec8d | ||
|
|
a4fae96c96 | ||
|
|
263bb0e68d | ||
|
|
0506b328b5 | ||
|
|
4e426c19d0 | ||
|
|
9795d87348 | ||
|
|
2eb0be0b73 | ||
|
|
cd95579834 | ||
|
|
98639d0f6f | ||
|
|
ab5e0632fe | ||
|
|
b123129f4e | ||
|
|
81d2b986af | ||
|
|
7a0b1d5781 | ||
|
|
9f0617cbfb | ||
|
|
75b07598fe | ||
|
|
dfbb6975b3 | ||
|
|
5b3052f999 | ||
|
|
506ff320f2 | ||
|
|
a30b279bad | ||
|
|
6a2495c840 | ||
|
|
cba5970cd8 | ||
|
|
689081d832 | ||
|
|
cc09f1a679 | ||
|
|
e4eb242ce8 | ||
|
|
ce98e0c6a0 | ||
|
|
49544ea943 | ||
|
|
6b7bfed40c | ||
|
|
bcab36da3f | ||
|
|
1689e73e90 | ||
|
|
0103408a5c | ||
|
|
38a16ecba2 | ||
|
|
205eb3a8f2 | ||
|
|
fe61b8c630 | ||
|
|
867b15d77c | ||
|
|
98cb9f9931 | ||
|
|
95077d60c9 | ||
|
|
bc49f094e7 | ||
|
|
cef6dfb422 | ||
|
|
c8703ba40b | ||
|
|
ab4405bea5 | ||
|
|
78a55e2898 | ||
|
|
d0a2494a99 | ||
|
|
89d009ba6e | ||
|
|
1f4ff47b41 | ||
|
|
eb52ac7a35 | ||
|
|
e904e891bd | ||
|
|
771292c328 | ||
|
|
86bf6045c6 | ||
|
|
5f7f7b954d | ||
|
|
5d3f0741e3 | ||
|
|
563cbb6c21 | ||
|
|
425778aa67 | ||
|
|
69a84198b0 | ||
|
|
5c04504932 | ||
|
|
556a1cfb34 | ||
|
|
28a8eae850 | ||
|
|
236fea1f00 | ||
|
|
e50ced88c6 | ||
|
|
112755cf91 | ||
|
|
4081b2fe94 | ||
|
|
2d9311e860 | ||
|
|
b3a4f28ad1 | ||
|
|
97c8873214 | ||
|
|
bb68f6089b | ||
|
|
f4ca065cfb | ||
|
|
cb224ecaa3 | ||
|
|
7977c2b4d0 | ||
|
|
e54eb67639 | ||
|
|
4fe0b11195 | ||
|
|
df4bd60f42 | ||
|
|
764fb35e1f | ||
|
|
e1bdc0ecaf | ||
|
|
39bde329bd | ||
|
|
204d299abb | ||
|
|
e0995b1c14 | ||
|
|
4af178bdfe | ||
|
|
aa41dc02b1 | ||
|
|
6a77ea3c93 | ||
|
|
62c72059d9 | ||
|
|
c10e3f7f4f | ||
|
|
e542e6953e | ||
|
|
530cf316b8 | ||
|
|
740385d636 | ||
|
|
cd4651116e | ||
|
|
46291be348 | ||
|
|
90071c1df0 | ||
|
|
25293d7ac6 | ||
|
|
5024742f8a | ||
|
|
0452a4e71f | ||
|
|
8de96817ce | ||
|
|
47e167679a | ||
|
|
f0a42346a4 | ||
|
|
86287b8d56 | ||
|
|
8924211f3b | ||
|
|
525e7649cf | ||
|
|
0ecb3d1829 | ||
|
|
9755307842 | ||
|
|
7446818f98 | ||
|
|
280b5612c0 | ||
|
|
e57ec7d563 | ||
|
|
2a3f4de3f4 | ||
|
|
27fdb4ead2 | ||
|
|
297e0bad8c | ||
|
|
e3b4c22ec9 | ||
|
|
da8278e1e3 | ||
|
|
17fba753c4 | ||
|
|
71e705a273 | ||
|
|
74654c8cbb | ||
|
|
f468b203ad | ||
|
|
20d4f2e836 | ||
|
|
08370c39ff | ||
|
|
bd3c792507 | ||
|
|
8d3fd86d6d | ||
|
|
4034715713 | ||
|
|
37d738fa6b | ||
|
|
271eff149f | ||
|
|
010efc310f | ||
|
|
811c8b58c5 | ||
|
|
82c4e2236a | ||
|
|
63e40c9614 | ||
|
|
2f448ed565 | ||
|
|
af28305961 | ||
|
|
48ea8193df | ||
|
|
1d112bdd1e | ||
|
|
5eb292a653 | ||
|
|
7e56b6b6cb | ||
|
|
41d97e1ef4 | ||
|
|
01c37e0a4b | ||
|
|
a5e7e7db95 | ||
|
|
bf19051a9f | ||
|
|
3c13a88b14 | ||
|
|
f6d75c534c | ||
|
|
e9c0b2d69e | ||
|
|
7eddbfed53 | ||
|
|
b347b3023f | ||
|
|
3541880efd | ||
|
|
7b50dc0b24 | ||
|
|
2805243103 | ||
|
|
34f22e88a1 | ||
|
|
a18b3fbbdc | ||
|
|
7277035736 | ||
|
|
7612c1ea87 | ||
|
|
b91d39f20b | ||
|
|
b4b64b9cce | ||
|
|
712abe40f2 | ||
|
|
af8a180aed | ||
|
|
a581e9e5d8 | ||
|
|
05a28312cf | ||
|
|
4d0aa4d8fe | ||
|
|
575f401896 | ||
|
|
6f3536f974 | ||
|
|
90ef46df0b | ||
|
|
3ae88147e2 | ||
|
|
6417952574 | ||
|
|
79694d424c | ||
|
|
51f2e2ca27 | ||
|
|
68555fdbd2 | ||
|
|
63e0c35412 | ||
|
|
2213a7110c | ||
|
|
79ba37f3bf | ||
|
|
a905d8f704 | ||
|
|
762c33a964 | ||
|
|
253d63159f | ||
|
|
c156093ffd | ||
|
|
34179b3354 | ||
|
|
0651e4598b | ||
|
|
6c025520aa | ||
|
|
51f8d0cc21 | ||
|
|
1305cbeb6f | ||
|
|
2d4fde3a2e | ||
|
|
5fd89d50e4 | ||
|
|
605ce5e429 | ||
|
|
085171e7e6 | ||
|
|
aa729bf25b | ||
|
|
aa2ddf9b86 | ||
|
|
c1654ce487 | ||
|
|
33712dc07a | ||
|
|
e5942ac9dd | ||
|
|
aae7a1338c | ||
|
|
6bcde9aab2 | ||
|
|
bb0db5e51e | ||
|
|
16410056bf | ||
|
|
2591ab91c3 | ||
|
|
d5b8002dcb | ||
|
|
821471e1d1 | ||
|
|
2e620ddbcd | ||
|
|
2f7e08856b | ||
|
|
c46a8de4e1 | ||
|
|
2696dc9273 | ||
|
|
0016da7ab3 | ||
|
|
ce3f76994a | ||
|
|
3b6248f602 | ||
|
|
2d9b1dd0ad | ||
|
|
1f0600a23b | ||
|
|
2ecdbb986d | ||
|
|
6f81ea151a | ||
|
|
0c8ffe9b0f | ||
|
|
42699bf408 | ||
|
|
bc51a8df04 | ||
|
|
45da432d60 | ||
|
|
d55e61f120 | ||
|
|
7e6827521a | ||
|
|
1d696dc280 | ||
|
|
f674434a67 | ||
|
|
5b5a597198 | ||
|
|
f80ed64dd9 | ||
|
|
3813966497 | ||
|
|
dce8e49b4f | ||
|
|
78b5944313 | ||
|
|
f233b56cdd | ||
|
|
595902f8a0 | ||
|
|
4f2ee8921d | ||
|
|
58a044be5d | ||
|
|
efe3694f15 | ||
|
|
9f312fe87e | ||
|
|
fb289cf56b | ||
|
|
86f0a7046e | ||
|
|
bff4d18efb | ||
|
|
f19b8885f2 | ||
|
|
f8e00a084a | ||
|
|
6cccdc24bc | ||
|
|
69902c1787 | ||
|
|
1edd38b96e | ||
|
|
e66ba16923 | ||
|
|
f39e6fb617 | ||
|
|
77b627be20 | ||
|
|
5dff01d31b | ||
|
|
d16d585e64 | ||
|
|
c7e6d8afb0 | ||
|
|
92bff2fe2c | ||
|
|
a0dcfbc57b | ||
|
|
1651b2d433 | ||
|
|
06895a7687 | ||
|
|
92a448a071 | ||
|
|
6be6544668 | ||
|
|
951e0d2333 | ||
|
|
f9f02df719 | ||
|
|
76e97dc4df | ||
|
|
e204df0e66 | ||
|
|
1c8bb54703 | ||
|
|
4b69c78751 | ||
|
|
fb0aeb8209 | ||
|
|
54daa0864a | ||
|
|
6fb7c6fb25 | ||
|
|
16985fdadf | ||
|
|
1378ddaefd | ||
|
|
4fd95e4b4d | ||
|
|
e06ae32294 | ||
|
|
7fc3d1f54c | ||
|
|
065889a593 | ||
|
|
d0dd678693 | ||
|
|
0e7cef069b | ||
|
|
e2c8c4557a | ||
|
|
e4c954ff0e | ||
|
|
c13f79e09e | ||
|
|
d7921d649a | ||
|
|
cd4af11efc | ||
|
|
1ebc2f7cc6 | ||
|
|
f4c997062a | ||
|
|
72920ba30a | ||
|
|
0907c08ae5 | ||
|
|
37c8f4eaf3 | ||
|
|
eaaaec9992 | ||
|
|
ccf8561cb3 | ||
|
|
0cc73ebf79 | ||
|
|
33efc3c94f | ||
|
|
4a4fc225ed | ||
|
|
61602a75db | ||
|
|
2f8fc29e9b | ||
|
|
717b226b59 | ||
|
|
2a69f56769 | ||
|
|
ea76933802 | ||
|
|
5413713c95 | ||
|
|
57f462428d | ||
|
|
0b6e7cc60a | ||
|
|
e587adb4e9 | ||
|
|
279d698e1b | ||
|
|
76cfb50b2d | ||
|
|
208291205d | ||
|
|
8d9ab96736 | ||
|
|
734344931f | ||
|
|
2a47a1e48f | ||
|
|
7c4c5c79d2 | ||
|
|
f0b84da5ff | ||
|
|
a3dfd6f927 | ||
|
|
51d05521e9 | ||
|
|
21c8b5c142 | ||
|
|
d82fdcc9e2 | ||
|
|
633213d96f | ||
|
|
b9d749095e | ||
|
|
86b63bb71a | ||
|
|
cbf6be9604 | ||
|
|
229ee9b469 | ||
|
|
2b7a146fa1 | ||
|
|
89d0c7124b | ||
|
|
e8f2580a43 | ||
|
|
6cefe55ac7 | ||
|
|
64e2da15cd | ||
|
|
1c8c810f88 | ||
|
|
c2399ccfca | ||
|
|
a7c5db06d5 | ||
|
|
a4c22acd0a | ||
|
|
0c1f4b5a0d | ||
|
|
63b422ee5e | ||
|
|
26e81a6731 | ||
|
|
de5fc6af3b | ||
|
|
9c2edfd1aa | ||
|
|
810357c014 | ||
|
|
0a7032a400 | ||
|
|
95d3abf95c | ||
|
|
98626093d2 | ||
|
|
47f8d7a345 | ||
|
|
46a63b7087 | ||
|
|
430f393d6f | ||
|
|
febffa4e64 | ||
|
|
d69e2da221 | ||
|
|
ce73ea37fb | ||
|
|
d39d661b18 | ||
|
|
c228bfe882 | ||
|
|
38ce19f738 | ||
|
|
d11849bc0b | ||
|
|
c08518a25b | ||
|
|
e2837084ee | ||
|
|
9f0c003371 | ||
|
|
d615137ca0 | ||
|
|
26b47b6fb5 | ||
|
|
7a01c9c523 | ||
|
|
b17d5c4f5d | ||
|
|
eb90da2e82 | ||
|
|
9d3cd0afb2 | ||
|
|
18024853b6 | ||
|
|
f5d4215b7c | ||
|
|
c26349f4d2 | ||
|
|
f4b11ef6e2 | ||
|
|
0097cf113d | ||
|
|
8fa20b471b | ||
|
|
a03bd3ddb0 | ||
|
|
c108ee1d59 | ||
|
|
a8074a865a | ||
|
|
5f62954864 | ||
|
|
bd903f96ac | ||
|
|
16cac46a09 | ||
|
|
415cd51913 | ||
|
|
e1bfb59619 | ||
|
|
ba8d98cbb7 | ||
|
|
04a1f6e991 | ||
|
|
e4f57bfd7f | ||
|
|
d870468159 | ||
|
|
e8ec09ae83 | ||
|
|
a2c4fed981 | ||
|
|
36406509d9 | ||
|
|
60c43e8703 | ||
|
|
b998e0f30b | ||
|
|
c5adfc51c5 | ||
|
|
c4ad94ce26 | ||
|
|
c1429651eb | ||
|
|
638db5ca5e | ||
|
|
c090569751 | ||
|
|
1efdb2dde4 | ||
|
|
dc69afad14 | ||
|
|
445f5d392b | ||
|
|
23063c3444 | ||
|
|
f57b62575c | ||
|
|
f19b1a521e | ||
|
|
5c67fefb26 | ||
|
|
1d2a556e1b | ||
|
|
04c9b62fb4 | ||
|
|
6be6762e57 | ||
|
|
f1dd2eb3c0 | ||
|
|
fbf3b943cc | ||
|
|
a29a01d304 | ||
|
|
9f0b3afb79 | ||
|
|
86b2f99f8c | ||
|
|
c472ff12d8 | ||
|
|
5173a76ba4 | ||
|
|
1614af3520 | ||
|
|
569a9b3a7f | ||
|
|
4e7e3c65a3 | ||
|
|
0f7a6bfa12 | ||
|
|
4faec5a5ee | ||
|
|
7dbc8ac716 | ||
|
|
c87dd746fa | ||
|
|
372175caf8 | ||
|
|
9047548766 | ||
|
|
d30bca64e3 | ||
|
|
d6047cdc4a | ||
|
|
810241b36e | ||
|
|
661c474739 | ||
|
|
7c33059fad | ||
|
|
9e20883ab3 | ||
|
|
41899d5225 | ||
|
|
f42f459089 | ||
|
|
2381df654f | ||
|
|
7ae816563e | ||
|
|
c56cf3d074 | ||
|
|
01309a34ab | ||
|
|
a62d060554 | ||
|
|
23e3a2eee8 | ||
|
|
d8e0554b97 | ||
|
|
1e8eea4f44 | ||
|
|
44bd5384a9 | ||
|
|
20e19387a2 | ||
|
|
56fed78149 | ||
|
|
56e63078ff | ||
|
|
31ce6bc702 | ||
|
|
c9c5b90da7 | ||
|
|
1f3f84631c | ||
|
|
5de62af604 | ||
|
|
cbddab2fe2 | ||
|
|
f69b6eaabd | ||
|
|
ba363b3a24 | ||
|
|
a6f8e7d860 | ||
|
|
e753244ab6 | ||
|
|
98a7a8b405 | ||
|
|
3135d95fd9 | ||
|
|
8630a8f5ff | ||
|
|
cc3a88e6b3 | ||
|
|
79c4b6bd70 | ||
|
|
d130ee070f | ||
|
|
d0f90b5be7 | ||
|
|
6e080660dc | ||
|
|
31c3a24266 | ||
|
|
613b3b459d | ||
|
|
978521bb81 | ||
|
|
4e94c649f9 | ||
|
|
1a83443e6c | ||
|
|
8bef1c3b3a | ||
|
|
b287c37c65 | ||
|
|
2cac8a9d2e | ||
|
|
9a4cc88426 | ||
|
|
5ddf9ee1bd | ||
|
|
0b3a83f7f4 | ||
|
|
5aa5c98738 | ||
|
|
397ad1bec3 | ||
|
|
7431165f38 | ||
|
|
ee4d4c7fd0 | ||
|
|
ab2f8484e0 | ||
|
|
e900d735bb | ||
|
|
f4de7b684a | ||
|
|
1f8f5450b5 | ||
|
|
d702a68df2 | ||
|
|
e956a14e9e | ||
|
|
98dcc251eb | ||
|
|
5b8641dddf | ||
|
|
8c88abde64 | ||
|
|
23b976a615 | ||
|
|
9edee0e727 | ||
|
|
a909d42b76 | ||
|
|
16637341b9 | ||
|
|
2d71d7e030 | ||
|
|
d259fcfb05 | ||
|
|
704ed557a1 | ||
|
|
8603bd20d0 | ||
|
|
547f12ae63 | ||
|
|
f904e8a1b4 | ||
|
|
100e8af08a | ||
|
|
c11d0f056e | ||
|
|
2453ee576a | ||
|
|
47ae521557 | ||
|
|
936a1833c2 | ||
|
|
f2c9cb6244 | ||
|
|
d3107f8551 | ||
|
|
5e7c70e206 | ||
|
|
38cc68b3e5 | ||
|
|
6732ea5000 | ||
|
|
57ddc77ce7 | ||
|
|
50bad7d62d | ||
|
|
8f7a824e47 | ||
|
|
f11e968708 | ||
|
|
09737dd83b | ||
|
|
d9e3d6e6ed | ||
|
|
795b47a7b5 | ||
|
|
95c6ac0cc8 | ||
|
|
21409cfdda | ||
|
|
88c8d534e7 | ||
|
|
0f3eaeac0a | ||
|
|
344218510d | ||
|
|
16aec06179 | ||
|
|
1e1193590d | ||
|
|
0893c9c2ef | ||
|
|
3245145a41 | ||
|
|
57fc44907f | ||
|
|
7d22bebb6f | ||
|
|
8f2b5fe74d | ||
|
|
f095c67b6a | ||
|
|
5aabf1f715 | ||
|
|
19c5b5d159 | ||
|
|
519571edec | ||
|
|
ac8dfd841f | ||
|
|
2c6165a22b | ||
|
|
28639969ef | ||
|
|
f5fa1dee54 | ||
|
|
51bf9cfacb | ||
|
|
1a716caf5d | ||
|
|
98d4bbf813 | ||
|
|
8c8f74a870 | ||
|
|
bc1b89da26 | ||
|
|
a7fb321ac6 | ||
|
|
8cadb96506 | ||
|
|
297c3b2ed5 | ||
|
|
943532fece | ||
|
|
bd8804019b | ||
|
|
f230300ac5 | ||
|
|
a265e25b79 | ||
|
|
2aa2526f64 | ||
|
|
8d78045e7c | ||
|
|
7aafa6bc64 | ||
|
|
c66aae1652 | ||
|
|
6d66de3805 | ||
|
|
6b219a58db | ||
|
|
eee2023c2a | ||
|
|
c5ed73aab2 | ||
|
|
ea1cd9638c | ||
|
|
d3964d7b1e | ||
|
|
d18c6723a2 | ||
|
|
96c18b26c2 | ||
|
|
ba25baeb97 | ||
|
|
981b517ccf | ||
|
|
922ea924bf | ||
|
|
e0d98923c7 | ||
|
|
8069265373 | ||
|
|
963ee08310 | ||
|
|
02a6fe59fb | ||
|
|
de290f5c4c | ||
|
|
d0623de510 | ||
|
|
73e335ed38 | ||
|
|
b4d46e3988 | ||
|
|
a182f7341e | ||
|
|
68201831a5 | ||
|
|
7f723fbcb8 | ||
|
|
c06851456d | ||
|
|
2f05054dd3 | ||
|
|
f0ce21164c | ||
|
|
44639b11fe | ||
|
|
1c86a99e8f | ||
|
|
8f511fc12f | ||
|
|
59fe455f36 | ||
|
|
b0f47a13e6 | ||
|
|
d6cea50d01 | ||
|
|
40bc7163fb | ||
|
|
080e44d0bf | ||
|
|
7e57cace5d | ||
|
|
7b66e2f219 | ||
|
|
bab3f58003 | ||
|
|
9cc7edfddc | ||
|
|
8d9d528bf5 | ||
|
|
8efd1a8ef6 | ||
|
|
a71bc9c825 | ||
|
|
60d85d598c | ||
|
|
c3099beb6f | ||
|
|
cbb4cb8991 | ||
|
|
b85e9ac38b | ||
|
|
e3710ab972 | ||
|
|
d59751f0f0 | ||
|
|
d6abb2fa03 | ||
|
|
e9fdea90b5 | ||
|
|
44b6584f22 | ||
|
|
78f041ab5b | ||
|
|
7ca89bf87a | ||
|
|
3c114d091b | ||
|
|
e2ef12a8c0 | ||
|
|
bca82719ab | ||
|
|
99da389627 | ||
|
|
f19d667943 | ||
|
|
3e69847616 | ||
|
|
9ac1eebd47 | ||
|
|
e2ff910675 | ||
|
|
f2ed03b919 | ||
|
|
9dde9f0131 | ||
|
|
b1af642d1d | ||
|
|
4a617f25c6 | ||
|
|
6f435f55c8 | ||
|
|
cb475cb884 | ||
|
|
1e1ac6e964 | ||
|
|
e51c449fe6 | ||
|
|
0463665ef1 | ||
|
|
7d748a6f82 | ||
|
|
2b75bd7ce6 | ||
|
|
4a1d5931cb | ||
|
|
811b0f9054 | ||
|
|
450e8eed97 | ||
|
|
b8fbcec1be | ||
|
|
56bc86ffac | ||
|
|
3f79357ef0 | ||
|
|
8a11148f99 | ||
|
|
e371e8b686 | ||
|
|
813732fede | ||
|
|
3670d5b3f6 | ||
|
|
9e2ad7cf68 | ||
|
|
63479c8519 | ||
|
|
5944fcad37 | ||
|
|
e253b371b2 | ||
|
|
0c86f467bc | ||
|
|
1929df4bc2 | ||
|
|
a138221813 | ||
|
|
04e0dfd4bd | ||
|
|
04cde756bc | ||
|
|
c9a57b9a81 | ||
|
|
f46f5ecaf0 | ||
|
|
6e8d7e2776 | ||
|
|
567ed03f88 | ||
|
|
c3fa333140 | ||
|
|
84898b4626 | ||
|
|
538d83fd08 | ||
|
|
8a4630686e | ||
|
|
a9d62d3f35 | ||
|
|
fdcf7870a2 | ||
|
|
5899267c47 | ||
|
|
07b4c246ea | ||
|
|
e99809f29d | ||
|
|
3cd5179f32 | ||
|
|
7404e33a73 | ||
|
|
3aab2171ed | ||
|
|
7645ca0724 | ||
|
|
e30d8391e4 | ||
|
|
8cd8ef03eb | ||
|
|
bbb6b357c7 | ||
|
|
36ea32640f | ||
|
|
141a00d642 | ||
|
|
3860edc5d9 | ||
|
|
7d01859ef1 | ||
|
|
63b23e786a | ||
|
|
4999796c15 | ||
|
|
34b3f7b7aa | ||
|
|
27e3c0fe9b | ||
|
|
9bdd1596ce | ||
|
|
d151562bdd | ||
|
|
346500e70b | ||
|
|
a434a8f778 | ||
|
|
9eb47d951a | ||
|
|
51c58a56ba | ||
|
|
3fc33f6273 | ||
|
|
2e32db5b99 | ||
|
|
c1ce6e01f7 | ||
|
|
1c3c80dc1f | ||
|
|
d1d653d895 | ||
|
|
73c8437485 | ||
|
|
e588b02b17 | ||
|
|
1a62711d01 | ||
|
|
5b02881582 | ||
|
|
a133187a8c | ||
|
|
80ce222ca6 | ||
|
|
770a94edef | ||
|
|
2864e8432a | ||
|
|
21a295c272 | ||
|
|
96c68afe69 | ||
|
|
664dd88e31 | ||
|
|
69779b4ed6 | ||
|
|
01a172c969 | ||
|
|
08ca40ea91 | ||
|
|
dd97f4920c | ||
|
|
2951169481 | ||
|
|
d3e668418f | ||
|
|
52d0e1bbe3 | ||
|
|
5d32ccfc31 | ||
|
|
3cf619de55 | ||
|
|
2559983e7a | ||
|
|
026f99178e | ||
|
|
9f70fc3e7a | ||
|
|
6012dc9ab4 | ||
|
|
85050aa2e6 | ||
|
|
ff486a72a7 | ||
|
|
678341275b | ||
|
|
6f01b6ebb6 | ||
|
|
61c5a51604 | ||
|
|
02bfd8a9a5 | ||
|
|
3c24052cf1 | ||
|
|
f72a905eb3 | ||
|
|
941d5e147a | ||
|
|
ee2b828b9a | ||
|
|
5bb8856655 | ||
|
|
1c0c59d4a0 | ||
|
|
b1adaa9881 | ||
|
|
48e8d0ebef | ||
|
|
ce00979152 | ||
|
|
db4a6cfbf9 | ||
|
|
29a1ea795a | ||
|
|
8a06ca84c7 | ||
|
|
153f753bde | ||
|
|
eafd079868 | ||
|
|
0c6919ec72 | ||
|
|
197a5c3721 | ||
|
|
68742e1d87 | ||
|
|
1e8493196e | ||
|
|
58e6c84f5a | ||
|
|
75a4525e5f | ||
|
|
6ccb2e241b | ||
|
|
bed134a4aa | ||
|
|
b2d3a86ec0 | ||
|
|
13d82e32bd | ||
|
|
2161a73f2b | ||
|
|
e00997b004 | ||
|
|
0415cf2350 | ||
|
|
3bafd0749b | ||
|
|
f733882b55 | ||
|
|
dc22360c34 | ||
|
|
1f1b50707c | ||
|
|
24924128e3 | ||
|
|
c54cd71800 | ||
|
|
43e9b29e50 | ||
|
|
b55ea58705 | ||
|
|
4098970db2 | ||
|
|
314e15001f | ||
|
|
f499b393d1 | ||
|
|
6c30f41443 | ||
|
|
1acb73f970 | ||
|
|
09a13244c8 | ||
|
|
419db8baa1 | ||
|
|
9fc4161f5e | ||
|
|
25d6916b3a | ||
|
|
0b2eb6501c | ||
|
|
fd1cabe464 | ||
|
|
a844d7ab81 | ||
|
|
47d3968092 | ||
|
|
7800173eb1 | ||
|
|
b4218aa0f8 | ||
|
|
8a3a8177d6 | ||
|
|
e5f2f8ce7a | ||
|
|
75765bfad5 | ||
|
|
9bd9738da0 | ||
|
|
bd5f903f28 | ||
|
|
06e437fd98 | ||
|
|
1bd4f54fa6 | ||
|
|
11cc2903e4 | ||
|
|
b124e3e8e7 | ||
|
|
ffd5f3469f | ||
|
|
0f0e5ddf5f | ||
|
|
1f110702a1 | ||
|
|
4ccbe4b5f2 | ||
|
|
40638a75b3 | ||
|
|
c8dd9cc99d | ||
|
|
4bbe57cebf | ||
|
|
55b6130055 | ||
|
|
ae3ea156ea | ||
|
|
77165fdf85 | ||
|
|
65ac626c58 | ||
|
|
cd0b3f9695 | ||
|
|
cef1e4354b | ||
|
|
0201c8db21 | ||
|
|
9e3f3e8cff | ||
|
|
aa07c57654 | ||
|
|
a73d89e9c7 | ||
|
|
cb8e7caf7c | ||
|
|
b3fd0005dd | ||
|
|
7b478f9dec | ||
|
|
c85efef312 | ||
|
|
455a7c0787 | ||
|
|
674c326d7c | ||
|
|
061a9897fe | ||
|
|
d2d1c9c560 | ||
|
|
b6e19e5953 | ||
|
|
f219dcd59b | ||
|
|
dea7fde8b7 | ||
|
|
5390e29d42 | ||
|
|
9f6434dcde | ||
|
|
dac9a7f99d | ||
|
|
3ca9533f38 | ||
|
|
7eec036d9a | ||
|
|
e6b37b4aff | ||
|
|
8cf4c52068 | ||
|
|
74532c23a3 | ||
|
|
b308159be5 | ||
|
|
162995fedd | ||
|
|
8b41362a0a | ||
|
|
1b1c70108a | ||
|
|
d7e72a09e0 | ||
|
|
2201890d7a | ||
|
|
6100ed4bb3 | ||
|
|
1afe201ae8 | ||
|
|
cd2b99032f | ||
|
|
9acf89fef6 | ||
|
|
9ea42fb26e | ||
|
|
da2569827e | ||
|
|
35959a31d7 | ||
|
|
ec2463c905 | ||
|
|
0012917f69 | ||
|
|
9e450911fa | ||
|
|
068d20bc31 | ||
|
|
a99fbe67b9 | ||
|
|
adbed11ed4 | ||
|
|
8ab1c5c6e8 | ||
|
|
a770009fcc | ||
|
|
598e6042d1 | ||
|
|
e09814dc93 | ||
|
|
b272fb3605 | ||
|
|
f94b7364b9 | ||
|
|
7abec071b5 | ||
|
|
b7eb8c8921 | ||
|
|
ae7c50185d | ||
|
|
9f2e7edaeb | ||
|
|
fd52de0c6b | ||
|
|
f675cb887e | ||
|
|
73a16b827f | ||
|
|
72879db40e | ||
|
|
d3aa0c3a28 | ||
|
|
31de9a1b80 | ||
|
|
227bfe62dd | ||
|
|
95dfdc6cc4 | ||
|
|
5916ff63c4 | ||
|
|
1ab80aa92c | ||
|
|
4f4d876616 | ||
|
|
f443bd3baf | ||
|
|
1219b65f21 | ||
|
|
071794ec65 | ||
|
|
d22e4ad85b | ||
|
|
983806b0c1 | ||
|
|
02af5beb8a | ||
|
|
123e7f7fc3 | ||
|
|
168460f02c | ||
|
|
a64f60c849 | ||
|
|
1a599117d8 | ||
|
|
b160123e39 | ||
|
|
5981588565 | ||
|
|
8bbe76af3a | ||
|
|
4ca6821e8f | ||
|
|
7111a1eb9f | ||
|
|
ae00bbdc91 | ||
|
|
e71e07d9fb | ||
|
|
0184df7020 | ||
|
|
1cbae6e9ba | ||
|
|
159f89e2b8 | ||
|
|
4b120b68ae | ||
|
|
186b225d9d | ||
|
|
4cbf4888ea | ||
|
|
e31f2b3d03 | ||
|
|
62da1db62a | ||
|
|
3bc28fcc6b | ||
|
|
3c05fa46c6 | ||
|
|
ba6e330fd3 | ||
|
|
6037b3cae9 | ||
|
|
fafb03fa6d | ||
|
|
2f9acd1838 | ||
|
|
aaf829bfb1 | ||
|
|
b994a0ab13 | ||
|
|
bb205d940d | ||
|
|
ef7369ce90 | ||
|
|
40e4c227db | ||
|
|
ea54b21e78 | ||
|
|
9cbf4b087c | ||
|
|
1200a34e10 | ||
|
|
9c7e2a6c6f | ||
|
|
34e921f6fe | ||
|
|
c3be0f593d | ||
|
|
c68703c9f4 | ||
|
|
9a21728b0a | ||
|
|
3de36e9348 | ||
|
|
4afb39bc24 | ||
|
|
7ffa62db18 | ||
|
|
0d07db1234 | ||
|
|
d19ed6716d | ||
|
|
99b6e928d4 | ||
|
|
57cd3f72e9 | ||
|
|
111fc127fe | ||
|
|
6003ec3f25 | ||
|
|
8877a67724 | ||
|
|
75fff1db64 | ||
|
|
28d7191c27 | ||
|
|
43271ba8e8 | ||
|
|
63a9f3fcd4 | ||
|
|
4cf59ce734 | ||
|
|
7395472dde | ||
|
|
9108b25da9 | ||
|
|
4d366c68b7 | ||
|
|
ded1e7679e | ||
|
|
c7edd8e570 | ||
|
|
75108a56f6 | ||
|
|
3e1f70fe02 | ||
|
|
125fc5e520 | ||
|
|
6793ffc1d6 | ||
|
|
f4fcc5fd28 | ||
|
|
4de41aa655 | ||
|
|
404a880bd4 | ||
|
|
092d2dc7b2 | ||
|
|
093e554211 | ||
|
|
d0696b0aa6 | ||
|
|
66d7746bb3 | ||
|
|
e9bff78814 | ||
|
|
57b6f2966d | ||
|
|
d79493e5ee | ||
|
|
78842ce0d6 | ||
|
|
5420bcce2d | ||
|
|
56a2e2075c | ||
|
|
ed117baa4f | ||
|
|
f26446290b | ||
|
|
7e1cb3237a | ||
|
|
f67783d7e6 | ||
|
|
1c6d85f7bb | ||
|
|
4a1da44f91 | ||
|
|
080b6899d2 | ||
|
|
c01ec54fde | ||
|
|
b0c2ab93fa | ||
|
|
9b7fe2a4a1 | ||
|
|
c58b7d9c2f | ||
|
|
ceff9b0b2e | ||
|
|
3dc8639f8a | ||
|
|
dcde089b4e | ||
|
|
2145a7bdcc | ||
|
|
52ae134f84 | ||
|
|
0d6dd0cc6a | ||
|
|
1f918159ed | ||
|
|
6868f888b2 | ||
|
|
87cd545a1e | ||
|
|
12f9437e22 | ||
|
|
bb0c8bfea8 | ||
|
|
e6e8298904 | ||
|
|
0f0848e4f4 | ||
|
|
a1fb5c7337 | ||
|
|
8a411c2bca | ||
|
|
0047dc10a2 | ||
|
|
263cdef8a0 | ||
|
|
d4ca54253a | ||
|
|
5bb7b28e15 | ||
|
|
1409dfe76b | ||
|
|
f1559e1d56 | ||
|
|
ffd05e65ed | ||
|
|
0889856d61 | ||
|
|
d6eede9e08 | ||
|
|
213e09644f | ||
|
|
6bfc9af8c9 | ||
|
|
3487f1b9cd | ||
|
|
791294d17b | ||
|
|
8e700619b7 | ||
|
|
58c6f8c7f5 | ||
|
|
40414b3446 | ||
|
|
b7a157401e | ||
|
|
7aa58c30bf | ||
|
|
8e9bffa986 | ||
|
|
ce4d87acd4 | ||
|
|
21acc2af43 | ||
|
|
00669427df | ||
|
|
d39ebf3ff2 | ||
|
|
6498bc6d31 | ||
|
|
a967dcbe20 | ||
|
|
8498bc97dd | ||
|
|
e2ea940673 | ||
|
|
2bc5585ff0 | ||
|
|
bb728a572a | ||
|
|
36d1390e67 | ||
|
|
599e0aef45 | ||
|
|
91f7619cc9 | ||
|
|
c4dc6bef24 | ||
|
|
646966e973 | ||
|
|
a5abe5d95c | ||
|
|
1cbc5fa6cb | ||
|
|
f7a5748fd3 | ||
|
|
0e94b931a2 | ||
|
|
5e58eb97b1 | ||
|
|
3a15ea3ea5 | ||
|
|
b87ac4d840 | ||
|
|
a927dda9bb | ||
|
|
dd11d45847 | ||
|
|
b55551f900 | ||
|
|
96f91428c6 | ||
|
|
b732f28c00 | ||
|
|
a82c1dc6d9 | ||
|
|
2730e90186 | ||
|
|
e4d6d9d7c8 | ||
|
|
a1079e9fd6 | ||
|
|
b66bb6b71f | ||
|
|
b60114533f | ||
|
|
c41cea8b18 | ||
|
|
0c7650373c | ||
|
|
0571013709 | ||
|
|
d2c9276fcd | ||
|
|
0fc7bd1573 | ||
|
|
b4f1988c4b | ||
|
|
4b8f8fac96 | ||
|
|
3b2fc033d1 | ||
|
|
ac59d9f3a4 | ||
|
|
8f27ce4d8b | ||
|
|
89b0c71fa9 | ||
|
|
f6a783ad2e | ||
|
|
ccc8f5db02 | ||
|
|
20fdb88a1c | ||
|
|
f29901097f | ||
|
|
758446c80d | ||
|
|
f7aedc5fc4 | ||
|
|
840a817ed2 | ||
|
|
79c923ba2c | ||
|
|
5dc577c064 | ||
|
|
c6d1a94a9f | ||
|
|
0656045d02 | ||
|
|
c85ae23c73 | ||
|
|
b3bf665764 | ||
|
|
0887887e23 | ||
|
|
ac71d853be | ||
|
|
6649b8e0ca | ||
|
|
56b5c192a0 | ||
|
|
b2f0b6e44e | ||
|
|
3d9f3c163b | ||
|
|
19547d5148 | ||
|
|
972ffd3151 | ||
|
|
2ed412fa38 | ||
|
|
df4dcf2ece | ||
|
|
f7a4b4ab91 | ||
|
|
611cf0b3c6 | ||
|
|
58a8f2f539 | ||
|
|
1882b9687b | ||
|
|
6de0454b42 | ||
|
|
16e3c48bb0 | ||
|
|
8ce5f680f2 | ||
|
|
2fd8f9ec8a | ||
|
|
fe642d7648 | ||
|
|
a128b5b2cb | ||
|
|
466128de00 | ||
|
|
22e98a5b6a | ||
|
|
f18a3f36a7 | ||
|
|
7cad33563c | ||
|
|
e1ab6bc006 | ||
|
|
24a88545d9 | ||
|
|
422e7b9d70 | ||
|
|
d1dd9d5327 | ||
|
|
9a56a608ee | ||
|
|
c76957565c | ||
|
|
200ee6f108 | ||
|
|
bcd9b9331a | ||
|
|
345ba07f1d | ||
|
|
9e2490be4c | ||
|
|
3f75e2b69e | ||
|
|
744302add0 | ||
|
|
f5556225a4 | ||
|
|
ad3c7855e2 | ||
|
|
7512a55aa3 | ||
|
|
9bd2f1f9af | ||
|
|
b9815cf048 | ||
|
|
fe00cddde2 | ||
|
|
1a7d172dc7 | ||
|
|
006c2546f2 | ||
|
|
4ce006fb6e | ||
|
|
e2e557e273 | ||
|
|
a5f470eb10 | ||
|
|
4070c1d80b | ||
|
|
f8b59251c4 | ||
|
|
643aa4c8c4 | ||
|
|
ffe29a92f4 | ||
|
|
e94d723667 | ||
|
|
a9337395a2 | ||
|
|
562a9f4991 | ||
|
|
b257c56e51 | ||
|
|
1488df3395 | ||
|
|
b918e3ff81 | ||
|
|
23b04ca6d5 | ||
|
|
5d5918a74d | ||
|
|
413d97b33a | ||
|
|
790fd90f40 | ||
|
|
c0890be77d | ||
|
|
5a4b24613b | ||
|
|
45dc3486fe | ||
|
|
5a353fa8cf | ||
|
|
c84d227da9 | ||
|
|
b2d4ca1546 | ||
|
|
2aae6b120c | ||
|
|
9f09b8eed1 | ||
|
|
2bb8120d98 | ||
|
|
c1e97392be | ||
|
|
4e99e09bb3 | ||
|
|
1607a01870 | ||
|
|
e8219952c6 | ||
|
|
544b537334 | ||
|
|
83c13a1fe3 | ||
|
|
2546dafece | ||
|
|
02c04b1736 | ||
|
|
5360ab0b59 | ||
|
|
b615eca964 | ||
|
|
22a42c0b01 | ||
|
|
c63624ed45 | ||
|
|
211d312406 | ||
|
|
ef55e74e08 | ||
|
|
612669d343 | ||
|
|
ba63ac8c18 | ||
|
|
3fe49163bd | ||
|
|
a5bd3ddb28 | ||
|
|
3df0ea34e5 | ||
|
|
436acf3489 | ||
|
|
823128049b | ||
|
|
1dfa2591b3 | ||
|
|
6f2dd30e38 | ||
|
|
431d0f85cf | ||
|
|
ad71f5a706 | ||
|
|
d0f2f3b816 | ||
|
|
eac2796ce3 | ||
|
|
ee36257469 | ||
|
|
bbf0bada33 | ||
|
|
3730b4f039 | ||
|
|
25ff2efc0a | ||
|
|
9393fe26f6 | ||
|
|
b48ffc14a4 | ||
|
|
3268531bc9 | ||
|
|
8bd59ec936 | ||
|
|
1235f0a24a | ||
|
|
4fb73d1145 | ||
|
|
f9ceefb0fe | ||
|
|
6bcc3fd216 | ||
|
|
6a497e1d06 | ||
|
|
e9b9b0aefa | ||
|
|
ec24342b2b | ||
|
|
230b24944c | ||
|
|
cadd92d69f | ||
|
|
41076d1de3 | ||
|
|
d561cb47a7 | ||
|
|
699fe8e711 | ||
|
|
da2d33f1f1 | ||
|
|
af4734fd15 | ||
|
|
a3a74672a0 | ||
|
|
c11e68305f | ||
|
|
dd8cc8b0ba | ||
|
|
f6f0415b83 | ||
|
|
c92dc37464 | ||
|
|
e3f20d3e13 | ||
|
|
b438812324 | ||
|
|
bc15e3700e | ||
|
|
cf5ebf2059 | ||
|
|
9c20e72de3 | ||
|
|
79209598f5 | ||
|
|
5488d0b53a | ||
|
|
e4f84ee1c6 | ||
|
|
8e0dcd20b3 | ||
|
|
1d3e3d8c04 | ||
|
|
bc628f8d49 | ||
|
|
edd13fcc1c | ||
|
|
6a031347e5 | ||
|
|
bc14c6ee20 | ||
|
|
476f25cd81 | ||
|
|
c9d5a08ed8 | ||
|
|
f487ddbdfa | ||
|
|
d8fd1699b1 | ||
|
|
c286ffc88d | ||
|
|
1289782f06 | ||
|
|
2249f5571e | ||
|
|
e76446958c | ||
|
|
de37de912b | ||
|
|
df1a3a141b | ||
|
|
78dec87a46 | ||
|
|
ded0a3bb3d | ||
|
|
83174f2a1f | ||
|
|
c2e84ee9cc | ||
|
|
2711cb1672 | ||
|
|
ab0ba8a9d0 | ||
|
|
bd3fd3bfda | ||
|
|
260c115908 | ||
|
|
9d97201ede | ||
|
|
037b84f214 | ||
|
|
e37ee419c6 | ||
|
|
e3488fcae2 | ||
|
|
d5d5865615 | ||
|
|
29ef7d31e4 | ||
|
|
af83192d79 | ||
|
|
6952732b6c | ||
|
|
b97e5d8c2a | ||
|
|
572b077dbf | ||
|
|
72e519a4bd | ||
|
|
635e01fe74 | ||
|
|
0e72c98043 | ||
|
|
f13906f408 | ||
|
|
22ddd4b989 | ||
|
|
bb827341ed | ||
|
|
64c54703d4 | ||
|
|
1c3197b8d8 | ||
|
|
fd2292f13a | ||
|
|
4912cff65d | ||
|
|
4639843839 | ||
|
|
e29708ee57 | ||
|
|
f03a6c5325 | ||
|
|
6c3d584e67 | ||
|
|
12f4683883 | ||
|
|
874d6727e4 | ||
|
|
a9940192fb | ||
|
|
34b5418359 | ||
|
|
cbbee1b385 | ||
|
|
92a44db11c | ||
|
|
d05d42751c | ||
|
|
d32fe0f3f6 | ||
|
|
e5422db4b2 | ||
|
|
9d7b64a259 | ||
|
|
5e293bd97a | ||
|
|
4a502d9802 | ||
|
|
d384cdd397 | ||
|
|
32544b6108 | ||
|
|
39f522a13a | ||
|
|
d7d2bebf99 | ||
|
|
9427f15bef | ||
|
|
87fbc6f756 | ||
|
|
a48daa60e5 | ||
|
|
afdbbac75c | ||
|
|
e33fe14f5b | ||
|
|
e895da2ec3 | ||
|
|
e1a67b5285 | ||
|
|
a291f07e1a | ||
|
|
5d9100fa2f | ||
|
|
4faadff0a0 | ||
|
|
5d48733596 | ||
|
|
0f0b42861b | ||
|
|
209db68b28 | ||
|
|
cb4c59495e | ||
|
|
40779749ac | ||
|
|
b3cf8613b1 | ||
|
|
3fdba04924 | ||
|
|
f5f3ffac59 | ||
|
|
a38b99a188 | ||
|
|
aa31028b2c | ||
|
|
0787d69747 | ||
|
|
bae00aa8d7 | ||
|
|
388bb389e6 | ||
|
|
7e39c7e6f4 | ||
|
|
3eff8f94d2 | ||
|
|
469a4bbd35 | ||
|
|
d2ee5f2407 | ||
|
|
c264e641ea | ||
|
|
4aa0dc578b | ||
|
|
064ce6b6c0 | ||
|
|
7893d85394 | ||
|
|
5bafcb437b | ||
|
|
1530242551 | ||
|
|
eddb84cfc0 | ||
|
|
7e42c65bb6 | ||
|
|
1e6e87cb74 | ||
|
|
0c6a6e0250 | ||
|
|
1653244c69 | ||
|
|
d54e64b3c8 | ||
|
|
ec6651087d | ||
|
|
4d4b8c238d | ||
|
|
56d2b91108 | ||
|
|
89d6c959b2 | ||
|
|
76ef39fc50 | ||
|
|
af2c73772c | ||
|
|
9df0e2d1f1 | ||
|
|
5b7bbf8853 | ||
|
|
4c650057a0 | ||
|
|
2833c76f22 | ||
|
|
67feef5589 | ||
|
|
78daa50ffc | ||
|
|
87e4ea2906 | ||
|
|
c56b17029a | ||
|
|
c929684e33 | ||
|
|
f57227a148 | ||
|
|
634f707f2b | ||
|
|
406e632bd1 | ||
|
|
49f78a427b | ||
|
|
637bf3c6d9 | ||
|
|
8302c2f33b | ||
|
|
d07cc2026b | ||
|
|
4a7966c773 | ||
|
|
9b3c24b99b | ||
|
|
30bce6c14c | ||
|
|
e5512c5d57 | ||
|
|
afc571aedc | ||
|
|
ad360a62b0 | ||
|
|
3cf12d7b11 | ||
|
|
bb254d146b | ||
|
|
291ba837f2 | ||
|
|
01c631af95 | ||
|
|
4fcd4a4bd0 | ||
|
|
2346779d6b | ||
|
|
afc1a74a6c | ||
|
|
ad0eade471 | ||
|
|
28c187bcd7 | ||
|
|
91bb3aaf06 | ||
|
|
5e7bdf1b97 | ||
|
|
570453f271 | ||
|
|
ef6282fc45 | ||
|
|
e3e470bb69 | ||
|
|
67179dbc23 | ||
|
|
a5ffa735db | ||
|
|
5ee0804631 | ||
|
|
25b72fc4cd | ||
|
|
d179ec5f8b | ||
|
|
2a9e8b52de | ||
|
|
2c77562b13 | ||
|
|
98b3775297 | ||
|
|
b488df6cfe | ||
|
|
f4dfd6e30f | ||
|
|
a6e8ed15c4 | ||
|
|
de5da50910 | ||
|
|
ea2976e6d5 | ||
|
|
77d6036cd5 | ||
|
|
ccc318e807 | ||
|
|
4c8efd694c | ||
|
|
d22d11b5ff | ||
|
|
e9bab6d028 | ||
|
|
f52c09f924 | ||
|
|
118d8bccc2 | ||
|
|
6828d549e8 | ||
|
|
3fd134be03 | ||
|
|
ca7c1f89dc | ||
|
|
ca978b3d21 | ||
|
|
c1d430e61a | ||
|
|
38a85502ed | ||
|
|
241414028d | ||
|
|
29c10fbf6e | ||
|
|
4a4d72f917 | ||
|
|
b3cc9c0567 | ||
|
|
2e3352fd05 | ||
|
|
4c721e3a2f | ||
|
|
8d8ea21c69 | ||
|
|
40a7975640 | ||
|
|
cb46397dfb | ||
|
|
134904c886 | ||
|
|
bd516e3429 | ||
|
|
5efb24dd2b | ||
|
|
946498cfbc | ||
|
|
6b20863918 | ||
|
|
d306585a3f | ||
|
|
544b927933 | ||
|
|
dc94010fa5 | ||
|
|
397e8dd9d5 | ||
|
|
2b415b7af7 | ||
|
|
5d755d0a4e | ||
|
|
bade46aae5 | ||
|
|
41fbaeb3b1 | ||
|
|
8bc0adb9ba | ||
|
|
1763d0e7a2 | ||
|
|
f569c1ba28 | ||
|
|
ccd70f59ee | ||
|
|
a4969ebe06 | ||
|
|
a6ad29aa34 | ||
|
|
52eb3fe274 | ||
|
|
09e2ac5e46 | ||
|
|
df4ea0c76c | ||
|
|
718f60accb | ||
|
|
aeb5ad3ce1 | ||
|
|
2808395481 | ||
|
|
6e37c20030 | ||
|
|
3de3d76a36 | ||
|
|
07d5a86a7c | ||
|
|
ab1474ef66 | ||
|
|
918ab77baa | ||
|
|
735b1fadc3 | ||
|
|
3c531b735b | ||
|
|
f10a7e2e46 | ||
|
|
bd8177177a | ||
|
|
0302927f56 | ||
|
|
bb6842ba35 | ||
|
|
b23c8633fa | ||
|
|
b588d7f35f | ||
|
|
018d8b57f6 | ||
|
|
1987db663b | ||
|
|
a6d1ad741d | ||
|
|
e979c782d3 | ||
|
|
9e1531c1e1 | ||
|
|
0a66e4cbbb | ||
|
|
91acfe6852 | ||
|
|
b7e6bf9671 | ||
|
|
da0ea4161a | ||
|
|
7ad3015f5b | ||
|
|
f0b572da05 | ||
|
|
6d416cf674 | ||
|
|
b742f622ab | ||
|
|
02a6f16b52 | ||
|
|
294fd7df96 | ||
|
|
17c6900f83 | ||
|
|
0faa968cc3 | ||
|
|
bc784d3625 | ||
|
|
53379dfd0c | ||
|
|
76d326a2a2 | ||
|
|
c21c6b8c4b | ||
|
|
ec645ca262 | ||
|
|
ae0b0dab9f | ||
|
|
5466a5b41f | ||
|
|
9b392a683d | ||
|
|
0fa65cf329 | ||
|
|
fdd0149e71 | ||
|
|
e19a95b271 | ||
|
|
ef39274973 | ||
|
|
a7f68dcc01 | ||
|
|
1428b34299 | ||
|
|
97619e27a2 | ||
|
|
dd6cc0e6ac | ||
|
|
a939c75956 | ||
|
|
17e4b53926 | ||
|
|
a82b3680dc | ||
|
|
287342dab1 | ||
|
|
e28429ee73 | ||
|
|
49bbf3c876 | ||
|
|
5e5506f833 | ||
|
|
e06523361d | ||
|
|
ebec00138b | ||
|
|
8daa3c6834 | ||
|
|
0d418a8d58 | ||
|
|
4c66dad8c1 | ||
|
|
b1f7cca89e | ||
|
|
f90d33ca12 | ||
|
|
78c755dc48 | ||
|
|
f230170157 | ||
|
|
ced8aa8c9e | ||
|
|
77d54251f0 | ||
|
|
1632f72cbe | ||
|
|
8129b9bc46 | ||
|
|
835087dd04 | ||
|
|
4523053e6f | ||
|
|
8407f4cb24 | ||
|
|
49d244c065 | ||
|
|
3466d9c845 | ||
|
|
93d22dec35 | ||
|
|
d560ddac25 | ||
|
|
2d981bb133 | ||
|
|
d8434baa03 | ||
|
|
8f7780a4f6 | ||
|
|
2e526a664a | ||
|
|
79b79f329e | ||
|
|
287eaab3b2 | ||
|
|
a97757736b | ||
|
|
327d4b6e9e | ||
|
|
8af651be39 | ||
|
|
187bd1b8b2 | ||
|
|
4e5694fd05 | ||
|
|
82c24edcf6 | ||
|
|
ed138d794a | ||
|
|
0476a51cba | ||
|
|
c5aad69f2a | ||
|
|
5b0006476a | ||
|
|
a44238f2ef | ||
|
|
83808076e3 | ||
|
|
9660ea1bff | ||
|
|
4a9d676362 | ||
|
|
f041f128f5 | ||
|
|
e4572e5def | ||
|
|
442fa1bd46 | ||
|
|
744e66bb08 | ||
|
|
d231d68a8b | ||
|
|
01f34d0b0b | ||
|
|
9a0a24f90b | ||
|
|
430e6ac9b6 | ||
|
|
467520e7a4 | ||
|
|
5a314a5288 | ||
|
|
9989e7f4e3 | ||
|
|
31510cb437 | ||
|
|
61c9b563c2 | ||
|
|
864b9a2202 | ||
|
|
1538336836 | ||
|
|
22de5a755f | ||
|
|
355eb6d29a | ||
|
|
b8d34e0db3 | ||
|
|
e61cac687d | ||
|
|
7fbbfed8c6 | ||
|
|
c3268f4e50 | ||
|
|
34951f1999 | ||
|
|
3f52336e6c | ||
|
|
7ca8fc3b17 | ||
|
|
5289dd600b | ||
|
|
bf6529f2ce | ||
|
|
0700612249 | ||
|
|
06c005b7b0 | ||
|
|
4f6fda558c | ||
|
|
9f70b034e1 | ||
|
|
7cdb1e5e40 | ||
|
|
5f1ceebc7f | ||
|
|
1b11b000c7 | ||
|
|
83f052930a | ||
|
|
fdd8e333c1 | ||
|
|
dad1eec842 | ||
|
|
b0cde860ae | ||
|
|
e05dfb0887 | ||
|
|
dde095fab8 | ||
|
|
4a059914a9 | ||
|
|
58b6f8db48 | ||
|
|
9a777b9e1c | ||
|
|
da55e96f53 | ||
|
|
dc8f8ce4c0 | ||
|
|
f5cc77cea0 | ||
|
|
39623a7400 | ||
|
|
ae1de3a8d3 | ||
|
|
1b8a216ddf | ||
|
|
b3ad759a0a | ||
|
|
9e554999ce | ||
|
|
b34d92b051 | ||
|
|
d39ece1870 | ||
|
|
fe2d715ff1 | ||
|
|
27b306701f | ||
|
|
68837079aa | ||
|
|
c98b202eb4 | ||
|
|
587a7f6634 | ||
|
|
84e5170c9c | ||
|
|
130e412b64 | ||
|
|
0bbdca5b8b | ||
|
|
77a7244804 | ||
|
|
3e01376e08 | ||
|
|
1f92f8a9d8 | ||
|
|
8668639ae2 | ||
|
|
93fd473b8f | ||
|
|
61ad543c3e | ||
|
|
7f7504b3f5 | ||
|
|
37f599b1a1 | ||
|
|
8c2e15aed5 | ||
|
|
de71db6d42 | ||
|
|
b180b39152 | ||
|
|
24594c747e | ||
|
|
b0f2224719 | ||
|
|
749276072f | ||
|
|
f54f3d0fb7 | ||
|
|
bf1f1c73e3 | ||
|
|
b6bc6ec246 | ||
|
|
acfa95d4a8 | ||
|
|
628f830583 | ||
|
|
aa3b5aba41 | ||
|
|
639de21757 | ||
|
|
3242ddf7b5 | ||
|
|
bd1104046b | ||
|
|
81b5c4a5fd | ||
|
|
7c4eb0fbeb | ||
|
|
2d624218bf | ||
|
|
b31680990e | ||
|
|
b10ccb83e1 | ||
|
|
0497875ff3 | ||
|
|
37dc495b9d | ||
|
|
2ff4996d05 | ||
|
|
77656c672c | ||
|
|
ea5e4790bd | ||
|
|
86681c4bb0 | ||
|
|
e867768ee6 | ||
|
|
0c7f5c3ca4 | ||
|
|
e7e2ab1070 | ||
|
|
29352af369 | ||
|
|
68214bd904 | ||
|
|
bcf3fcd673 | ||
|
|
9dcf127fa5 | ||
|
|
b8b06e3e10 | ||
|
|
322b2594e0 | ||
|
|
0835f1ba3b | ||
|
|
a084495d7e | ||
|
|
fa1d4dbcfd | ||
|
|
2b2cfdac19 | ||
|
|
99744f8f8f | ||
|
|
f5fe849238 | ||
|
|
a5a9805a91 | ||
|
|
645c76a9a5 | ||
|
|
fecb2d6f0d | ||
|
|
64690d3a97 | ||
|
|
01640f44cf | ||
|
|
e37d6a9840 | ||
|
|
982ee5c699 | ||
|
|
b7b8548559 | ||
|
|
00a8cc8325 | ||
|
|
33fbb3a7eb | ||
|
|
bd6121596f | ||
|
|
702b3d1618 | ||
|
|
9d4ef94350 | ||
|
|
6c95fb3562 | ||
|
|
16b78ee629 | ||
|
|
19e008876b | ||
|
|
f2ee988105 | ||
|
|
1385050e26 | ||
|
|
03c1b110a5 | ||
|
|
cc805c6162 | ||
|
|
e01579231d | ||
|
|
34030deca9 | ||
|
|
6b26e3f2d7 | ||
|
|
d286c97753 | ||
|
|
d951f6dfe7 | ||
|
|
a23d592472 | ||
|
|
36161284e2 | ||
|
|
38f355d87b | ||
|
|
324eac1aa5 | ||
|
|
bdda4d6030 | ||
|
|
5ee1a4bc8a | ||
|
|
2dea780fbd | ||
|
|
b98e8301d5 | ||
|
|
ccd3e8bbf3 | ||
|
|
4373153800 | ||
|
|
73cfd8f325 | ||
|
|
ec384302db | ||
|
|
0a96c032b9 | ||
|
|
61e6d2e38c | ||
|
|
ea4010d704 | ||
|
|
486fff597c | ||
|
|
1e3dcbba81 | ||
|
|
f0328f8e36 | ||
|
|
895fb98456 | ||
|
|
20c708bf6d | ||
|
|
9d0c9c4bb1 | ||
|
|
2d2326a76d | ||
|
|
1ec0272303 | ||
|
|
2c81c851b2 | ||
|
|
846c644e84 | ||
|
|
13d472bd8c | ||
|
|
b71d3fe7ab | ||
|
|
847abb6f8f | ||
|
|
dda47c9466 | ||
|
|
2924622157 | ||
|
|
bda5f9a556 | ||
|
|
b1ca608bac | ||
|
|
e8efdef8de | ||
|
|
98f1c1fe87 | ||
|
|
50b18a3c10 | ||
|
|
699297520a | ||
|
|
4bb76ef0c7 | ||
|
|
ddd7caf38e | ||
|
|
10e03e695b | ||
|
|
07200f445a | ||
|
|
08a65c2282 | ||
|
|
167f8fe325 | ||
|
|
57983423c3 | ||
|
|
7bebb3e128 | ||
|
|
939fbe5567 | ||
|
|
61f81a0719 | ||
|
|
f27defc639 | ||
|
|
6a685571df | ||
|
|
87a0408c64 | ||
|
|
2b5acad4a9 | ||
|
|
655ce53383 | ||
|
|
fea712abb1 | ||
|
|
f16a118e88 | ||
|
|
041bf83d9b | ||
|
|
2299032392 | ||
|
|
f5480635c0 | ||
|
|
cdf3fa08dc | ||
|
|
38325248e5 | ||
|
|
deb901b9e4 | ||
|
|
0f98de3011 | ||
|
|
c797708fcc | ||
|
|
49b4c1e9db | ||
|
|
63a87beba4 | ||
|
|
4e0c314654 | ||
|
|
c3538a1eee | ||
|
|
2d7d0835d7 | ||
|
|
3f4cfa6c60 | ||
|
|
f8027414f5 | ||
|
|
76a47d41c8 | ||
|
|
267fdc7a1b | ||
|
|
5bced12421 | ||
|
|
674999c527 | ||
|
|
e4fea22d15 | ||
|
|
66992e90d2 | ||
|
|
e864acfdbd | ||
|
|
4cf21f58b2 | ||
|
|
d7f17613f5 | ||
|
|
e4ca37ccf6 | ||
|
|
d66fa2216e | ||
|
|
48e6dcd0f2 | ||
|
|
0ea3221d34 | ||
|
|
73c53d7833 | ||
|
|
d41be23acd | ||
|
|
2def9e4c82 | ||
|
|
ff6e46ed97 | ||
|
|
715f2b4c00 | ||
|
|
ec0cdc46f6 | ||
|
|
3e75ad9822 | ||
|
|
4f043f8e00 | ||
|
|
cc02cbc455 | ||
|
|
73c0238e3b | ||
|
|
cb122a4d03 | ||
|
|
dc69cc45d2 | ||
|
|
9d8021f0d6 | ||
|
|
9d2221b954 | ||
|
|
70a6a4bb01 | ||
|
|
e4fc856c2f | ||
|
|
3f4984fb36 | ||
|
|
d43665056d | ||
|
|
894b6fac8e | ||
|
|
59f555ad8f | ||
|
|
a7e356cc80 | ||
|
|
e758bfbae1 | ||
|
|
66381e308d | ||
|
|
295a0d84d9 | ||
|
|
1fb1c4c912 | ||
|
|
465a593536 | ||
|
|
d62f4c3bc1 | ||
|
|
a243490ad7 | ||
|
|
9e12ca6069 | ||
|
|
fbca830dd1 | ||
|
|
6146248cf4 | ||
|
|
bc26fbf1b0 | ||
|
|
97cc889374 | ||
|
|
7110b46076 | ||
|
|
c8a8464f7d | ||
|
|
8cbfb6e727 | ||
|
|
6ffc828a79 | ||
|
|
aeb6add336 | ||
|
|
5614289dd8 | ||
|
|
10c7f89351 | ||
|
|
59c268a5f8 | ||
|
|
918bb1ce8f | ||
|
|
a3ba6b4f62 | ||
|
|
8671689449 | ||
|
|
cc10b4607f | ||
|
|
981797f059 | ||
|
|
2117775747 | ||
|
|
be0e268468 | ||
|
|
fbc38b9083 | ||
|
|
8dc69b9da9 | ||
|
|
1489d3b7fa | ||
|
|
dd8c5ce442 | ||
|
|
46484da711 | ||
|
|
802ff8866e | ||
|
|
95a718992c | ||
|
|
e483a01a0f | ||
|
|
f51080916e | ||
|
|
2a952dd0b2 | ||
|
|
0de44a469a | ||
|
|
f0d0a1ebd7 | ||
|
|
569ac91e0b | ||
|
|
a11eb3a090 | ||
|
|
62010520ed | ||
|
|
987514761e | ||
|
|
ba95e36a58 | ||
|
|
abde38b4fb | ||
|
|
18400503da | ||
|
|
9de312112a | ||
|
|
8bbb0b48b4 | ||
|
|
5c0101ab2d | ||
|
|
fbe6410e53 | ||
|
|
8b9fb9fb7e | ||
|
|
0f04ec68a9 | ||
|
|
809073851f | ||
|
|
5d02041c59 | ||
|
|
4b868b8922 | ||
|
|
4061a0d35d | ||
|
|
c68bab7014 | ||
|
|
0c63d15ee9 | ||
|
|
ce19309d09 | ||
|
|
c684349195 | ||
|
|
8db14efa84 | ||
|
|
ffe414cad1 | ||
|
|
c178ab440f | ||
|
|
5befe6584d | ||
|
|
35538ca66c | ||
|
|
4f16409730 | ||
|
|
2a4e948864 | ||
|
|
d778bded95 | ||
|
|
7b4f170c94 | ||
|
|
b1d10a2884 | ||
|
|
cf2719bd12 | ||
|
|
50584f42b4 | ||
|
|
73bed45b7a | ||
|
|
6eaa507473 | ||
|
|
48dff9f3c5 | ||
|
|
a9e261599b | ||
|
|
efd8ee8a7f | ||
|
|
8615ff2acc | ||
|
|
916ed99dab | ||
|
|
e7e9578ed4 | ||
|
|
c99a259739 | ||
|
|
e0f6a2f8be | ||
|
|
ae4a3945f5 | ||
|
|
a317448bd4 | ||
|
|
0eb01b832c | ||
|
|
2a4cd6d05e | ||
|
|
9c32e73abf | ||
|
|
e5c93108e6 | ||
|
|
60c662b3a7 | ||
|
|
f66ba6508a | ||
|
|
f21268aa72 | ||
|
|
07b690a679 | ||
|
|
f9e9bf0231 | ||
|
|
c2ce7e4f07 | ||
|
|
434eb9167e | ||
|
|
09d94162f9 | ||
|
|
e6362642cf | ||
|
|
f0110e8125 | ||
|
|
479ee2a8c6 | ||
|
|
e928b6724c | ||
|
|
ec218a3ad1 | ||
|
|
c04fb91b03 | ||
|
|
323b92bffe | ||
|
|
c6d9730ddb | ||
|
|
2e95823ef7 | ||
|
|
ab2d88ca8e | ||
|
|
3abd036c47 | ||
|
|
c2f3805488 | ||
|
|
ce500635c7 | ||
|
|
0508bbc7ae | ||
|
|
c2fbadb9cf | ||
|
|
47268ecd80 | ||
|
|
9ff3b6af2e | ||
|
|
e3707ef14b | ||
|
|
45fa4ee949 | ||
|
|
9c07b37fff | ||
|
|
5b5886a993 | ||
|
|
d2bfee13e2 | ||
|
|
aff6e45e14 | ||
|
|
1b8a7f8fa0 | ||
|
|
4bc26f0a7b | ||
|
|
fc6e0fe992 | ||
|
|
cd5b5670ba | ||
|
|
6322b47e60 | ||
|
|
691a7a91a1 | ||
|
|
dd1a5ef7f9 | ||
|
|
d5c462596b | ||
|
|
47d147b65d | ||
|
|
911a75114b | ||
|
|
94b476283c | ||
|
|
252f11f85d | ||
|
|
81d5663825 | ||
|
|
68f0ac8271 | ||
|
|
b60a5c5d49 | ||
|
|
8dc2360b11 | ||
|
|
4e4b8570e5 | ||
|
|
4027557958 | ||
|
|
5c32aa411c | ||
|
|
468c243ca8 | ||
|
|
2f257b7291 | ||
|
|
6a5bb6e268 | ||
|
|
e282d963fe | ||
|
|
e2cd521b8f | ||
|
|
fba352a92a | ||
|
|
6dcc526d5b | ||
|
|
5386f1df20 | ||
|
|
ba6640b257 | ||
|
|
507a50c3ad | ||
|
|
147807c911 | ||
|
|
8b246531e6 | ||
|
|
5ad54256c5 | ||
|
|
6ebc1a967d | ||
|
|
6966db1dab | ||
|
|
2196025dd1 | ||
|
|
589f5f37b6 | ||
|
|
edd5f1445d | ||
|
|
936aba5f90 | ||
|
|
3e3a27740e | ||
|
|
b76bb79613 | ||
|
|
fbd5153487 | ||
|
|
69823bf852 | ||
|
|
d940fa679c | ||
|
|
d2bf93fe22 | ||
|
|
550ef1d29d | ||
|
|
728e4f5a8d | ||
|
|
8c2557710d | ||
|
|
a68fd44ecc | ||
|
|
e3f7f3a2e9 | ||
|
|
984232db15 | ||
|
|
78677e3fcf | ||
|
|
ad23270ec7 | ||
|
|
3c0f8c2601 | ||
|
|
989378930a | ||
|
|
dfb6546932 | ||
|
|
3aa2911579 | ||
|
|
d3f6c841c1 | ||
|
|
c1441ae4c4 | ||
|
|
dece85b31f | ||
|
|
6a1df3bd05 | ||
|
|
838400d29b | ||
|
|
b64b24ebc5 | ||
|
|
fc9087114f | ||
|
|
46c374a8a9 | ||
|
|
f0ae725721 | ||
|
|
d72d046254 | ||
|
|
edbbf7ce6c | ||
|
|
a4e4f74530 | ||
|
|
7d3de49715 | ||
|
|
a4c7d99f70 | ||
|
|
0adccaefb6 | ||
|
|
2570f1afdc | ||
|
|
ca31ca13f1 | ||
|
|
6cd666100f | ||
|
|
fe19c266ce | ||
|
|
2768af2388 | ||
|
|
dd296e1de0 | ||
|
|
0efc8a1808 | ||
|
|
df1ba52b64 | ||
|
|
221b08fd8f | ||
|
|
fa9066fe3e | ||
|
|
90ff31b38e | ||
|
|
b1f68c43b5 | ||
|
|
cd90097ca4 | ||
|
|
822eccc3b8 | ||
|
|
2ae41242a5 | ||
|
|
a1579b0ff8 | ||
|
|
ded921f0a2 | ||
|
|
3284751f43 | ||
|
|
bb738c4c26 | ||
|
|
d180c25c8f | ||
|
|
1ed842a3b4 | ||
|
|
e80aba1c2b | ||
|
|
7b8cb3135a | ||
|
|
48ae0506de | ||
|
|
096c4051b2 | ||
|
|
7610c5362a | ||
|
|
111fa5814b | ||
|
|
52fcef1e57 | ||
|
|
7d28674d3a | ||
|
|
9382b76f2a | ||
|
|
fd0b07a75a | ||
|
|
26aa34f319 | ||
|
|
44cc034651 | ||
|
|
0829cab8f2 | ||
|
|
cb7bbc6224 | ||
|
|
5079f924d6 | ||
|
|
5859e58ba1 | ||
|
|
1e747f603f | ||
|
|
9d4efd7aa2 | ||
|
|
9764f55891 | ||
|
|
4ef97b9bb2 | ||
|
|
23759b2688 | ||
|
|
4975297eb0 | ||
|
|
e8e006f4e7 | ||
|
|
c5ebecf7c6 | ||
|
|
3cf0526316 | ||
|
|
174087bfdb | ||
|
|
050f3f1f0e | ||
|
|
e90b1da367 | ||
|
|
8e10d404db | ||
|
|
7a41d61d79 | ||
|
|
4fea018b2d | ||
|
|
6957d28cfb | ||
|
|
0ea70defbe | ||
|
|
9ce5e30c06 | ||
|
|
8c29459eda | ||
|
|
a24005d5fd | ||
|
|
3651b7fca6 | ||
|
|
b64486dae9 | ||
|
|
3da71d51e0 | ||
|
|
7971ed3db3 | ||
|
|
f61ca2ec4f | ||
|
|
84e520b79c | ||
|
|
e8aa0f3315 | ||
|
|
17258e9c63 | ||
|
|
6d339e32a0 | ||
|
|
c3d05245fe | ||
|
|
b58c8ddeb4 | ||
|
|
505b3ae66f | ||
|
|
70dffc639a | ||
|
|
df828f88da | ||
|
|
42f70c8b4f | ||
|
|
10b939b096 | ||
|
|
3adfaae20c | ||
|
|
4006678577 | ||
|
|
9c5f54a723 | ||
|
|
7bab90e52d | ||
|
|
2e21e7d1f1 | ||
|
|
acb469ae2e | ||
|
|
c37c4c437e | ||
|
|
6d21fc43b9 | ||
|
|
e02aacc634 | ||
|
|
aee4512cc5 | ||
|
|
7db0e94b9e | ||
|
|
9facc119a6 | ||
|
|
a1d187113b | ||
|
|
daf650c49a | ||
|
|
8fd7e30f37 | ||
|
|
ca93be130a | ||
|
|
80e57c7a3d | ||
|
|
ae3cc844e7 | ||
|
|
585512fc7c | ||
|
|
7755cdc199 | ||
|
|
f867d08239 | ||
|
|
a103b9bc46 | ||
|
|
bb47109a78 | ||
|
|
f1ede6380b | ||
|
|
995b63adfe | ||
|
|
4023291759 | ||
|
|
86a9bc8291 | ||
|
|
b7632e9641 | ||
|
|
5281ea6ad2 | ||
|
|
d07ba49821 | ||
|
|
418659adbe | ||
|
|
1d2adef28d | ||
|
|
45518c3fe1 | ||
|
|
698d909706 | ||
|
|
81074c7048 | ||
|
|
1b4525384b | ||
|
|
6090e51b65 | ||
|
|
0827ec5aa9 | ||
|
|
4d35f94133 | ||
|
|
34cf54c2fc | ||
|
|
0565d65461 | ||
|
|
f5dc0ed342 | ||
|
|
ea06f021f8 | ||
|
|
5b49177352 | ||
|
|
f45f70af09 | ||
|
|
db86e8d5d3 | ||
|
|
55f5c9f21b | ||
|
|
e92ba1071d | ||
|
|
a7ae5666a0 | ||
|
|
24d249b0b4 | ||
|
|
e508e30800 | ||
|
|
0ee4273b04 | ||
|
|
8ca3ab2c4c | ||
|
|
18ac98700e | ||
|
|
ce4a65ffea | ||
|
|
91721caa42 | ||
|
|
1efc15c177 | ||
|
|
8ed264fcd4 | ||
|
|
4ba3f7db82 | ||
|
|
7d2723d57c | ||
|
|
24d66c5d65 | ||
|
|
229887bd40 | ||
|
|
f3f19e762f | ||
|
|
e9fa42acb8 | ||
|
|
affb35cfb9 | ||
|
|
9710c058aa | ||
|
|
1a4e892765 | ||
|
|
522de7b55d | ||
|
|
0b508fd29d | ||
|
|
1849735f12 | ||
|
|
3239c51814 | ||
|
|
78166ccd36 | ||
|
|
d8ef8a9e9b | ||
|
|
822222181b | ||
|
|
b00053247c | ||
|
|
a502decddb | ||
|
|
61065e1a5c | ||
|
|
403ae0a23b | ||
|
|
5096c0fe97 | ||
|
|
5b3f9eab94 | ||
|
|
e802cf14e3 | ||
|
|
c96d64652b | ||
|
|
dbd84697ff | ||
|
|
5013c15737 | ||
|
|
cdfcee27fb | ||
|
|
66b25ef0d0 | ||
|
|
6cb68f9496 | ||
|
|
0b635c9dc5 | ||
|
|
66afd9b33a | ||
|
|
67e070fe5a | ||
|
|
867b330966 | ||
|
|
64599973e9 | ||
|
|
35f8f03670 | ||
|
|
92a250fdb6 | ||
|
|
2f13d41e30 | ||
|
|
1e19ae8348 | ||
|
|
3810d7e4d4 | ||
|
|
5c7474e1fb | ||
|
|
1f57243b49 | ||
|
|
dc5403612e | ||
|
|
5d8ba816de | ||
|
|
a9f810c188 | ||
|
|
2582f41e12 | ||
|
|
1a7d0ba2d0 | ||
|
|
8921f613de | ||
|
|
f62e225e82 | ||
|
|
94806747df | ||
|
|
bfce29ffef | ||
|
|
8cf30aa2be | ||
|
|
f164e4c72f | ||
|
|
c57029c1f0 | ||
|
|
8fa9acb8e5 | ||
|
|
3dae25828f | ||
|
|
1c7b751d70 | ||
|
|
08dff3774c | ||
|
|
c753a2af39 | ||
|
|
a5185ec8d4 | ||
|
|
768061c85e | ||
|
|
0c136381e3 | ||
|
|
5060568f72 | ||
|
|
a09f748894 | ||
|
|
f9fa7c405f | ||
|
|
a980d3b46b | ||
|
|
87eab90ea8 | ||
|
|
75005bbcd5 | ||
|
|
19f990a9c0 | ||
|
|
bca9de9e68 | ||
|
|
0555cea5fc | ||
|
|
a93270fd60 | ||
|
|
21429c8646 | ||
|
|
0473c48f88 | ||
|
|
72d9fffd78 | ||
|
|
e79588d6c1 | ||
|
|
3a6c7d0cbd | ||
|
|
5e4c34b25a | ||
|
|
bd8a7e7ea1 | ||
|
|
f78c3e41be | ||
|
|
0a402056bc | ||
|
|
e35d41fff5 | ||
|
|
d8c25a175a | ||
|
|
e95e4659d9 | ||
|
|
e51119508c | ||
|
|
229ee34eea | ||
|
|
7fe0f3dabc | ||
|
|
38b603a42f | ||
|
|
a1e7e4a768 | ||
|
|
3f24a38840 | ||
|
|
f853d94a15 | ||
|
|
9649919d01 | ||
|
|
c8efe145b4 | ||
|
|
da80005f11 | ||
|
|
8ed163533c | ||
|
|
1760c31b52 | ||
|
|
72606f2391 | ||
|
|
c15710032e | ||
|
|
6822466aa3 | ||
|
|
64b349aee2 | ||
|
|
e3b69efbe1 | ||
|
|
322736d3bb | ||
|
|
1029119497 | ||
|
|
c1d137ed5f | ||
|
|
f6fd38bb3a | ||
|
|
c2fecb9b2a | ||
|
|
9a53a706fc | ||
|
|
91ee9c9acd | ||
|
|
67928eae28 | ||
|
|
217e7c76f1 | ||
|
|
22994c62f7 | ||
|
|
00f1450d9a | ||
|
|
3a2e89e134 | ||
|
|
c719d94473 | ||
|
|
cea3c20747 | ||
|
|
232ceabbc3 | ||
|
|
c095445394 | ||
|
|
c3d6c5fc4c | ||
|
|
0f98773164 | ||
|
|
d165d9c483 | ||
|
|
3663414053 | ||
|
|
6f2769d0b4 | ||
|
|
5f1c73db7d | ||
|
|
319346025d | ||
|
|
51a16f8c58 | ||
|
|
a00874603d | ||
|
|
941663d038 | ||
|
|
955062da2e | ||
|
|
5705bf1c71 | ||
|
|
cabce31f45 | ||
|
|
ccaae0c019 | ||
|
|
e37151021e | ||
|
|
b3495f2e4b | ||
|
|
61f296e30c | ||
|
|
ce801c9095 | ||
|
|
41fc29907a | ||
|
|
971fb584c3 | ||
|
|
af0f21da0f | ||
|
|
7cea163809 | ||
|
|
5328907f7f | ||
|
|
faaafc7e12 | ||
|
|
94edb1a71c | ||
|
|
3aaa25fa70 | ||
|
|
84bd2f1962 | ||
|
|
7f351dec27 | ||
|
|
81bd9e8ea3 | ||
|
|
10e70a06c9 | ||
|
|
f9c97de46b | ||
|
|
e0243000de | ||
|
|
ac5f95208c | ||
|
|
0e914372fb | ||
|
|
f03a35a679 | ||
|
|
e9da574147 | ||
|
|
b25a029284 | ||
|
|
c8a9d902dd | ||
|
|
6570dc3122 | ||
|
|
3851994ab0 | ||
|
|
44e186512b | ||
|
|
e7e270f511 | ||
|
|
692b82d32c | ||
|
|
c523dd584f | ||
|
|
5a32e64b05 | ||
|
|
093e2a4780 | ||
|
|
dc104cbaaa | ||
|
|
39411504a5 | ||
|
|
e3eb5ea074 | ||
|
|
734e722da4 | ||
|
|
62af25dca8 | ||
|
|
594bd8feba | ||
|
|
f2b52bba05 | ||
|
|
62df6f27cb | ||
|
|
dfdb1adea5 | ||
|
|
7967c2f874 | ||
|
|
18a0b94b0e | ||
|
|
493586cbca | ||
|
|
1d751bc617 | ||
|
|
686ff942af | ||
|
|
5b95b5d77c | ||
|
|
246bdafc74 | ||
|
|
e805543341 | ||
|
|
dba1ccc4d7 | ||
|
|
e613b3c7b1 | ||
|
|
11415bce3c | ||
|
|
9982dd0130 | ||
|
|
9fda7a36fd | ||
|
|
92847a0d11 | ||
|
|
a03842b0d5 | ||
|
|
42e88c4fcb | ||
|
|
1c855a4762 | ||
|
|
780b44bf82 | ||
|
|
8ca6e76dbc | ||
|
|
a7e986166a | ||
|
|
db9ffa1405 | ||
|
|
e926ae78ac | ||
|
|
57e266ab1d | ||
|
|
d29c7c3aca | ||
|
|
aadb38a5e6 | ||
|
|
dd0b72e1ee | ||
|
|
e52b10e33f | ||
|
|
529d88ce95 | ||
|
|
d2f2a8b0ca | ||
|
|
7a9c1ba190 | ||
|
|
6b3840b73c | ||
|
|
a38bd9ca24 | ||
|
|
91014f0171 | ||
|
|
932ab2bfca | ||
|
|
0ebdf41efa | ||
|
|
170f5c671f | ||
|
|
3d11eac784 | ||
|
|
c69e308690 | ||
|
|
25aac0bee5 | ||
|
|
b83241ff4d | ||
|
|
bd5188c811 | ||
|
|
62616b88a6 | ||
|
|
b8f85f671f | ||
|
|
7174de0d79 | ||
|
|
3785afc5a3 | ||
|
|
324415c036 | ||
|
|
1b5ccf6c13 | ||
|
|
5f39721c0a | ||
|
|
ca96acbe4f | ||
|
|
708d9509ff | ||
|
|
9328a074b1 | ||
|
|
2c077dd442 | ||
|
|
933a33a794 | ||
|
|
17f93fe084 | ||
|
|
d5e918b61f | ||
|
|
be5b4552d9 | ||
|
|
643fb0662e | ||
|
|
bef89db6e7 | ||
|
|
d45544d14e | ||
|
|
2a619d96dd | ||
|
|
8cbf544733 | ||
|
|
e051de37f3 | ||
|
|
5de459bf33 | ||
|
|
ec4f5175f1 | ||
|
|
83dd2ab919 | ||
|
|
5a8ae0bb05 | ||
|
|
39bc319b35 | ||
|
|
534bff7d31 | ||
|
|
0cda806dcc | ||
|
|
a3191a9903 | ||
|
|
fced79b0ee | ||
|
|
be887d9269 | ||
|
|
53cf073561 | ||
|
|
2972de4ba3 | ||
|
|
9ee7c2163c | ||
|
|
1a09194ae6 | ||
|
|
c18a4041f9 | ||
|
|
1cade7ef4d | ||
|
|
7413239f49 | ||
|
|
af00e4f9c9 | ||
|
|
44a26e5e21 | ||
|
|
0fbd846561 | ||
|
|
8a2bc0ab1b | ||
|
|
80505995d0 | ||
|
|
165895346c | ||
|
|
3e75d3e001 | ||
|
|
b0867f3fa0 | ||
|
|
89654cd127 | ||
|
|
f194a418f9 | ||
|
|
47c84d7974 | ||
|
|
20168147dd | ||
|
|
77c892c88e | ||
|
|
be7d72ba0d | ||
|
|
d4c504ae1c | ||
|
|
27ad6cee82 | ||
|
|
64681739fd | ||
|
|
388061674a | ||
|
|
a7320bdce9 | ||
|
|
016acebb56 | ||
|
|
07f8ffc44f | ||
|
|
466386d5cd | ||
|
|
70ef82a8e3 | ||
|
|
37eb419af2 | ||
|
|
14d8534900 | ||
|
|
c2201ce02e | ||
|
|
6efbccb387 | ||
|
|
5e0562ab51 | ||
|
|
032c83807f | ||
|
|
6655e804c4 | ||
|
|
1102d46508 | ||
|
|
45911770c5 | ||
|
|
7bd776e7db | ||
|
|
873c8451ed | ||
|
|
9f7957c073 | ||
|
|
da439f2838 | ||
|
|
eefdb379f9 | ||
|
|
2f4f49fd60 | ||
|
|
d16c4d20f8 | ||
|
|
9c56a8ce5c | ||
|
|
a8d6f309c8 | ||
|
|
ca0e38304c | ||
|
|
d16582a038 | ||
|
|
81790d726f | ||
|
|
3028344380 | ||
|
|
361911dd18 | ||
|
|
9ea183aaba | ||
|
|
8f4b918c5b | ||
|
|
4193485b43 | ||
|
|
07123e8ff3 | ||
|
|
586d63636a | ||
|
|
4045d7fea2 | ||
|
|
89c3bc585c | ||
|
|
4af9421ff0 | ||
|
|
1a398b5404 | ||
|
|
589ccc1675 | ||
|
|
c38170461d | ||
|
|
16bdd8424f | ||
|
|
b492316d5d | ||
|
|
91f4ce02b6 | ||
|
|
398343897f | ||
|
|
749ed39d79 | ||
|
|
aba72982df | ||
|
|
e8ef103799 | ||
|
|
5e23fff052 | ||
|
|
f61e71ccb9 | ||
|
|
d9f0c58c65 | ||
|
|
569c5bdbf1 | ||
|
|
eafc6a3292 | ||
|
|
dc8c943372 | ||
|
|
ac5484c4e7 | ||
|
|
746adc5e71 | ||
|
|
048d2aec27 | ||
|
|
e14bac62a0 | ||
|
|
0284a2893a | ||
|
|
07ed421521 | ||
|
|
c56d345985 | ||
|
|
dcfd40a1b8 | ||
|
|
79f11dbaa7 | ||
|
|
52aabbe7ef | ||
|
|
4423490d0b | ||
|
|
d49f206183 | ||
|
|
7a4ac9ec9c | ||
|
|
82bb4f4e89 | ||
|
|
73ca9948fe | ||
|
|
cbac016cce | ||
|
|
12252152ac | ||
|
|
5aa8d6ea21 | ||
|
|
32ec13f149 | ||
|
|
b4f4b7e21a | ||
|
|
f423e46835 | ||
|
|
c03f55ec3a | ||
|
|
23b8c24da4 | ||
|
|
7175bd8ae6 | ||
|
|
7258d1b8f3 | ||
|
|
fbc8ea8c3e | ||
|
|
6c3aa28c94 | ||
|
|
e3b5d806a8 | ||
|
|
3610f34c70 | ||
|
|
cc736e7611 | ||
|
|
789ebea863 | ||
|
|
6f8006c2ce | ||
|
|
589b93de45 | ||
|
|
db0d54f855 | ||
|
|
703960aa54 | ||
|
|
e208fbff52 | ||
|
|
572491ad1f | ||
|
|
20089c23ca | ||
|
|
c333dca065 | ||
|
|
6a2ff287b2 | ||
|
|
eedfd07f8b | ||
|
|
4ec8860783 | ||
|
|
50e716737d | ||
|
|
e022c21ddc | ||
|
|
87b691d80c | ||
|
|
c2f021692f | ||
|
|
fefaf07b6f | ||
|
|
6e568f3a08 | ||
|
|
ad6d78f2a8 | ||
|
|
a00006119f | ||
|
|
bb1c82ef7d | ||
|
|
a13b96ed88 | ||
|
|
624c58682d | ||
|
|
7ae8bd7073 | ||
|
|
bf0f107564 | ||
|
|
296e9cada2 | ||
|
|
b5fb8dd18b | ||
|
|
984a102921 | ||
|
|
4863730eca | ||
|
|
aaa0fc396b | ||
|
|
aea5d3ab00 | ||
|
|
8485027710 | ||
|
|
ec15ef7b7b | ||
|
|
bc6af7548b | ||
|
|
67662702aa | ||
|
|
9e9ad57f58 | ||
|
|
a2596d685d | ||
|
|
d8754af063 | ||
|
|
e0251fdcef | ||
|
|
b77c8190ca | ||
|
|
8428621ddc | ||
|
|
e1689cb985 | ||
|
|
939aff2936 | ||
|
|
f69786a715 | ||
|
|
b2a0d8914a | ||
|
|
acd1811c50 | ||
|
|
42a319074c | ||
|
|
a4d6cb32d1 | ||
|
|
b9aaa507fc | ||
|
|
d705d51671 | ||
|
|
02553d13a0 | ||
|
|
422236af7c | ||
|
|
abb6996f36 | ||
|
|
ee1651ce07 | ||
|
|
3bbc5799b6 | ||
|
|
63fcfc5798 | ||
|
|
db780cb119 | ||
|
|
d86e51e9c1 | ||
|
|
f05888692c | ||
|
|
1183621867 | ||
|
|
763ca9780f | ||
|
|
6cba8fe9ba | ||
|
|
fac5546321 | ||
|
|
e1ee5bf0ba | ||
|
|
0854f8c3bf | ||
|
|
9cf6c8fdc6 | ||
|
|
5f022ae081 | ||
|
|
41d4bcf0cc | ||
|
|
284297019f | ||
|
|
d4084ac5b1 | ||
|
|
d58cc8a4a8 | ||
|
|
796beaaddb | ||
|
|
e2dfd39c75 | ||
|
|
751ff64bdb | ||
|
|
c9dc41ab3f | ||
|
|
caa60b9c99 | ||
|
|
95a53e1f62 | ||
|
|
def687462c | ||
|
|
6d24116763 | ||
|
|
25f8ad13dd | ||
|
|
1d2049b53e | ||
|
|
f5b1c16e2c | ||
|
|
a1dd524b6f | ||
|
|
55a1ac5035 | ||
|
|
85793a18cd | ||
|
|
9998f66f8c | ||
|
|
cfd00af37a | ||
|
|
6274401919 | ||
|
|
2fa4655af6 | ||
|
|
8cef95f7c3 | ||
|
|
922ae4896b | ||
|
|
05ba3e7888 | ||
|
|
1daddec151 | ||
|
|
d8867a2b07 | ||
|
|
6c0125785b | ||
|
|
49ccb2e449 | ||
|
|
7ce7def515 | ||
|
|
8f455c10b0 | ||
|
|
e599fe7436 | ||
|
|
c577f72596 | ||
|
|
15d0f32773 | ||
|
|
8c63ea432c | ||
|
|
2bba420337 | ||
|
|
b656a1c133 | ||
|
|
edf98792a5 | ||
|
|
64ca334a2d | ||
|
|
be613204ab | ||
|
|
f85d5f4dac | ||
|
|
18dfa257d0 | ||
|
|
abbefd7166 | ||
|
|
ed874df293 | ||
|
|
1e018e65cb | ||
|
|
1500f00525 | ||
|
|
dafbec7553 | ||
|
|
506435bf71 | ||
|
|
f287994084 | ||
|
|
4809e2956a | ||
|
|
61fb85618c | ||
|
|
88c4bc33d2 | ||
|
|
48fe97835b | ||
|
|
119a63ab72 | ||
|
|
65a8c2c343 | ||
|
|
13b04044e5 | ||
|
|
cee50b7572 | ||
|
|
8a77e7927e | ||
|
|
1e8553d679 | ||
|
|
06bab3edb0 | ||
|
|
f66d37fb1c | ||
|
|
6fd6ecc10d | ||
|
|
c4212f9ec2 | ||
|
|
1546b9e336 | ||
|
|
17c17d1585 | ||
|
|
d09dd1a81a | ||
|
|
21c6700b83 | ||
|
|
64a0016680 | ||
|
|
9ec3bea2d6 | ||
|
|
1fb0586b06 | ||
|
|
5f26b5da28 | ||
|
|
209a1d58bf | ||
|
|
9a07973261 | ||
|
|
0d25f6fcbb | ||
|
|
ea28a63706 | ||
|
|
0d8aca8de3 | ||
|
|
4ece95a754 | ||
|
|
0028ce57b6 | ||
|
|
ece7ae5f49 | ||
|
|
621447fece | ||
|
|
a0190e4bbd | ||
|
|
b903f5c123 | ||
|
|
43c0095aa3 | ||
|
|
4873685c7e | ||
|
|
fc73e10620 | ||
|
|
92605eb4f7 | ||
|
|
9bb213e920 | ||
|
|
2ae6bca488 | ||
|
|
04335aeadb | ||
|
|
3d5125cd87 | ||
|
|
d775a20fff | ||
|
|
4dc9fd995f | ||
|
|
a79c7b4e8f | ||
|
|
195d6a5663 | ||
|
|
6c184efa75 | ||
|
|
93975c70bb | ||
|
|
53f9e7f65c | ||
|
|
768739c310 | ||
|
|
94d387cd45 | ||
|
|
721c9100f2 | ||
|
|
108498bdd0 | ||
|
|
f19d8f9655 | ||
|
|
2bf59a97c6 | ||
|
|
12a6027b40 | ||
|
|
a5d0adf395 | ||
|
|
1a23f9c274 | ||
|
|
9dbb60c4c8 | ||
|
|
ed30108918 | ||
|
|
d5893c9a13 | ||
|
|
6ee9f2ed09 | ||
|
|
631ffef438 | ||
|
|
355861f1ff | ||
|
|
ab054532ce | ||
|
|
9823675832 | ||
|
|
d4ddaaf2b1 | ||
|
|
fa0f870ac9 | ||
|
|
1dbc6bd1fc | ||
|
|
c8c9973669 | ||
|
|
65cd664195 | ||
|
|
c110c6eca7 | ||
|
|
1acfd07f1e | ||
|
|
d4885cea62 | ||
|
|
903357c853 | ||
|
|
88b84d6429 | ||
|
|
d7c4e1cb1f | ||
|
|
0d5ef5c2a6 | ||
|
|
8631694021 | ||
|
|
4133e501f3 | ||
|
|
0e6df7e511 | ||
|
|
44c926d96f | ||
|
|
75f862bf57 | ||
|
|
116914a949 | ||
|
|
689fd2ad49 | ||
|
|
7a0806a366 | ||
|
|
a81bff9349 | ||
|
|
5c876088d3 | ||
|
|
d688072990 | ||
|
|
aa1e6b0f75 | ||
|
|
26819461bd | ||
|
|
2e69e454d0 | ||
|
|
a914384bc4 | ||
|
|
41356aa00a | ||
|
|
e9a0d3141b | ||
|
|
c7d0241abb | ||
|
|
e0d6f630f8 | ||
|
|
a201c61977 | ||
|
|
4569b4dbd6 | ||
|
|
c9bb5468b6 | ||
|
|
b26e76efe9 | ||
|
|
c7739536e8 | ||
|
|
dfa631e64a | ||
|
|
18e3f16576 | ||
|
|
72d51e0b1e | ||
|
|
6ccb5673c4 | ||
|
|
a82026746d | ||
|
|
9d36a5a3b0 | ||
|
|
81e2dac955 | ||
|
|
5940431e2d | ||
|
|
15008bf05d | ||
|
|
06045cb4a5 | ||
|
|
9492b9ff03 | ||
|
|
0d9870dd9e | ||
|
|
5e70843a73 | ||
|
|
d25e07660e | ||
|
|
579736f210 | ||
|
|
8650c57ccd | ||
|
|
9071daebe9 | ||
|
|
fcaf8a0cdc | ||
|
|
231c16df25 | ||
|
|
971359997f | ||
|
|
f7abf9fd0f | ||
|
|
e68836c123 | ||
|
|
dc1e36fa0e | ||
|
|
7bb1b50835 | ||
|
|
96c28f748d | ||
|
|
e160c2b79a | ||
|
|
e2a332e5df | ||
|
|
ebff26f8f1 | ||
|
|
559739ec1d | ||
|
|
45a1509455 | ||
|
|
5b106083e7 | ||
|
|
2d8a7ed086 | ||
|
|
b18f783fed | ||
|
|
b6c0cf9683 | ||
|
|
d00b43c592 | ||
|
|
cc9b051d12 | ||
|
|
d67eb8af2f | ||
|
|
3400e0d609 | ||
|
|
f76583276a | ||
|
|
31a4f0ab05 | ||
|
|
744c2824c5 | ||
|
|
140f11190b | ||
|
|
fb67a2f660 | ||
|
|
d2b65f77e8 | ||
|
|
03cdd4ca50 | ||
|
|
e5e4fb370c | ||
|
|
70d93078e3 | ||
|
|
b344bd9582 | ||
|
|
add6bcca3e | ||
|
|
836415b215 | ||
|
|
7ce503e6a0 | ||
|
|
a4538ac1e8 | ||
|
|
6dfdada493 | ||
|
|
b7fe7dfad1 | ||
|
|
9c865560fd | ||
|
|
1788883262 | ||
|
|
90730e706b | ||
|
|
041725e9d0 | ||
|
|
c5fe3eb87e | ||
|
|
b2a8141373 | ||
|
|
408c84cd42 | ||
|
|
6825ac9ccf | ||
|
|
f3d6d3a8f2 | ||
|
|
8eaad79de7 | ||
|
|
131d446183 | ||
|
|
4042198262 | ||
|
|
729491eab7 | ||
|
|
3a04ebf14f | ||
|
|
b64d13a357 | ||
|
|
e0ac51cbd9 | ||
|
|
4e279e2a70 | ||
|
|
a3929b719a | ||
|
|
63be22d5dc | ||
|
|
f171d1f3d6 | ||
|
|
c33f3e281b | ||
|
|
59d0efd6d6 | ||
|
|
56b6c05bf9 | ||
|
|
8dd48923d8 | ||
|
|
7dac3c44f5 | ||
|
|
4a0d9dbc30 | ||
|
|
c916ab3319 | ||
|
|
f9ee5f4b43 | ||
|
|
e817bb9cc4 | ||
|
|
5946029585 | ||
|
|
f4b5aeaed2 | ||
|
|
5a6a58576a | ||
|
|
90accff030 | ||
|
|
49f6771ca9 | ||
|
|
fa5ebd27d4 | ||
|
|
4cddbfa7cf | ||
|
|
f1cd5413e9 | ||
|
|
7f0d8184c9 | ||
|
|
e569297d6a | ||
|
|
bea282dae9 | ||
|
|
17544b1824 | ||
|
|
afd67497de | ||
|
|
5e1576f79f | ||
|
|
848ab63a2a | ||
|
|
c7d9d79ad2 | ||
|
|
9ae2ac2fb7 | ||
|
|
125bb0f19a | ||
|
|
bfdca8b576 | ||
|
|
da3467b7f9 | ||
|
|
fb5350543c | ||
|
|
ccbc891992 | ||
|
|
b69e6dcead | ||
|
|
4d8cee2d48 | ||
|
|
f68771abe4 | ||
|
|
581afee039 | ||
|
|
e49a4e0aff | ||
|
|
753e9a04c0 | ||
|
|
18c69c998d | ||
|
|
6cfe43539a | ||
|
|
c61043450b | ||
|
|
e4f7d0d311 | ||
|
|
d8e246daaf | ||
|
|
620f999e80 | ||
|
|
dcbb6b1e4d | ||
|
|
a99891e7a5 | ||
|
|
52f89065e1 | ||
|
|
9ffe98c00e | ||
|
|
63d7f3d116 | ||
|
|
c052cf11b9 | ||
|
|
0c901efb16 | ||
|
|
030cccfeef | ||
|
|
062e3bd757 | ||
|
|
5174b8ca28 | ||
|
|
090de29ddf | ||
|
|
59607f5e99 | ||
|
|
763d1fe6a3 | ||
|
|
7d6622942c | ||
|
|
0867c1b447 | ||
|
|
6883d6e724 | ||
|
|
8f4b8edb8b | ||
|
|
5324d385c0 | ||
|
|
fc505b5447 | ||
|
|
3c3d6b3d2a | ||
|
|
2a05a87fe7 | ||
|
|
3ecad55910 | ||
|
|
d929fdeb9b | ||
|
|
9d577cae6f | ||
|
|
6e820841d4 | ||
|
|
82d6813e7c | ||
|
|
2f12a32c20 | ||
|
|
6178bc6f8e | ||
|
|
209748f128 | ||
|
|
f64ea6235f | ||
|
|
80d288b146 | ||
|
|
6500f161f7 | ||
|
|
abd93d824a | ||
|
|
2b2aa8926f | ||
|
|
21b8279cfe | ||
|
|
cd7f6c1fda | ||
|
|
70e44a8e7f | ||
|
|
b8c6192a61 | ||
|
|
c7b7141b11 | ||
|
|
c57f8f563b | ||
|
|
016af73d19 | ||
|
|
f961683516 | ||
|
|
27a1b787c8 | ||
|
|
6a79a3279b | ||
|
|
734d3bf175 | ||
|
|
8c8877df5a | ||
|
|
754be04f11 | ||
|
|
1adee75e1c | ||
|
|
a4b611a3d3 | ||
|
|
220bb764e5 | ||
|
|
a750114a38 | ||
|
|
4d56c5ce4c | ||
|
|
c0ad9a888b | ||
|
|
0598d84f61 | ||
|
|
b09c83504e | ||
|
|
3133925ab2 | ||
|
|
03b9485cb3 | ||
|
|
ded46cc1b6 | ||
|
|
c1a4cd0fa7 | ||
|
|
797d72133e | ||
|
|
56cfd9f4ce | ||
|
|
e0e8f717a0 | ||
|
|
cfb25b0e80 | ||
|
|
e489f879c3 | ||
|
|
c0e926109e | ||
|
|
b05a02b91c | ||
|
|
d411aa165e | ||
|
|
be961bae0f | ||
|
|
0a4acc9656 | ||
|
|
d3fe82c55b | ||
|
|
a659d8079e | ||
|
|
00fda9b25a | ||
|
|
4aeeb49d23 | ||
|
|
fee52f79b8 | ||
|
|
4952e79e45 | ||
|
|
95c0fb5075 | ||
|
|
62ac1d98a4 | ||
|
|
5aa5116edc | ||
|
|
5e7ab2f4ea | ||
|
|
b52d0bd9d4 | ||
|
|
0fb474be3a | ||
|
|
3019a8c1fd | ||
|
|
7ee287d3d9 | ||
|
|
ae6368c985 | ||
|
|
bb7a80b1ab | ||
|
|
8474a6232d | ||
|
|
22f61140d1 | ||
|
|
52ee516cf3 | ||
|
|
ef7bbfff87 | ||
|
|
891e9117f6 | ||
|
|
3fc3ecd184 | ||
|
|
06f3abe26d | ||
|
|
50f14f225c | ||
|
|
b732455fd3 | ||
|
|
daf74ae0b1 | ||
|
|
4af764d040 | ||
|
|
97e9ed11bc | ||
|
|
f55bf55d43 | ||
|
|
e604d5347f | ||
|
|
979e70f10d | ||
|
|
b203beb61d | ||
|
|
28a303ddd4 | ||
|
|
3943803412 | ||
|
|
7185e96da1 | ||
|
|
251a0869be | ||
|
|
804ad8f4df | ||
|
|
8b0504825d | ||
|
|
77d3761b50 | ||
|
|
0525a03a69 | ||
|
|
1a5a1708b7 | ||
|
|
4797ca025e | ||
|
|
3121ebd044 | ||
|
|
b098306839 | ||
|
|
a721319e3a | ||
|
|
29726cefb8 | ||
|
|
811964502d | ||
|
|
0629d76bb0 | ||
|
|
016714c57b | ||
|
|
c679352517 | ||
|
|
1042ddda0f | ||
|
|
d998b5d038 | ||
|
|
bf6651d1ca | ||
|
|
1cba0aea27 | ||
|
|
a9d2e826fe | ||
|
|
c47318afa8 | ||
|
|
ecd52bc610 | ||
|
|
5c76d107cb | ||
|
|
98c1f76f24 | ||
|
|
e7f4566dd4 | ||
|
|
e0179ee190 | ||
|
|
e567fe6960 | ||
|
|
7c60db1e24 | ||
|
|
0ea73df717 | ||
|
|
aa7bb101ed | ||
|
|
3bc97a5564 | ||
|
|
c2ffa14684 | ||
|
|
535dbdd1c8 | ||
|
|
00d56e06ef | ||
|
|
7e94fcb680 | ||
|
|
6ced4230f4 | ||
|
|
5f8af5ef1d | ||
|
|
5837851cb2 | ||
|
|
abe932164a | ||
|
|
19de4a863a | ||
|
|
328c8888ec | ||
|
|
df2dfd9612 | ||
|
|
fac207816c | ||
|
|
ec80a1ab51 | ||
|
|
3bf900e301 | ||
|
|
722c8e4ae6 | ||
|
|
13d6b2d38c | ||
|
|
b8bd80ff28 | ||
|
|
7cbb29f61e | ||
|
|
053df632f8 | ||
|
|
222f2d28f5 | ||
|
|
f60c4b9947 | ||
|
|
0519737b95 | ||
|
|
9a08fb52bf | ||
|
|
8265263c5d | ||
|
|
d266adf805 | ||
|
|
6cff6d8137 | ||
|
|
1a2a333a1a | ||
|
|
289885e8c0 | ||
|
|
4118b89139 | ||
|
|
96731cebe1 | ||
|
|
b83fd00183 | ||
|
|
646829e34d | ||
|
|
8beadace37 | ||
|
|
223575b567 | ||
|
|
ee3e68dc16 | ||
|
|
e5d599875c | ||
|
|
b53994fd0d | ||
|
|
fd1753484e | ||
|
|
6606971aae | ||
|
|
31aced8b59 | ||
|
|
1dd5e035eb | ||
|
|
0219d5591b | ||
|
|
3a2f91bd58 | ||
|
|
c1a8dfe555 | ||
|
|
d9e0f5c04e | ||
|
|
9c03176e6b | ||
|
|
2157375d5c | ||
|
|
7dcf05108e | ||
|
|
32f0295460 | ||
|
|
3df9bf3a91 | ||
|
|
7d94b5bbeb | ||
|
|
ef5e5e02b4 | ||
|
|
11f946efff | ||
|
|
57ba9436a0 | ||
|
|
5e37698911 | ||
|
|
b5fda1c90d | ||
|
|
e61c8d4cba | ||
|
|
89cd4a5e17 | ||
|
|
0550f1217c | ||
|
|
d6d019aa12 | ||
|
|
477962884e | ||
|
|
aa741bafe6 | ||
|
|
8b86a74ad5 | ||
|
|
7c24973637 | ||
|
|
9beb01d8e5 | ||
|
|
5b7dd17dff | ||
|
|
41ebedf516 | ||
|
|
9954aa064b | ||
|
|
f4d8884af1 | ||
|
|
fe34b2f357 | ||
|
|
8af9bf1d06 | ||
|
|
de3cea7f02 | ||
|
|
27c2e880d0 | ||
|
|
b4b13ee2b8 | ||
|
|
96d518f2f8 | ||
|
|
0cb37ce2eb | ||
|
|
82acd483ae | ||
|
|
b1a55d50bf | ||
|
|
e1ed1d789c | ||
|
|
dc7a372bfc | ||
|
|
387b23f890 | ||
|
|
1133fe8ab0 | ||
|
|
0bfa6bed4b | ||
|
|
a4e3cf834b | ||
|
|
09e288e55b | ||
|
|
17869454c2 | ||
|
|
6a93dda265 | ||
|
|
4d3be75bcd | ||
|
|
587b4894ba | ||
|
|
c6a67b91de | ||
|
|
2ebdd49e96 | ||
|
|
b3411bdeed | ||
|
|
0ba89d256b | ||
|
|
c04617c8d4 | ||
|
|
fa88490453 | ||
|
|
7638a3be1e | ||
|
|
7610e98a37 | ||
|
|
333770bfa3 | ||
|
|
1b187ce57f | ||
|
|
bcc136de81 | ||
|
|
83b639987c | ||
|
|
1942ff4c70 | ||
|
|
fef203bf6c | ||
|
|
1df1af0245 | ||
|
|
d2f707e33a | ||
|
|
4800554fc2 | ||
|
|
0bf9b07173 | ||
|
|
2d727e7d0e | ||
|
|
522e0e8371 | ||
|
|
316b05cf34 | ||
|
|
17960dd3d3 | ||
|
|
9bbdf3b4c9 | ||
|
|
def5d983de | ||
|
|
4822044dc9 | ||
|
|
247fe7a2a6 | ||
|
|
b91eea5549 | ||
|
|
87a2a61d56 | ||
|
|
f27f848bb8 | ||
|
|
5b7d8db684 | ||
|
|
b92c60c171 | ||
|
|
d1ae63032d | ||
|
|
acfa858e3c | ||
|
|
716ab0499d | ||
|
|
4e9faed8f9 | ||
|
|
024eae91fb | ||
|
|
2167da4bb3 | ||
|
|
fe3d4513cc | ||
|
|
59442e968d | ||
|
|
74ea872b0c | ||
|
|
ef741a4649 | ||
|
|
c43603b363 | ||
|
|
a5b45dc389 | ||
|
|
64e66befd5 | ||
|
|
ce973be1bb | ||
|
|
ae48a4c6f9 | ||
|
|
f080b62047 | ||
|
|
fb27723a9f | ||
|
|
b64913b00b | ||
|
|
869ed1ec19 | ||
|
|
ecbfdb46d3 | ||
|
|
23e84472b2 | ||
|
|
ab25cd2c8b | ||
|
|
13e0e38d99 | ||
|
|
cd097d334e | ||
|
|
adee0dfc39 | ||
|
|
cb5a1698c9 | ||
|
|
c684886dfc | ||
|
|
221dd0cb66 | ||
|
|
a68ce59c74 | ||
|
|
3814a07c44 | ||
|
|
49382a0aa7 | ||
|
|
d25d775ae6 | ||
|
|
22d572d7a2 | ||
|
|
a9582bb1a2 | ||
|
|
5a648b300f | ||
|
|
85a93a8078 | ||
|
|
56d3b9135f | ||
|
|
317ff51fd9 | ||
|
|
6bed5e5b01 | ||
|
|
931173ab77 | ||
|
|
3242e624d5 | ||
|
|
566f393b49 | ||
|
|
a43e242716 | ||
|
|
5405b09ff4 | ||
|
|
e81c0aef39 | ||
|
|
b2714f83cc | ||
|
|
6049fd9d66 | ||
|
|
77b32006a3 | ||
|
|
9608a98b01 | ||
|
|
caa8f76a88 | ||
|
|
044ef900bc | ||
|
|
6d9712c7fd | ||
|
|
826edabae1 | ||
|
|
5898720c28 | ||
|
|
a596b8724b | ||
|
|
79d7aacff3 | ||
|
|
aaa8b1e0aa | ||
|
|
2d921c96e0 | ||
|
|
ee1fdc575b | ||
|
|
418cd1c82a | ||
|
|
884c55741f | ||
|
|
2cca51c744 | ||
|
|
221eeda912 | ||
|
|
d57c6204cd | ||
|
|
694bfb5309 | ||
|
|
9daa774b5b | ||
|
|
1554c9c6e5 | ||
|
|
2a4f98f474 | ||
|
|
39265a4288 | ||
|
|
a257d811d8 | ||
|
|
238d6dc506 | ||
|
|
a5b296a484 | ||
|
|
e854c7d47e | ||
|
|
e61f4d2bf6 | ||
|
|
ee6f4e7aec | ||
|
|
13c633223e | ||
|
|
a08bc864fb | ||
|
|
95fa85cf04 | ||
|
|
f4d38ce3ea | ||
|
|
d6ecf3ae61 | ||
|
|
6dae7f3ba6 | ||
|
|
08bcf61fb2 | ||
|
|
bdbac0b78f | ||
|
|
5bc908623c | ||
|
|
7732688b80 | ||
|
|
9575e77e40 | ||
|
|
358ae822bb | ||
|
|
dd60ec673c | ||
|
|
47e26cdc37 | ||
|
|
2eda8313af | ||
|
|
c0813c59f3 | ||
|
|
3b9765f858 | ||
|
|
bc6010cc21 | ||
|
|
a63a24f2d7 | ||
|
|
50e9487e18 | ||
|
|
ef710dee6c | ||
|
|
a12f49669c | ||
|
|
42d8f5b994 | ||
|
|
79d8f59906 | ||
|
|
59155abbf3 | ||
|
|
d48047e4c0 | ||
|
|
005379ac6f | ||
|
|
75fdfe3e0e | ||
|
|
6de8f4a416 | ||
|
|
06c1859420 | ||
|
|
5bcd5ac6d6 | ||
|
|
4807f69ab4 | ||
|
|
c2ba9e191d | ||
|
|
edf5c26001 | ||
|
|
b3714625c0 | ||
|
|
1bba22667e | ||
|
|
d07fd577c3 | ||
|
|
4274f15f0d | ||
|
|
0d99eb5d6b | ||
|
|
914b97859c | ||
|
|
4150fa0f95 | ||
|
|
4e2a0a7e1c | ||
|
|
2161823559 | ||
|
|
2923d7f588 | ||
|
|
11395c4f09 | ||
|
|
32fbc083b7 | ||
|
|
8c4483d3cb | ||
|
|
b247d81046 | ||
|
|
c3ba615c65 | ||
|
|
cdcdacef9c | ||
|
|
a8a2982b9a | ||
|
|
2202541364 | ||
|
|
ca7478144d | ||
|
|
43081b833a | ||
|
|
2c6e32f6ff | ||
|
|
58fcf0c0da | ||
|
|
f6135df529 | ||
|
|
ecdc7ec1f1 | ||
|
|
7fa17fe772 | ||
|
|
a8d12ade1c | ||
|
|
f9813c313d | ||
|
|
5b8d0a7aa9 | ||
|
|
64eb3d8bb2 | ||
|
|
0affb23560 | ||
|
|
1e8496da4a | ||
|
|
b634309a31 | ||
|
|
7e12c5c9df | ||
|
|
2830cf65c9 | ||
|
|
d15e0d3e06 | ||
|
|
b022790f3b | ||
|
|
922fe90ac3 | ||
|
|
fabd3a84c5 | ||
|
|
611eb774ca | ||
|
|
45e7b5b672 | ||
|
|
4b6a52c6f8 | ||
|
|
d02a5031f0 | ||
|
|
200037683e | ||
|
|
c4d0bc1ac9 | ||
|
|
0eac037416 | ||
|
|
69a0317590 | ||
|
|
583f7e9e1c | ||
|
|
0586a9e4ea | ||
|
|
3b224e1813 | ||
|
|
76d1218345 | ||
|
|
e498ffbb3d | ||
|
|
6cf24c7f92 | ||
|
|
4f7ad14c2b | ||
|
|
f3bef7ac92 | ||
|
|
b6c1c9233a | ||
|
|
6484a15ca0 | ||
|
|
c669cbedf8 | ||
|
|
7859f81233 | ||
|
|
0332284ce3 | ||
|
|
7154238d45 | ||
|
|
279749168a | ||
|
|
ba09c1b56e | ||
|
|
df0835ac27 | ||
|
|
438bd9b0e6 | ||
|
|
88c7c20102 | ||
|
|
761a0afb85 | ||
|
|
5b9b485f57 | ||
|
|
0a7e5141c1 | ||
|
|
9769f4b9ed | ||
|
|
e5b16e80cc | ||
|
|
948317b6dd | ||
|
|
958299dd7f | ||
|
|
b88a17ad9e | ||
|
|
abcc2d96f0 | ||
|
|
8ab665afbc | ||
|
|
8450f5e1d3 | ||
|
|
2e874af293 | ||
|
|
dd6a3bbc7c | ||
|
|
a0ed6bfe4f | ||
|
|
e39490500c | ||
|
|
147e5ebbbc | ||
|
|
270069beda | ||
|
|
9b6b3382e3 | ||
|
|
63f6c10449 | ||
|
|
8725d07d8b | ||
|
|
24c309fbfa | ||
|
|
9d09214e7a | ||
|
|
fd5c2e909b | ||
|
|
fccff7be5f | ||
|
|
b83ab16676 | ||
|
|
e5005c98b0 | ||
|
|
834618ee28 | ||
|
|
3c99ed4498 | ||
|
|
2e254ad19d | ||
|
|
a98583dde3 | ||
|
|
4325c155f7 | ||
|
|
83659f425b | ||
|
|
7487bde587 | ||
|
|
ed2dfe5124 | ||
|
|
8949a2e941 | ||
|
|
a5e7d08ad0 | ||
|
|
99edb141ec | ||
|
|
03bf6dea67 | ||
|
|
54a6cb34c7 | ||
|
|
d311927c64 | ||
|
|
4d521064cf | ||
|
|
d8a3b74664 | ||
|
|
ce5ab7d68f | ||
|
|
5a61d54eb7 | ||
|
|
3310849fa0 | ||
|
|
f478f7f490 | ||
|
|
b902efd870 | ||
|
|
921f1bae46 | ||
|
|
079c6442e1 | ||
|
|
9e83b8a6e0 | ||
|
|
e1fcb0a2b5 | ||
|
|
eaf30d5b0d | ||
|
|
9af6c41684 | ||
|
|
9ca1ce293e | ||
|
|
bfe9267d4d | ||
|
|
42001e541e | ||
|
|
ba994e78ec | ||
|
|
f5f9f50f87 | ||
|
|
63572da4e7 | ||
|
|
78936ad6d7 | ||
|
|
eb50269744 | ||
|
|
c389ec05a1 | ||
|
|
e4c0046a99 | ||
|
|
dfe2a65b5d | ||
|
|
efba235246 | ||
|
|
0022e0b40f | ||
|
|
44fabfc803 | ||
|
|
e15eae012c | ||
|
|
5d570d7ee9 | ||
|
|
9f60609405 | ||
|
|
37141a1e3f | ||
|
|
719208c24b | ||
|
|
3e49279267 | ||
|
|
595845153d | ||
|
|
f77b00e1f7 | ||
|
|
eb20f8aece | ||
|
|
1456a496f0 | ||
|
|
fbc2fcb3e2 | ||
|
|
fca83df599 | ||
|
|
6955417236 | ||
|
|
469f3674cf | ||
|
|
702e53d7a8 | ||
|
|
f9936c4859 | ||
|
|
abba1477a7 | ||
|
|
183ce52c41 | ||
|
|
86aa72f3d5 | ||
|
|
0ba61ffa6d | ||
|
|
c17f4ec099 | ||
|
|
56d5335e3f | ||
|
|
18a55cdb27 | ||
|
|
4c1a0303aa | ||
|
|
0e28acdd05 | ||
|
|
4d1bd5ac18 | ||
|
|
0ba03ee823 | ||
|
|
2c03e822b2 | ||
|
|
804a74c998 | ||
|
|
90a12b1bb2 | ||
|
|
a5757c86df | ||
|
|
5517c8962e | ||
|
|
684495c887 | ||
|
|
640445fc48 | ||
|
|
e17b743141 | ||
|
|
c8688576f2 | ||
|
|
024f8c6a0a | ||
|
|
8035c3eb30 | ||
|
|
15de5f68b4 | ||
|
|
3913f29ad7 | ||
|
|
2da08f21dd | ||
|
|
0e5c8e5395 | ||
|
|
ea9a31b225 | ||
|
|
dd8e6b9a72 | ||
|
|
c150722945 | ||
|
|
f3fc8052ab | ||
|
|
3e03934d15 | ||
|
|
85b985e9f2 | ||
|
|
3e379829a0 | ||
|
|
4888000f32 | ||
|
|
673a4525f6 | ||
|
|
1c72e7062b | ||
|
|
6de2edf05b | ||
|
|
fde90aa551 | ||
|
|
40681e6037 | ||
|
|
ca2cadb1c6 | ||
|
|
11464343a9 | ||
|
|
3c388185c0 | ||
|
|
f5b3c9cbec | ||
|
|
de994a27a7 | ||
|
|
e515e5f14e | ||
|
|
87cb2935f8 | ||
|
|
969d1cdbdc | ||
|
|
67ce394256 | ||
|
|
f44666aac6 | ||
|
|
001054c8a0 | ||
|
|
926b7680ea | ||
|
|
8af48bbaf1 | ||
|
|
8d2559bd96 | ||
|
|
62c483c940 | ||
|
|
88f4be3d19 | ||
|
|
c3ebcce89d | ||
|
|
0963fd0a4d | ||
|
|
cea64132a2 | ||
|
|
f6823221d3 | ||
|
|
f35a220536 | ||
|
|
8c24a42395 | ||
|
|
dc3039a40d | ||
|
|
d2ada77ccc | ||
|
|
3a0624ab2e | ||
|
|
fb362ef880 | ||
|
|
fd53bb6fb8 | ||
|
|
aab64b55a4 | ||
|
|
d2387999ec | ||
|
|
60405cf693 | ||
|
|
9c75d0ccf7 | ||
|
|
3a5573ac6e | ||
|
|
d4ea2d7fcb | ||
|
|
d618f8baac | ||
|
|
885d1a1c64 | ||
|
|
2ba3988da3 | ||
|
|
66915785dd | ||
|
|
3c3ae4e319 | ||
|
|
00df5c91f3 | ||
|
|
cf04d98d06 | ||
|
|
1addec97bc | ||
|
|
da052ae821 | ||
|
|
72aae04adf | ||
|
|
a445e727c2 | ||
|
|
45bba4f129 | ||
|
|
73ea170966 | ||
|
|
906432161b | ||
|
|
b9f4668855 | ||
|
|
ba81f04bfa | ||
|
|
100bc30773 | ||
|
|
df477565f8 | ||
|
|
a53ac7ad5c | ||
|
|
f49ab8e4a9 | ||
|
|
0e8fcd47a0 | ||
|
|
bf8636c959 | ||
|
|
2adbfa4af7 | ||
|
|
23b60f5735 | ||
|
|
ef7d4879e4 | ||
|
|
33ec5b16d8 | ||
|
|
275d1ab423 | ||
|
|
107a95c9cc | ||
|
|
3d4af9cd65 | ||
|
|
ef5972e1ca | ||
|
|
d99c49b970 | ||
|
|
538c2610cb | ||
|
|
8ed6031457 | ||
|
|
a6aa789f4b | ||
|
|
b739ec893f | ||
|
|
357950e06b | ||
|
|
df47d819b9 | ||
|
|
a530052b7e | ||
|
|
eccd5e8d15 | ||
|
|
93ae73adbc | ||
|
|
2b793d2d1e | ||
|
|
5aecd4947f | ||
|
|
c6d3a73201 | ||
|
|
4825fb4a0d | ||
|
|
eb6baf04ff | ||
|
|
d08c4ba84a | ||
|
|
4547523e19 | ||
|
|
e65e05b960 | ||
|
|
80d1dd29b7 | ||
|
|
c97c0fbbc9 | ||
|
|
e1776acd19 | ||
|
|
341b98c6e2 | ||
|
|
2d4631a580 | ||
|
|
593d3aef9e | ||
|
|
b8c36498f2 | ||
|
|
97b33fe069 | ||
|
|
82a3e78e04 | ||
|
|
9f19796ef0 | ||
|
|
23b7bfead0 | ||
|
|
57f9f06619 | ||
|
|
03ee6a0295 | ||
|
|
6bca5ca109 | ||
|
|
b2207f9d05 | ||
|
|
752580a5c2 | ||
|
|
93cfe9951b | ||
|
|
6dd532b456 | ||
|
|
3b259b5120 | ||
|
|
870f42e1f0 | ||
|
|
e3a1da5a71 | ||
|
|
da547f5533 | ||
|
|
961097315c | ||
|
|
f9e1c2bd59 | ||
|
|
8c8826f749 | ||
|
|
5821aec7b9 | ||
|
|
689ea8d3dd | ||
|
|
55836caa8d | ||
|
|
a037a829f5 | ||
|
|
7e251643db | ||
|
|
08d759c425 | ||
|
|
6af3da1089 | ||
|
|
eec6b29b64 | ||
|
|
0b097da31e | ||
|
|
f9e98c2007 | ||
|
|
2d80bcc1cb | ||
|
|
fa5b35e539 | ||
|
|
549b61e958 | ||
|
|
2d200e3caa | ||
|
|
3252eead94 | ||
|
|
d82b6c7e62 | ||
|
|
55ba812d12 | ||
|
|
5463a62d43 | ||
|
|
9350328086 | ||
|
|
9d1fc0ecd5 | ||
|
|
9c006520bd | ||
|
|
8ad6f93428 | ||
|
|
72c97ab4ab | ||
|
|
bcc2fd1dbe | ||
|
|
a89f578c14 | ||
|
|
6005907db6 | ||
|
|
53dd7d1583 | ||
|
|
65a8a7f85e | ||
|
|
89e0684da6 | ||
|
|
a5c6975118 | ||
|
|
ec7b006fab | ||
|
|
c1f8274701 | ||
|
|
91d9497911 | ||
|
|
3453df6d65 | ||
|
|
648c730bd2 | ||
|
|
8abc15f85e | ||
|
|
4ff6ab396c | ||
|
|
14d1fb561f | ||
|
|
7ae6dfbcba | ||
|
|
bdada10c2c | ||
|
|
65cf5414c9 | ||
|
|
cb40e7c60b | ||
|
|
3a9b7ad8b6 | ||
|
|
38b5f573dd | ||
|
|
5ad6c6bd7f | ||
|
|
85ef48cb6d | ||
|
|
a6864a7264 | ||
|
|
0dd1f19281 | ||
|
|
7c8f915f0b | ||
|
|
e1b62a5d39 | ||
|
|
4d208ae86f | ||
|
|
29451ea8e2 | ||
|
|
e6113fb9f5 | ||
|
|
7c0a23329e | ||
|
|
f1e77e41a5 | ||
|
|
267d4542bb | ||
|
|
ee5443e920 | ||
|
|
103530d407 | ||
|
|
efc42fbd4e | ||
|
|
7c0d5756ff | ||
|
|
91a7ee6c20 | ||
|
|
74512aa282 | ||
|
|
beaf6f7436 | ||
|
|
63b4f0ae1a | ||
|
|
5bea8a649b | ||
|
|
2e3423b053 | ||
|
|
1244f3d58f | ||
|
|
656f0895ed | ||
|
|
5a51aac85e | ||
|
|
c3e845ab7e | ||
|
|
ce4d3e175c | ||
|
|
fb86e4f6fa | ||
|
|
da6ac7fb26 | ||
|
|
07754c047c | ||
|
|
67089022bf | ||
|
|
4df5d10e3c | ||
|
|
8a915b9b8d | ||
|
|
8f1e5df672 | ||
|
|
c09c42f9a7 | ||
|
|
86a7d856fa | ||
|
|
391d6430e5 | ||
|
|
a8a7534f78 | ||
|
|
110d4c0ab0 | ||
|
|
17b9e4db8c | ||
|
|
52f44bf114 | ||
|
|
fede517b22 | ||
|
|
c746122623 | ||
|
|
ed490145d8 | ||
|
|
f3fe82415d | ||
|
|
d5602d9fb6 | ||
|
|
7716157bdb | ||
|
|
e70af5b99e | ||
|
|
f014d32147 | ||
|
|
bf14b2c41b | ||
|
|
f6cffb5eeb | ||
|
|
c634a5bf2b | ||
|
|
f8fd34ac30 | ||
|
|
c2bcb31354 | ||
|
|
7215c3446b | ||
|
|
642b72cd91 | ||
|
|
89fed501d4 | ||
|
|
28fd7fb159 | ||
|
|
85833c90ee | ||
|
|
4da1fa391e | ||
|
|
de92f5d8a7 | ||
|
|
d06ff7a7e8 | ||
|
|
a81baf2904 | ||
|
|
810c734c3f | ||
|
|
524222f094 | ||
|
|
016adee06c | ||
|
|
2b35c9e8e7 | ||
|
|
cbc46d9e78 | ||
|
|
e87a24633b | ||
|
|
14eae59c6a | ||
|
|
2418a84f02 | ||
|
|
27e0bf72c0 | ||
|
|
939193be21 | ||
|
|
00e3ae508e | ||
|
|
bc33d17ce3 | ||
|
|
65cd4835cd | ||
|
|
53010624a0 | ||
|
|
a92205be9c | ||
|
|
a16ca84346 | ||
|
|
f40f790159 | ||
|
|
88835f8468 | ||
|
|
5b0a9bbe85 | ||
|
|
6a52fc164a | ||
|
|
b4df6cb2fa | ||
|
|
932eb9777e | ||
|
|
4a1974577f | ||
|
|
dfad5f1d39 | ||
|
|
3f574c1611 | ||
|
|
8d07db0e0e | ||
|
|
bd133382f0 | ||
|
|
040b8e7e06 | ||
|
|
d9ef0e0a44 | ||
|
|
6c656663f3 | ||
|
|
291e43abac | ||
|
|
a85d5e962b | ||
|
|
11fab458c4 | ||
|
|
829cd70cd2 | ||
|
|
1d49443405 | ||
|
|
9fd566412d | ||
|
|
9331533309 | ||
|
|
43b9fefbd2 | ||
|
|
0fc15d48f3 | ||
|
|
2eef573656 | ||
|
|
f77350f8fa | ||
|
|
5282bebbd7 | ||
|
|
e2583ab5f3 | ||
|
|
950e6b9753 | ||
|
|
c110f7b8d3 | ||
|
|
86fee707fb | ||
|
|
c643fdae53 | ||
|
|
609f33c94a | ||
|
|
2f05eaa07d | ||
|
|
2ced92529d | ||
|
|
dd2e8b98de | ||
|
|
f79c88c190 | ||
|
|
4f51033aa9 | ||
|
|
503e87f153 | ||
|
|
3822241d99 | ||
|
|
e392eea160 | ||
|
|
8273855067 | ||
|
|
8bd1953094 | ||
|
|
33f85efb55 | ||
|
|
7b77eb61b5 | ||
|
|
50151ff804 | ||
|
|
4a11f70408 | ||
|
|
01b00e6dfb | ||
|
|
a32f9148fc | ||
|
|
a95b3f7ee1 | ||
|
|
04a21bbb2e | ||
|
|
618dd9d6af | ||
|
|
a92c179a6d | ||
|
|
267382af39 | ||
|
|
cfd476bb8b | ||
|
|
e875e3145f | ||
|
|
9368b6a4ee | ||
|
|
7004d1edf6 | ||
|
|
d5ab6ba728 | ||
|
|
bc78ca42a9 | ||
|
|
4806f75469 | ||
|
|
5a9dc8f991 | ||
|
|
26c151c5e4 | ||
|
|
bce73e2bd8 | ||
|
|
51ceef3dee | ||
|
|
326ade7698 | ||
|
|
502d2ede8a | ||
|
|
81dc04dd48 | ||
|
|
fe2b5351be | ||
|
|
d7fea1ba0c | ||
|
|
37ad436068 | ||
|
|
45d70b71ec | ||
|
|
d930f6956f | ||
|
|
38a7406318 | ||
|
|
83f5085551 | ||
|
|
554abb12f1 | ||
|
|
f2c16957f7 | ||
|
|
48e6df117a | ||
|
|
59254410da | ||
|
|
58a300c82a | ||
|
|
710817befb | ||
|
|
ba17cca432 | ||
|
|
f82f4bd79b | ||
|
|
589b73f646 | ||
|
|
afba2422ae | ||
|
|
58683f5376 | ||
|
|
bc6fcd90cf | ||
|
|
402f5f3178 | ||
|
|
bdeffc3fdc | ||
|
|
b4eef59100 | ||
|
|
90bc8dd3ed | ||
|
|
237eaa53e1 | ||
|
|
531ee615af | ||
|
|
fae27d262c | ||
|
|
0bd32f3f29 | ||
|
|
43aebf51d6 | ||
|
|
757a523195 | ||
|
|
7f706171a9 | ||
|
|
cd828a8691 | ||
|
|
6080108802 | ||
|
|
e8febf7f4b | ||
|
|
130bccbcbf | ||
|
|
01414ac6ec | ||
|
|
3cb004d0d3 | ||
|
|
a7d7e0daec | ||
|
|
67e196eac4 | ||
|
|
fdecd5b40f | ||
|
|
a8b1769803 | ||
|
|
8d89e56d2c | ||
|
|
fb12cfd196 | ||
|
|
ecd2b80e8f | ||
|
|
c95908bd8c | ||
|
|
c630d1f236 | ||
|
|
0d1eb8b1ea | ||
|
|
dff2137405 | ||
|
|
2523f3b939 | ||
|
|
f9fc8fd09d | ||
|
|
b49a1b4a52 | ||
|
|
df580969f7 | ||
|
|
f9c3ff244d | ||
|
|
6e3d7d9a6a | ||
|
|
54f19ff7b2 | ||
|
|
f3bd9d4241 | ||
|
|
6f3c095ed6 | ||
|
|
0fea89ec8f | ||
|
|
7706e1054d | ||
|
|
a23fbbb9a3 | ||
|
|
838dc1e189 | ||
|
|
820c03a473 | ||
|
|
311251eb91 | ||
|
|
c2a6903e19 | ||
|
|
d9c605c61f | ||
|
|
334fc54b5d | ||
|
|
bd0067ee76 | ||
|
|
4c59aa8780 | ||
|
|
aca49379a5 | ||
|
|
615c1eef6b | ||
|
|
8ea9f068c7 | ||
|
|
97ea39cf79 | ||
|
|
43d3c0a110 | ||
|
|
f02e4100db | ||
|
|
e41ca7b951 | ||
|
|
6527551d43 | ||
|
|
9cbb25e43f | ||
|
|
10698cc44d | ||
|
|
aa78f6155b | ||
|
|
6bcfb377b2 | ||
|
|
bbd7681a33 | ||
|
|
8f93e84a1a | ||
|
|
ed92af29b3 | ||
|
|
14984acd27 | ||
|
|
daca48cb15 | ||
|
|
cabe5bddb4 | ||
|
|
5a5870d3ca | ||
|
|
5c4b6678e4 | ||
|
|
10d83aaa52 |
14
.clang-format
Normal file
14
.clang-format
Normal file
@@ -0,0 +1,14 @@
|
||||
# Run manually to reformat a file:
|
||||
# clang-format -i --style=file <file>
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentCaseLabels: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
DerivePointerAlignment: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignCaseColons: false
|
||||
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # Necessary to update action hashes.
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
# Allow up to 3 opened pull requests for github-actions versions.
|
||||
open-pull-requests-limit: 3
|
||||
6
.github/issue_template.md
vendored
Normal file
6
.github/issue_template.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<!--
|
||||
Please make sure that the problem reproduces on the current master before
|
||||
submitting an issue.
|
||||
If possible please provide a repro on Compiler Explorer:
|
||||
https://godbolt.org/z/fxccbh53W.
|
||||
-->
|
||||
7
.github/pull_request_template.md
vendored
Normal file
7
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<!--
|
||||
Please read the contribution guidelines before submitting a pull request:
|
||||
https://github.com/fmtlib/fmt/blob/master/CONTRIBUTING.md.
|
||||
By submitting this pull request, you agree to license your contribution(s)
|
||||
under the terms outlined in LICENSE.rst and represent that you have the right
|
||||
to do so.
|
||||
-->
|
||||
32
.github/workflows/cifuzz.yml
vendored
Normal file
32
.github/workflows/cifuzz.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: CIFuzz
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build fuzzers
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@92182553173581f871130c71c71b17f003d47b0a
|
||||
with:
|
||||
oss-fuzz-project-name: 'fmt'
|
||||
dry-run: false
|
||||
language: c++
|
||||
|
||||
- name: Run fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@92182553173581f871130c71c71b17f003d47b0a
|
||||
with:
|
||||
oss-fuzz-project-name: 'fmt'
|
||||
fuzz-seconds: 300
|
||||
dry-run: false
|
||||
language: c++
|
||||
|
||||
- name: Upload crash
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
||||
43
.github/workflows/doc.yml
vendored
Normal file
43
.github/workflows/doc.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: doc
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken.
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
|
||||
- name: Add Ubuntu mirrors
|
||||
run: |
|
||||
# Github Actions caching proxy is at times unreliable
|
||||
# see https://github.com/actions/runner-images/issues/7048
|
||||
printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt
|
||||
curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt
|
||||
sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list
|
||||
|
||||
- name: Create build environment
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install doxygen
|
||||
pip install mkdocs-material==9.5.25 mkdocstrings==0.25.1 mike==2.1.1
|
||||
cmake -E make_directory ${{runner.workspace}}/build
|
||||
# Workaround https://github.com/actions/checkout/issues/13:
|
||||
git config --global user.name "$(git --no-pager log --format=format:'%an' -n 1)"
|
||||
git config --global user.email "$(git --no-pager log --format=format:'%ae' -n 1)"
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: $GITHUB_WORKSPACE/support/mkdocs deploy dev
|
||||
|
||||
- name: Deploy
|
||||
env:
|
||||
KEY: "${{secrets.KEY}}"
|
||||
if: env.KEY != '' && github.ref == 'refs/heads/master'
|
||||
working-directory: ${{runner.workspace}}/fmt/build/fmt.dev
|
||||
run: git push https://$KEY@github.com/fmtlib/fmt.dev.git
|
||||
28
.github/workflows/lint.yml
vendored
Normal file
28
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.h'
|
||||
- '**.cc'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
format_code:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
sudo bash ./llvm.sh 17
|
||||
sudo apt install clang-format-17
|
||||
|
||||
- name: Run clang-format
|
||||
run: |
|
||||
find include src -name '*.h' -o -name '*.cc' | \
|
||||
xargs clang-format-17 -i -style=file -fallback-style=none
|
||||
git diff --exit-code
|
||||
118
.github/workflows/linux.yml
vendored
Normal file
118
.github/workflows/linux.yml
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
name: linux
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
cxx: [g++-4.9, g++-10, clang++-9]
|
||||
build_type: [Debug, Release]
|
||||
std: [11]
|
||||
shared: [""]
|
||||
include:
|
||||
- cxx: g++-4.9
|
||||
install: sudo apt install g++-4.9
|
||||
- cxx: g++-8
|
||||
build_type: Debug
|
||||
std: 14
|
||||
install: sudo apt install g++-8
|
||||
- cxx: g++-8
|
||||
build_type: Debug
|
||||
std: 17
|
||||
install: sudo apt install g++-8
|
||||
- cxx: g++-9
|
||||
build_type: Debug
|
||||
std: 17
|
||||
- cxx: g++-10
|
||||
build_type: Debug
|
||||
std: 17
|
||||
- cxx: g++-11
|
||||
build_type: Debug
|
||||
std: 20
|
||||
install: sudo apt install g++-11
|
||||
- cxx: clang++-8
|
||||
build_type: Debug
|
||||
std: 17
|
||||
cxxflags: -stdlib=libc++
|
||||
install: sudo apt install clang-8 libc++-8-dev libc++abi-8-dev
|
||||
- cxx: clang++-9
|
||||
install: sudo apt install clang-9
|
||||
- cxx: clang++-9
|
||||
build_type: Debug
|
||||
fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON
|
||||
std: 17
|
||||
install: sudo apt install clang-9
|
||||
- cxx: clang++-11
|
||||
build_type: Debug
|
||||
std: 20
|
||||
- cxx: clang++-11
|
||||
build_type: Debug
|
||||
std: 20
|
||||
cxxflags: -stdlib=libc++
|
||||
install: sudo apt install libc++-11-dev libc++abi-11-dev
|
||||
- cxx: g++-13
|
||||
build_type: Release
|
||||
std: 23
|
||||
install: sudo apt install g++-13
|
||||
shared: -DBUILD_SHARED_LIBS=ON
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
|
||||
- name: Set timezone
|
||||
run: sudo timedatectl set-timezone 'Asia/Yekaterinburg'
|
||||
|
||||
- name: Add repositories for older GCC
|
||||
run: |
|
||||
# Below repo provides GCC 4.9.
|
||||
sudo apt-add-repository 'deb http://dk.archive.ubuntu.com/ubuntu/ xenial main'
|
||||
sudo apt-add-repository 'deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe'
|
||||
if: ${{ matrix.cxx == 'g++-4.9' }}
|
||||
|
||||
- name: Add repositories for newer GCC
|
||||
run: |
|
||||
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||
if: ${{ matrix.cxx == 'g++-11' || matrix.cxx == 'g++-13' }}
|
||||
|
||||
- name: Add Ubuntu mirrors
|
||||
run: |
|
||||
# Github Actions caching proxy is at times unreliable
|
||||
# see https://github.com/actions/runner-images/issues/7048
|
||||
printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt
|
||||
curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt
|
||||
sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list
|
||||
|
||||
- name: Create Build Environment
|
||||
run: |
|
||||
sudo apt update
|
||||
${{matrix.install}}
|
||||
sudo apt install locales-all
|
||||
cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Configure
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
CXXFLAGS: ${{matrix.cxxflags}}
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.fuzz}} ${{matrix.shared}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} -DFMT_DOC=OFF \
|
||||
-DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
|
||||
-DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: |
|
||||
threads=`nproc`
|
||||
cmake --build . --config ${{matrix.build_type}} --parallel $threads
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: ctest -C ${{matrix.build_type}}
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: True
|
||||
58
.github/workflows/macos.yml
vendored
Normal file
58
.github/workflows/macos.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: macos
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-13, macos-14]
|
||||
build_type: [Debug, Release]
|
||||
std: [11, 17, 20]
|
||||
shared: [""]
|
||||
exclude:
|
||||
- { os: macos-13, std: 11 }
|
||||
- { os: macos-13, std: 17 }
|
||||
include:
|
||||
- os: macos-14
|
||||
std: 23
|
||||
build_type: Release
|
||||
shared: -DBUILD_SHARED_LIBS=ON
|
||||
|
||||
runs-on: '${{ matrix.os }}'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
|
||||
- name: Set timezone
|
||||
run: sudo systemsetup -settimezone 'Asia/Yekaterinburg'
|
||||
|
||||
- name: Select Xcode 14.3 (macOS 13)
|
||||
run: sudo xcode-select -s "/Applications/Xcode_14.3.app"
|
||||
if: ${{ matrix.os == 'macos-13' }}
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Configure
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.shared}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
-DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
|
||||
-DFMT_DOC=OFF -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: |
|
||||
threads=`sysctl -n hw.logicalcpu`
|
||||
cmake --build . --config ${{matrix.build_type}} --parallel $threads
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: ctest -C ${{matrix.build_type}}
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: True
|
||||
65
.github/workflows/scorecard.yml
vendored
Normal file
65
.github/workflows/scorecard.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '26 14 * * 5'
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
# Needed to publish results and get a badge (see publish_results below).
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
95
.github/workflows/windows.yml
vendored
Normal file
95
.github/workflows/windows.yml
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
name: windows
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
# windows-2019 has MSVC 2019 installed;
|
||||
# windows-2022 has MSVC 2022 installed:
|
||||
# https://github.com/actions/virtual-environments.
|
||||
os: [windows-2019]
|
||||
platform: [Win32, x64]
|
||||
toolset: [v141, v142]
|
||||
standard: [14, 17, 20]
|
||||
shared: ["", -DBUILD_SHARED_LIBS=ON]
|
||||
build_type: [Debug, Release]
|
||||
exclude:
|
||||
- { toolset: v141, standard: 20 }
|
||||
- { toolset: v142, standard: 14 }
|
||||
- { platform: Win32, toolset: v141 }
|
||||
- { platform: Win32, standard: 14 }
|
||||
- { platform: Win32, standard: 20 }
|
||||
- { platform: x64, toolset: v141, shared: -DBUILD_SHARED_LIBS=ON }
|
||||
- { platform: x64, standard: 14, shared: -DBUILD_SHARED_LIBS=ON }
|
||||
- { platform: x64, standard: 20, shared: -DBUILD_SHARED_LIBS=ON }
|
||||
include:
|
||||
- os: windows-2022
|
||||
platform: x64
|
||||
toolset: v143
|
||||
build_type: Debug
|
||||
standard: 20
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
|
||||
- name: Set timezone
|
||||
run: tzutil /s "Ekaterinburg Standard Time"
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Configure
|
||||
# Use a bash shell for $GITHUB_WORKSPACE.
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: |
|
||||
cmake -A ${{matrix.platform}} -T ${{matrix.toolset}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.standard}} \
|
||||
${{matrix.shared}} -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
$GITHUB_WORKSPACE
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: |
|
||||
$threads = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors
|
||||
cmake --build . --config ${{matrix.build_type}} --parallel $threads
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: ctest -C ${{matrix.build_type}} -V
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: True
|
||||
|
||||
mingw:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
strategy:
|
||||
matrix:
|
||||
sys: [ mingw64, ucrt64 ]
|
||||
steps:
|
||||
- name: Set timezone
|
||||
run: tzutil /s "Ekaterinburg Standard Time"
|
||||
shell: cmd
|
||||
- uses: msys2/setup-msys2@c52d1fa9c7492275e60fe763540fb601f5f232a1 # v2.25.0
|
||||
with:
|
||||
release: false
|
||||
msystem: ${{matrix.sys}}
|
||||
pacboy: cc:p cmake:p ninja:p lld:p
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- name: Configure
|
||||
run: cmake -B ../build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
env: { LDFLAGS: -fuse-ld=lld }
|
||||
- name: Build
|
||||
run: cmake --build ../build
|
||||
- name: Test
|
||||
run: ctest -j `nproc` --test-dir ../build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: True
|
||||
29
.gitignore
vendored
29
.gitignore
vendored
@@ -1,17 +1,20 @@
|
||||
/_CPack_Packages
|
||||
/doc/conf.py
|
||||
/doc/doxyxml
|
||||
/doc/html
|
||||
/Testing
|
||||
/*-test
|
||||
/install_manifest.txt
|
||||
/tinyformat_speed_test
|
||||
*~
|
||||
*.a
|
||||
*.zip
|
||||
cmake_install.cmake
|
||||
CPack*Config.cmake
|
||||
CTestTestfile.cmake
|
||||
*.so*
|
||||
*.xcodeproj
|
||||
*~
|
||||
.vscode/
|
||||
/CMakeScripts
|
||||
/Testing
|
||||
/_CPack_Packages
|
||||
/install_manifest.txt
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CPack*.cmake
|
||||
CTestTestfile.cmake
|
||||
FMT.build
|
||||
Makefile
|
||||
bin/
|
||||
build/
|
||||
cmake_install.cmake
|
||||
fmt-*.cmake
|
||||
fmt.pc
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "breathe"]
|
||||
path = breathe
|
||||
url = git://github.com/vitaut/breathe.git
|
||||
[submodule "doc/sphinx-bootstrap-theme"]
|
||||
path = doc/sphinx-bootstrap-theme
|
||||
url = https://github.com/cppformat/sphinx-bootstrap-theme.git
|
||||
23
.travis.yml
23
.travis.yml
@@ -1,23 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
before_install:
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then curl http://www.cmake.org/files/v2.8/cmake-2.8.12.2-Darwin64-universal.tar.gz -o cmake.tar.gz; fi
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then tar xzf cmake.tar.gz; fi
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then export PATH=$PATH:"cmake-2.8.12.2-Darwin64-universal/CMake 2.8-12.app/Contents/bin"; fi
|
||||
- git submodule update --init
|
||||
|
||||
env:
|
||||
- BUILD_TYPE=Debug
|
||||
- BUILD_TYPE=Release
|
||||
|
||||
script:
|
||||
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFMT_EXTRA_TESTS=ON .
|
||||
- make -j4
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 make test
|
||||
|
||||
after_failure:
|
||||
- cat Testing/Temporary/LastTest.log
|
||||
551
CMakeLists.txt
551
CMakeLists.txt
@@ -1,36 +1,274 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_minimum_required(VERSION 3.8...3.28)
|
||||
|
||||
# Fallback for using newer policies on CMake <3.12.
|
||||
if (${CMAKE_VERSION} VERSION_LESS 3.12)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
endif ()
|
||||
|
||||
# Determine if fmt is built as a subproject (using add_subdirectory)
|
||||
# or if it is the master project.
|
||||
if (NOT DEFINED FMT_MASTER_PROJECT)
|
||||
set(FMT_MASTER_PROJECT OFF)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(FMT_MASTER_PROJECT ON)
|
||||
message(STATUS "CMake version: ${CMAKE_VERSION}")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Joins arguments and places the results in ${result_var}.
|
||||
function(join result_var)
|
||||
set(result "")
|
||||
foreach (arg ${ARGN})
|
||||
set(result "${result}${arg}")
|
||||
endforeach ()
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# DEPRECATED! Should be merged into add_module_library.
|
||||
function(enable_module target)
|
||||
if (MSVC)
|
||||
set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc)
|
||||
target_compile_options(${target}
|
||||
PRIVATE /interface /ifcOutput ${BMI}
|
||||
INTERFACE /reference fmt=${BMI})
|
||||
set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI})
|
||||
set_source_files_properties(${BMI} PROPERTIES GENERATED ON)
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
set(FMT_USE_CMAKE_MODULES FALSE)
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.28 AND
|
||||
CMAKE_GENERATOR STREQUAL "Ninja")
|
||||
set(FMT_USE_CMAKE_MODULES TRUE)
|
||||
endif ()
|
||||
|
||||
# Adds a library compiled with C++20 module support.
|
||||
# `enabled` is a CMake variables that specifies if modules are enabled.
|
||||
# If modules are disabled `add_module_library` falls back to creating a
|
||||
# non-modular library.
|
||||
#
|
||||
# Usage:
|
||||
# add_module_library(<name> [sources...] FALLBACK [sources...] [IF enabled])
|
||||
function(add_module_library name)
|
||||
cmake_parse_arguments(AML "" "IF" "FALLBACK" ${ARGN})
|
||||
set(sources ${AML_UNPARSED_ARGUMENTS})
|
||||
|
||||
add_library(${name})
|
||||
set_target_properties(${name} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
if (NOT ${${AML_IF}})
|
||||
# Create a non-modular library.
|
||||
target_sources(${name} PRIVATE ${AML_FALLBACK})
|
||||
set_target_properties(${name} PROPERTIES CXX_SCAN_FOR_MODULES OFF)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Modules require C++20.
|
||||
target_compile_features(${name} PUBLIC cxx_std_20)
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
target_compile_options(${name} PUBLIC -fmodules-ts)
|
||||
endif ()
|
||||
|
||||
if (FMT_USE_CMAKE_MODULES)
|
||||
target_sources(${name} PUBLIC FILE_SET fmt TYPE CXX_MODULES
|
||||
FILES ${sources})
|
||||
else()
|
||||
# `std` is affected by CMake options and may be higher than C++20.
|
||||
get_target_property(std ${name} CXX_STANDARD)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(pcms)
|
||||
foreach (src ${sources})
|
||||
get_filename_component(pcm ${src} NAME_WE)
|
||||
set(pcm ${pcm}.pcm)
|
||||
|
||||
# Propagate -fmodule-file=*.pcm to targets that link with this library.
|
||||
target_compile_options(
|
||||
${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR}/${pcm})
|
||||
|
||||
# Use an absolute path to prevent target_link_libraries prepending -l
|
||||
# to it.
|
||||
set(pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR}/${pcm})
|
||||
add_custom_command(
|
||||
OUTPUT ${pcm}
|
||||
COMMAND ${CMAKE_CXX_COMPILER}
|
||||
-std=c++${std} -x c++-module --precompile -c
|
||||
-o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR}/${src}
|
||||
"-I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;-I>"
|
||||
# Required by the -I generator expression above.
|
||||
COMMAND_EXPAND_LISTS
|
||||
DEPENDS ${src})
|
||||
endforeach ()
|
||||
|
||||
# Add .pcm files as sources to make sure they are built before the library.
|
||||
set(sources)
|
||||
foreach (pcm ${pcms})
|
||||
get_filename_component(pcm_we ${pcm} NAME_WE)
|
||||
set(obj ${pcm_we}.o)
|
||||
# Use an absolute path to prevent target_link_libraries prepending -l.
|
||||
set(sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR}/${obj})
|
||||
add_custom_command(
|
||||
OUTPUT ${obj}
|
||||
COMMAND ${CMAKE_CXX_COMPILER} $<TARGET_PROPERTY:${name},COMPILE_OPTIONS>
|
||||
-c -o ${obj} ${pcm}
|
||||
DEPENDS ${pcm})
|
||||
endforeach ()
|
||||
endif ()
|
||||
target_sources(${name} PRIVATE ${sources})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
# Sets a cache variable with a docstring joined from multiple arguments:
|
||||
# set(<variable> <value>... CACHE <type> <docstring>...)
|
||||
# This allows splitting a long docstring for readability.
|
||||
function(set_verbose)
|
||||
# cmake_parse_arguments is broken in CMake 3.4 (cannot parse CACHE) so use
|
||||
# list instead.
|
||||
list(GET ARGN 0 var)
|
||||
list(REMOVE_AT ARGN 0)
|
||||
list(GET ARGN 0 val)
|
||||
list(REMOVE_AT ARGN 0)
|
||||
list(REMOVE_AT ARGN 0)
|
||||
list(GET ARGN 0 type)
|
||||
list(REMOVE_AT ARGN 0)
|
||||
join(doc ${ARGN})
|
||||
set(${var} ${val} CACHE ${type} ${doc})
|
||||
endfunction()
|
||||
|
||||
# Set the default CMAKE_BUILD_TYPE to Release.
|
||||
# This should be done before the project command since the latter can set
|
||||
# CMAKE_BUILD_TYPE itself (it does so for nmake).
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
"Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
|
||||
if (FMT_MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
|
||||
set_verbose(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
"Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
|
||||
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
|
||||
endif ()
|
||||
|
||||
option(FMT_EXTRA_TESTS "Enable extra tests." OFF)
|
||||
project(FMT CXX)
|
||||
include(GNUInstallDirs)
|
||||
set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING
|
||||
"Installation directory for include files, a relative path that "
|
||||
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.")
|
||||
|
||||
project(FORMAT)
|
||||
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
|
||||
option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
|
||||
OFF)
|
||||
|
||||
# Options that control generation of various targets.
|
||||
option(FMT_DOC "Generate the doc target." ${FMT_MASTER_PROJECT})
|
||||
option(FMT_INSTALL "Generate the install target." ON)
|
||||
option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT})
|
||||
option(FMT_FUZZ "Generate the fuzz target." OFF)
|
||||
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
|
||||
option(FMT_OS "Include OS-specific APIs." ON)
|
||||
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
|
||||
option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF)
|
||||
option(FMT_UNICODE "Enable Unicode support." ON)
|
||||
|
||||
if (FMT_TEST AND FMT_MODULE)
|
||||
# The tests require {fmt} to be compiled as traditional library
|
||||
message(STATUS "Testing is incompatible with build mode 'module'.")
|
||||
endif ()
|
||||
set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
|
||||
if (FMT_SYSTEM_HEADERS)
|
||||
set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
|
||||
endif ()
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "MSDOS")
|
||||
set(FMT_TEST OFF)
|
||||
message(STATUS "MSDOS is incompatible with gtest")
|
||||
endif ()
|
||||
|
||||
# Get version from base.h
|
||||
file(READ include/fmt/base.h base_h)
|
||||
if (NOT base_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])")
|
||||
message(FATAL_ERROR "Cannot get FMT_VERSION from base.h.")
|
||||
endif ()
|
||||
# Use math to skip leading zeros if any.
|
||||
math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.
|
||||
${CPACK_PACKAGE_VERSION_PATCH})
|
||||
message(STATUS "{fmt} version: ${FMT_VERSION}")
|
||||
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag(-std=c++11 HAVE_STD_CPP11_FLAG)
|
||||
if (HAVE_STD_CPP11_FLAG)
|
||||
set(CPP11_FLAG -std=c++11)
|
||||
else ()
|
||||
check_cxx_compiler_flag(-std=c++0x HAVE_STD_CPP0X_FLAG)
|
||||
if (HAVE_STD_CPP0X_FLAG)
|
||||
set(CPP11_FLAG -std=c++0x)
|
||||
endif ()
|
||||
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
endif ()
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
|
||||
|
||||
if (CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(JoinPaths)
|
||||
|
||||
if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
|
||||
set_verbose(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING
|
||||
"Preset for the export of private symbols")
|
||||
set_property(CACHE CMAKE_CXX_VISIBILITY_PRESET PROPERTY STRINGS
|
||||
hidden default)
|
||||
endif ()
|
||||
|
||||
if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN)
|
||||
set_verbose(CMAKE_VISIBILITY_INLINES_HIDDEN ON CACHE BOOL
|
||||
"Whether to add a compile flag to hide symbols of inline functions")
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
|
||||
-Wold-style-cast -Wundef
|
||||
-Wredundant-decls -Wwrite-strings -Wpointer-arith
|
||||
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
|
||||
-Wcast-align
|
||||
-Wctor-dtor-privacy -Wdisabled-optimization
|
||||
-Winvalid-pch -Woverloaded-virtual
|
||||
-Wconversion -Wundef
|
||||
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
|
||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
||||
-Wno-dangling-else -Wno-unused-local-typedefs)
|
||||
endif ()
|
||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion
|
||||
-Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast
|
||||
-Wvector-operation-performance -Wsized-deallocation -Wshadow)
|
||||
endif ()
|
||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
|
||||
-Wduplicated-cond)
|
||||
# Workaround for GCC regression
|
||||
# [12/13/14/15 regression] New (since gcc 12) false positive null-dereference in vector.resize
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108860
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnull-dereference)
|
||||
endif ()
|
||||
endif ()
|
||||
set(WERROR_FLAG -Werror)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef
|
||||
-Wdeprecated -Wweak-vtables -Wshadow
|
||||
-Wno-gnu-zero-variadic-macro-arguments)
|
||||
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
|
||||
if (HAS_NULLPTR_WARNING)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
||||
-Wzero-as-null-pointer-constant)
|
||||
endif ()
|
||||
set(WERROR_FLAG -Werror)
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
set(PEDANTIC_COMPILE_FLAGS /W3)
|
||||
set(WERROR_FLAG /WX)
|
||||
endif ()
|
||||
|
||||
if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
# If Microsoft SDK is installed create script run-msbuild.bat that
|
||||
# calls SetEnv.cmd to to set up build environment and runs msbuild.
|
||||
# calls SetEnv.cmd to set up build environment and runs msbuild.
|
||||
# It is useful when building Visual Studio projects with the SDK
|
||||
# toolchain rather than Visual Studio.
|
||||
include(FindSetEnv)
|
||||
@@ -38,94 +276,255 @@ if (CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
|
||||
endif ()
|
||||
# Set FrameworkPathOverride to get rid of MSB3644 warnings.
|
||||
set(netfxpath "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0")
|
||||
join(netfxpath
|
||||
"C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\"
|
||||
".NETFramework\\v4.0")
|
||||
file(WRITE run-msbuild.bat "
|
||||
${MSBUILD_SETUP}
|
||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||
endif ()
|
||||
|
||||
option(FMT_SHARED "Build shared library instead of static one" OFF)
|
||||
if (FMT_SHARED)
|
||||
set(shared SHARED)
|
||||
function(add_headers VAR)
|
||||
set(headers ${${VAR}})
|
||||
foreach (header ${ARGN})
|
||||
set(headers ${headers} include/fmt/${header})
|
||||
endforeach()
|
||||
set(${VAR} ${headers} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Define the fmt library, its includes and the needed defines.
|
||||
set(FMT_HEADERS)
|
||||
add_headers(FMT_HEADERS args.h base.h chrono.h color.h compile.h core.h format.h
|
||||
format-inl.h os.h ostream.h printf.h ranges.h std.h
|
||||
xchar.h)
|
||||
set(FMT_SOURCES src/format.cc)
|
||||
|
||||
add_module_library(fmt src/fmt.cc FALLBACK
|
||||
${FMT_SOURCES} ${FMT_HEADERS} README.md ChangeLog.md
|
||||
IF FMT_MODULE)
|
||||
add_library(fmt::fmt ALIAS fmt)
|
||||
if (FMT_MODULE)
|
||||
enable_module(fmt)
|
||||
elseif (FMT_OS)
|
||||
target_sources(fmt PRIVATE src/os.cc)
|
||||
else()
|
||||
target_compile_definitions(fmt PRIVATE FMT_OS=0)
|
||||
endif ()
|
||||
|
||||
set(FMT_SOURCES format.cc format.h)
|
||||
if (FMT_WERROR)
|
||||
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
||||
endif ()
|
||||
if (FMT_PEDANTIC)
|
||||
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
endif ()
|
||||
|
||||
include(CheckSymbolExists)
|
||||
if (WIN32)
|
||||
check_symbol_exists(open io.h HAVE_OPEN)
|
||||
if (cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
|
||||
target_compile_features(fmt PUBLIC cxx_std_11)
|
||||
else ()
|
||||
check_symbol_exists(open fcntl.h HAVE_OPEN)
|
||||
endif ()
|
||||
if (HAVE_OPEN)
|
||||
add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1)
|
||||
set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h)
|
||||
message(WARNING "Feature cxx_std_11 is unknown for the CXX compiler")
|
||||
endif ()
|
||||
|
||||
if (CPP11_FLAG)
|
||||
set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG})
|
||||
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||
|
||||
set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
|
||||
|
||||
set_target_properties(fmt PROPERTIES
|
||||
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
PUBLIC_HEADER "${FMT_HEADERS}"
|
||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}"
|
||||
|
||||
# Workaround for Visual Studio 2017:
|
||||
# Ensure the .pdb is created with the same name and in the same directory
|
||||
# as the .lib. Newer VS versions already do this by default, but there is no
|
||||
# harm in setting it for those too. Ignored by other generators.
|
||||
COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
COMPILE_PDB_NAME "fmt"
|
||||
COMPILE_PDB_NAME_DEBUG "fmt${FMT_DEBUG_POSTFIX}")
|
||||
|
||||
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
||||
# property because it's not set by default.
|
||||
set(FMT_LIB_NAME fmt)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(FMT_LIB_NAME ${FMT_LIB_NAME}${FMT_DEBUG_POSTFIX})
|
||||
endif ()
|
||||
|
||||
add_library(format ${shared} ${FMT_SOURCES})
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set_target_properties(format PROPERTIES COMPILE_FLAGS
|
||||
"-Wall -Wextra -pedantic")
|
||||
if (BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(fmt PRIVATE FMT_LIB_EXPORT INTERFACE FMT_SHARED)
|
||||
endif ()
|
||||
if (CPP11_FLAG AND FMT_EXTRA_TESTS)
|
||||
set_target_properties(format PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
|
||||
# Test compilation with default flags.
|
||||
file(GLOB src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cc test/*.h)
|
||||
add_library(testformat ${FMT_SOURCE_FILES} ${src})
|
||||
if (FMT_SAFE_DURATION_CAST)
|
||||
target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(doc)
|
||||
add_library(fmt-header-only INTERFACE)
|
||||
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
|
||||
|
||||
include_directories(. gmock)
|
||||
|
||||
# We compile Google Test ourselves instead of using pre-compiled libraries.
|
||||
# See the Google Test FAQ "Why is it not recommended to install a
|
||||
# pre-compiled copy of Google Test (for example, into /usr/local)?"
|
||||
# at http://code.google.com/p/googletest/wiki/FAQ for more details.
|
||||
|
||||
add_library(gmock gmock/gmock-gtest-all.cc)
|
||||
find_package(Threads)
|
||||
target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
# Check if variadic templates are working and not affected by GCC bug 39653:
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
|
||||
check_cxx_source_compiles("
|
||||
template <class T, class ...Types>
|
||||
struct S { typedef typename S<Types...>::type type; };
|
||||
int main() {}" FMT_VARIADIC_TEMPLATES)
|
||||
if (NOT FMT_VARIADIC_TEMPLATES)
|
||||
add_definitions(-DGTEST_LANG_CXX11=0)
|
||||
if (NOT MSVC)
|
||||
# Unicode is always supported on compilers other than MSVC.
|
||||
elseif (FMT_UNICODE)
|
||||
# Unicode support requires compiling with /utf-8.
|
||||
target_compile_options(fmt PUBLIC $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
|
||||
target_compile_options(fmt-header-only INTERFACE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
|
||||
else ()
|
||||
target_compile_definitions(fmt PUBLIC FMT_UNICODE=0)
|
||||
endif ()
|
||||
|
||||
# GTest doesn't detect <tuple> with clang.
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_definitions(gmock PUBLIC GTEST_USE_OWN_TR1_TUPLE=1)
|
||||
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
|
||||
target_compile_features(fmt-header-only INTERFACE cxx_std_11)
|
||||
|
||||
target_include_directories(fmt-header-only
|
||||
${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE INTERFACE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||
|
||||
# Install targets.
|
||||
if (FMT_INSTALL)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
|
||||
"Installation directory for cmake files, a relative path that "
|
||||
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute "
|
||||
"path.")
|
||||
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
|
||||
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
|
||||
set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
|
||||
set(targets_export_name fmt-targets)
|
||||
|
||||
set_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
|
||||
"Installation directory for libraries, a relative path that "
|
||||
"will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.")
|
||||
|
||||
set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE STRING
|
||||
"Installation directory for pkgconfig (.pc) files, a relative "
|
||||
"path that will be joined with ${CMAKE_INSTALL_PREFIX} or an "
|
||||
"absolute path.")
|
||||
|
||||
# Generate the version, config and target files into the build directory.
|
||||
write_basic_package_version_file(
|
||||
${version_config}
|
||||
VERSION ${FMT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
join_paths(libdir_for_pc_file "\${exec_prefix}" "${FMT_LIB_DIR}")
|
||||
join_paths(includedir_for_pc_file "\${prefix}" "${FMT_INC_DIR}")
|
||||
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in"
|
||||
"${pkgconfig}"
|
||||
@ONLY)
|
||||
configure_package_config_file(
|
||||
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
|
||||
${project_config}
|
||||
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
|
||||
|
||||
set(INSTALL_TARGETS fmt fmt-header-only)
|
||||
|
||||
set(INSTALL_FILE_SET)
|
||||
if (FMT_USE_CMAKE_MODULES)
|
||||
set(INSTALL_FILE_SET FILE_SET fmt DESTINATION "${FMT_INC_DIR}/fmt")
|
||||
endif()
|
||||
|
||||
# Install the library and headers.
|
||||
install(TARGETS ${INSTALL_TARGETS}
|
||||
COMPONENT fmt-core
|
||||
EXPORT ${targets_export_name}
|
||||
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
||||
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
||||
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
${INSTALL_FILE_SET})
|
||||
|
||||
# Use a namespace because CMake provides better diagnostics for namespaced
|
||||
# imported targets.
|
||||
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
|
||||
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
|
||||
|
||||
# Install version, config and target files.
|
||||
install(FILES ${project_config} ${version_config}
|
||||
DESTINATION ${FMT_CMAKE_DIR}
|
||||
COMPONENT fmt-core)
|
||||
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
|
||||
NAMESPACE fmt::
|
||||
COMPONENT fmt-core)
|
||||
|
||||
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}"
|
||||
COMPONENT fmt-core)
|
||||
endif ()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
function(add_doc_target)
|
||||
find_program(DOXYGEN doxygen
|
||||
PATHS "$ENV{ProgramFiles}/doxygen/bin"
|
||||
"$ENV{ProgramFiles\(x86\)}/doxygen/bin")
|
||||
if (NOT DOXYGEN)
|
||||
message(STATUS "Target 'doc' disabled because doxygen not found")
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
if (EXISTS .gitignore)
|
||||
find_program(MKDOCS mkdocs)
|
||||
if (NOT MKDOCS)
|
||||
message(STATUS "Target 'doc' disabled because mkdocs not found")
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
set(sources )
|
||||
foreach (source api.md index.md syntax.md get-started.md fmt.css fmt.js)
|
||||
set(sources ${sources} doc/${source})
|
||||
endforeach()
|
||||
|
||||
add_custom_target(
|
||||
doc
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-E env PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}/support/python
|
||||
${MKDOCS} build -f ${CMAKE_CURRENT_SOURCE_DIR}/support/mkdocs.yml
|
||||
# MkDocs requires the site dir to be outside of the doc dir.
|
||||
--site-dir ${CMAKE_CURRENT_BINARY_DIR}/doc-html
|
||||
--no-directory-urls
|
||||
SOURCES ${sources})
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc-html/
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt
|
||||
COMPONENT fmt-doc OPTIONAL)
|
||||
endfunction()
|
||||
|
||||
if (FMT_DOC)
|
||||
add_doc_target()
|
||||
endif ()
|
||||
|
||||
if (FMT_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif ()
|
||||
|
||||
# Control fuzzing independent of the unit tests.
|
||||
if (FMT_FUZZ)
|
||||
add_subdirectory(test/fuzzing)
|
||||
|
||||
# The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing
|
||||
# mode and make fuzzing practically possible. It is similar to
|
||||
# FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to
|
||||
# avoid interfering with fuzzing of projects that use {fmt}.
|
||||
# See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode.
|
||||
target_compile_definitions(fmt PUBLIC FMT_FUZZ)
|
||||
endif ()
|
||||
|
||||
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
|
||||
if (FMT_MASTER_PROJECT AND EXISTS ${gitignore})
|
||||
# Get the list of ignored files from .gitignore.
|
||||
file (STRINGS ".gitignore" lines)
|
||||
LIST(REMOVE_ITEM lines /doc/html)
|
||||
file (STRINGS ${gitignore} lines)
|
||||
list(REMOVE_ITEM lines /doc/html)
|
||||
foreach (line ${lines})
|
||||
string(REPLACE "." "[.]" line "${line}")
|
||||
string(REPLACE "*" ".*" line "${line}")
|
||||
set(ignored_files ${ignored_files} "${line}$" "${line}/")
|
||||
endforeach ()
|
||||
set(ignored_files ${ignored_files} /.git /breathe /format-benchmark sphinx/)
|
||||
set(ignored_files ${ignored_files} /.git /build/doxyxml .vagrant)
|
||||
|
||||
set(CPACK_SOURCE_GENERATOR ZIP)
|
||||
set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 0)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 12)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME cppformat-${CPPFORMAT_VERSION})
|
||||
set(CPACK_RESOURCE_FILE_README ${FORMAT_SOURCE_DIR}/README.rst)
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION})
|
||||
set(CPACK_PACKAGE_NAME fmt)
|
||||
set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.md)
|
||||
include(CPack)
|
||||
endif ()
|
||||
|
||||
20
CONTRIBUTING.md
Normal file
20
CONTRIBUTING.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Contributing to {fmt}
|
||||
=====================
|
||||
|
||||
By submitting a pull request or a patch, you represent that you have the right
|
||||
to license your contribution to the {fmt} project owners and the community,
|
||||
agree that your contributions are licensed under the {fmt} license, and agree
|
||||
to future changes to the licensing.
|
||||
|
||||
All C++ code must adhere to [Google C++ Style Guide](
|
||||
https://google.github.io/styleguide/cppguide.html) with the following
|
||||
exceptions:
|
||||
|
||||
* Exceptions are permitted
|
||||
* snake_case should be used instead of UpperCamelCase for function and type
|
||||
names
|
||||
|
||||
All documentation must adhere to the [Google Developer Documentation Style
|
||||
Guide](https://developers.google.com/style).
|
||||
|
||||
Thanks for contributing!
|
||||
2924
ChangeLog.md
Normal file
2924
ChangeLog.md
Normal file
File diff suppressed because it is too large
Load Diff
27
LICENSE
Normal file
27
LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
|
||||
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.
|
||||
|
||||
--- Optional exception to the license ---
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into a machine-executable object form of such
|
||||
source code, you may redistribute such embedded portions in such object form
|
||||
without including the above copyright and permission notices.
|
||||
485
README.md
Normal file
485
README.md
Normal file
@@ -0,0 +1,485 @@
|
||||
<img src="https://user-images.githubusercontent.com/576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png" alt="{fmt}" width="25%"/>
|
||||
|
||||
[](https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux)
|
||||
[](https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos)
|
||||
[](https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?\%0Acolspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\%0ASummary&q=proj%3Dfmt&can=1)
|
||||
[](https://stackoverflow.com/questions/tagged/fmt)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt)
|
||||
|
||||
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||
alternative to C stdio and C++ iostreams.
|
||||
|
||||
If you like this project, please consider donating to one of the funds
|
||||
that help victims of the war in Ukraine: <https://www.stopputin.net/>.
|
||||
|
||||
[Documentation](https://fmt.dev)
|
||||
|
||||
[Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html)
|
||||
|
||||
Q&A: ask questions on [StackOverflow with the tag
|
||||
fmt](https://stackoverflow.com/questions/tagged/fmt).
|
||||
|
||||
Try {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v).
|
||||
|
||||
# Features
|
||||
|
||||
- Simple [format API](https://fmt.dev/latest/api/) with positional
|
||||
arguments for localization
|
||||
- Implementation of [C++20
|
||||
std::format](https://en.cppreference.com/w/cpp/utility/format) and
|
||||
[C++23 std::print](https://en.cppreference.com/w/cpp/io/print)
|
||||
- [Format string syntax](https://fmt.dev/latest/syntax/) similar
|
||||
to Python\'s
|
||||
[format](https://docs.python.org/3/library/stdtypes.html#str.format)
|
||||
- Fast IEEE 754 floating-point formatter with correct rounding,
|
||||
shortness and round-trip guarantees using the
|
||||
[Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm
|
||||
- Portable Unicode support
|
||||
- Safe [printf
|
||||
implementation](https://fmt.dev/latest/api/#printf-formatting)
|
||||
including the POSIX extension for positional arguments
|
||||
- Extensibility: [support for user-defined
|
||||
types](https://fmt.dev/latest/api/#formatting-user-defined-types)
|
||||
- High performance: faster than common standard library
|
||||
implementations of `(s)printf`, iostreams, `to_string` and
|
||||
`to_chars`, see [Speed tests](#speed-tests) and [Converting a
|
||||
hundred million integers to strings per
|
||||
second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html)
|
||||
- Small code size both in terms of source code with the minimum
|
||||
configuration consisting of just three files, `core.h`, `format.h`
|
||||
and `format-inl.h`, and compiled code; see [Compile time and code
|
||||
bloat](#compile-time-and-code-bloat)
|
||||
- Reliability: the library has an extensive set of
|
||||
[tests](https://github.com/fmtlib/fmt/tree/master/test) and is
|
||||
[continuously fuzzed](https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1)
|
||||
- Safety: the library is fully type-safe, errors in format strings can
|
||||
be reported at compile time, automatic memory management prevents
|
||||
buffer overflow errors
|
||||
- Ease of use: small self-contained code base, no external
|
||||
dependencies, permissive MIT
|
||||
[license](https://github.com/fmtlib/fmt/blob/master/LICENSE)
|
||||
- [Portability](https://fmt.dev/latest/#portability) with
|
||||
consistent output across platforms and support for older compilers
|
||||
- Clean warning-free codebase even on high warning levels such as
|
||||
`-Wall -Wextra -pedantic`
|
||||
- Locale independence by default
|
||||
- Optional header-only configuration enabled with the
|
||||
`FMT_HEADER_ONLY` macro
|
||||
|
||||
See the [documentation](https://fmt.dev) for more details.
|
||||
|
||||
# Examples
|
||||
|
||||
**Print to stdout** ([run](https://godbolt.org/z/Tevcjh))
|
||||
|
||||
``` c++
|
||||
#include <fmt/core.h>
|
||||
|
||||
int main() {
|
||||
fmt::print("Hello, world!\n");
|
||||
}
|
||||
```
|
||||
|
||||
**Format a string** ([run](https://godbolt.org/z/oK8h33))
|
||||
|
||||
``` c++
|
||||
std::string s = fmt::format("The answer is {}.", 42);
|
||||
// s == "The answer is 42."
|
||||
```
|
||||
|
||||
**Format a string using positional arguments**
|
||||
([run](https://godbolt.org/z/Yn7Txe))
|
||||
|
||||
``` c++
|
||||
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
|
||||
// s == "I'd rather be happy than right."
|
||||
```
|
||||
|
||||
**Print dates and times** ([run](https://godbolt.org/z/c31ExdY3W))
|
||||
|
||||
``` c++
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
int main() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
fmt::print("Date and time: {}\n", now);
|
||||
fmt::print("Time: {:%H:%M}\n", now);
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
Date and time: 2023-12-26 19:10:31.557195597
|
||||
Time: 19:10
|
||||
|
||||
**Print a container** ([run](https://godbolt.org/z/MxM1YqjE7))
|
||||
|
||||
``` c++
|
||||
#include <vector>
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
int main() {
|
||||
std::vector<int> v = {1, 2, 3};
|
||||
fmt::print("{}\n", v);
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
[1, 2, 3]
|
||||
|
||||
**Check a format string at compile time**
|
||||
|
||||
``` c++
|
||||
std::string s = fmt::format("{:d}", "I am not a number");
|
||||
```
|
||||
|
||||
This gives a compile-time error in C++20 because `d` is an invalid
|
||||
format specifier for a string.
|
||||
|
||||
**Write a file from a single thread**
|
||||
|
||||
``` c++
|
||||
#include <fmt/os.h>
|
||||
|
||||
int main() {
|
||||
auto out = fmt::output_file("guide.txt");
|
||||
out.print("Don't {}", "Panic");
|
||||
}
|
||||
```
|
||||
|
||||
This can be [5 to 9 times faster than
|
||||
fprintf](http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html).
|
||||
|
||||
**Print with colors and text styles**
|
||||
|
||||
``` c++
|
||||
#include <fmt/color.h>
|
||||
|
||||
int main() {
|
||||
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
|
||||
"Hello, {}!\n", "world");
|
||||
fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
|
||||
fmt::emphasis::underline, "Olá, {}!\n", "Mundo");
|
||||
fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
|
||||
"你好{}!\n", "世界");
|
||||
}
|
||||
```
|
||||
|
||||
Output on a modern terminal with Unicode support:
|
||||
|
||||

|
||||
|
||||
# Benchmarks
|
||||
|
||||
## Speed tests
|
||||
|
||||
| Library | Method | Run Time, s |
|
||||
|-------------------|---------------|-------------|
|
||||
| libc | printf | 0.91 |
|
||||
| libc++ | std::ostream | 2.49 |
|
||||
| {fmt} 9.1 | fmt::print | 0.74 |
|
||||
| Boost Format 1.80 | boost::format | 6.26 |
|
||||
| Folly Format | folly::format | 1.87 |
|
||||
|
||||
{fmt} is the fastest of the benchmarked methods, \~20% faster than
|
||||
`printf`.
|
||||
|
||||
The above results were generated by building `tinyformat_test.cpp` on
|
||||
macOS 12.6.1 with `clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT`, and
|
||||
taking the best of three runs. In the test, the format string
|
||||
`"%0.10f:%04d:%+g:%s:%p:%c:%%\n"` or equivalent is filled 2,000,000
|
||||
times with output sent to `/dev/null`; for further details refer to the
|
||||
[source](https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc).
|
||||
|
||||
{fmt} is up to 20-30x faster than `std::ostringstream` and `sprintf` on
|
||||
IEEE754 `float` and `double` formatting
|
||||
([dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark)) and faster
|
||||
than [double-conversion](https://github.com/google/double-conversion)
|
||||
and [ryu](https://github.com/ulfjack/ryu):
|
||||
|
||||
[](https://fmt.dev/unknown_mac64_clang12.0.html)
|
||||
|
||||
## Compile time and code bloat
|
||||
|
||||
The script [bloat-test.py][test] from [format-benchmark][bench] tests compile
|
||||
time and code bloat for nontrivial projects. It generates 100 translation units
|
||||
and uses `printf()` or its alternative five times in each to simulate a
|
||||
medium-sized project. The resulting executable size and compile time (Apple
|
||||
clang version 15.0.0 (clang-1500.1.0.2.5), macOS Sonoma, best of three) is shown
|
||||
in the following tables.
|
||||
|
||||
[test]: https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py
|
||||
[bench]: https://github.com/fmtlib/format-benchmark
|
||||
|
||||
**Optimized build (-O3)**
|
||||
|
||||
| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
|
||||
|---------------|-----------------|----------------------|--------------------|
|
||||
| printf | 1.6 | 54 | 50 |
|
||||
| IOStreams | 25.9 | 98 | 84 |
|
||||
| fmt 83652df | 4.8 | 54 | 50 |
|
||||
| tinyformat | 29.1 | 161 | 136 |
|
||||
| Boost Format | 55.0 | 530 | 317 |
|
||||
|
||||
{fmt} is fast to compile and is comparable to `printf` in terms of per-call
|
||||
binary size (within a rounding error on this system).
|
||||
|
||||
**Non-optimized build**
|
||||
|
||||
| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
|
||||
|---------------|-----------------|----------------------|--------------------|
|
||||
| printf | 1.4 | 54 | 50 |
|
||||
| IOStreams | 23.4 | 92 | 68 |
|
||||
| {fmt} 83652df | 4.4 | 89 | 85 |
|
||||
| tinyformat | 24.5 | 204 | 161 |
|
||||
| Boost Format | 36.4 | 831 | 462 |
|
||||
|
||||
`libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries
|
||||
to compare formatting function overhead only. Boost Format is a
|
||||
header-only library so it doesn\'t provide any linkage options.
|
||||
|
||||
## Running the tests
|
||||
|
||||
Please refer to [Building the
|
||||
library](https://fmt.dev/latest/get-started/#building-from-source) for
|
||||
instructions on how to build the library and run the unit tests.
|
||||
|
||||
Benchmarks reside in a separate repository,
|
||||
[format-benchmarks](https://github.com/fmtlib/format-benchmark), so to
|
||||
run the benchmarks you first need to clone this repository and generate
|
||||
Makefiles with CMake:
|
||||
|
||||
$ git clone --recursive https://github.com/fmtlib/format-benchmark.git
|
||||
$ cd format-benchmark
|
||||
$ cmake .
|
||||
|
||||
Then you can run the speed test:
|
||||
|
||||
$ make speed-test
|
||||
|
||||
or the bloat test:
|
||||
|
||||
$ make bloat-test
|
||||
|
||||
# Migrating code
|
||||
|
||||
[clang-tidy](https://clang.llvm.org/extra/clang-tidy/) v18 provides the
|
||||
[modernize-use-std-print](https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-print.html)
|
||||
check that is capable of converting occurrences of `printf` and
|
||||
`fprintf` to `fmt::print` if configured to do so. (By default it
|
||||
converts to `std::print`.)
|
||||
|
||||
# Notable projects using this library
|
||||
|
||||
- [0 A.D.](https://play0ad.com/): a free, open-source, cross-platform
|
||||
real-time strategy game
|
||||
- [AMPL/MP](https://github.com/ampl/mp): an open-source library for
|
||||
mathematical programming
|
||||
- [Apple's FoundationDB](https://github.com/apple/foundationdb): an open-source,
|
||||
distributed, transactional key-value store
|
||||
- [Aseprite](https://github.com/aseprite/aseprite): animated sprite
|
||||
editor & pixel art tool
|
||||
- [AvioBook](https://www.aviobook.aero/en): a comprehensive aircraft
|
||||
operations suite
|
||||
- [Blizzard Battle.net](https://battle.net/): an online gaming
|
||||
platform
|
||||
- [Celestia](https://celestia.space/): real-time 3D visualization of
|
||||
space
|
||||
- [Ceph](https://ceph.com/): a scalable distributed storage system
|
||||
- [ccache](https://ccache.dev/): a compiler cache
|
||||
- [ClickHouse](https://github.com/ClickHouse/ClickHouse): an
|
||||
analytical database management system
|
||||
- [ContextVision](https://www.contextvision.com/): medical imaging software
|
||||
- [Contour](https://github.com/contour-terminal/contour/): a modern
|
||||
terminal emulator
|
||||
- [CUAUV](https://cuauv.org/): Cornell University\'s autonomous
|
||||
underwater vehicle
|
||||
- [Drake](https://drake.mit.edu/): a planning, control, and analysis
|
||||
toolbox for nonlinear dynamical systems (MIT)
|
||||
- [Envoy](https://github.com/envoyproxy/envoy): C++ L7 proxy and
|
||||
communication bus (Lyft)
|
||||
- [FiveM](https://fivem.net/): a modification framework for GTA V
|
||||
- [fmtlog](https://github.com/MengRao/fmtlog): a performant
|
||||
fmtlib-style logging library with latency in nanoseconds
|
||||
- [Folly](https://github.com/facebook/folly): Facebook open-source
|
||||
library
|
||||
- [GemRB](https://gemrb.org/): a portable open-source implementation
|
||||
of Bioware's Infinity Engine
|
||||
- [Grand Mountain
|
||||
Adventure](https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/):
|
||||
a beautiful open-world ski & snowboarding game
|
||||
- [HarpyWar/pvpgn](https://github.com/pvpgn/pvpgn-server): Player vs
|
||||
Player Gaming Network with tweaks
|
||||
- [KBEngine](https://github.com/kbengine/kbengine): an open-source
|
||||
MMOG server engine
|
||||
- [Keypirinha](https://keypirinha.com/): a semantic launcher for
|
||||
Windows
|
||||
- [Kodi](https://kodi.tv/) (formerly xbmc): home theater software
|
||||
- [Knuth](https://kth.cash/): high-performance Bitcoin full-node
|
||||
- [libunicode](https://github.com/contour-terminal/libunicode/): a
|
||||
modern C++17 Unicode library
|
||||
- [MariaDB](https://mariadb.org/): relational database management
|
||||
system
|
||||
- [Microsoft Verona](https://github.com/microsoft/verona): research
|
||||
programming language for concurrent ownership
|
||||
- [MongoDB](https://mongodb.com/): distributed document database
|
||||
- [MongoDB Smasher](https://github.com/duckie/mongo_smasher): a small
|
||||
tool to generate randomized datasets
|
||||
- [OpenSpace](https://openspaceproject.com/): an open-source
|
||||
astrovisualization framework
|
||||
- [PenUltima Online (POL)](https://www.polserver.com/): an MMO server,
|
||||
compatible with most Ultima Online clients
|
||||
- [PyTorch](https://github.com/pytorch/pytorch): an open-source
|
||||
machine learning library
|
||||
- [quasardb](https://www.quasardb.net/): a distributed,
|
||||
high-performance, associative database
|
||||
- [Quill](https://github.com/odygrd/quill): asynchronous low-latency
|
||||
logging library
|
||||
- [QKW](https://github.com/ravijanjam/qkw): generalizing aliasing to
|
||||
simplify navigation, and execute complex multi-line terminal
|
||||
command sequences
|
||||
- [redis-cerberus](https://github.com/HunanTV/redis-cerberus): a Redis
|
||||
cluster proxy
|
||||
- [redpanda](https://vectorized.io/redpanda): a 10x faster Kafka®
|
||||
replacement for mission-critical systems written in C++
|
||||
- [rpclib](http://rpclib.net/): a modern C++ msgpack-RPC server and
|
||||
client library
|
||||
- [Salesforce Analytics
|
||||
Cloud](https://www.salesforce.com/analytics-cloud/overview/):
|
||||
business intelligence software
|
||||
- [Scylla](https://www.scylladb.com/): a Cassandra-compatible NoSQL
|
||||
data store that can handle 1 million transactions per second on a
|
||||
single server
|
||||
- [Seastar](http://www.seastar-project.org/): an advanced, open-source
|
||||
C++ framework for high-performance server applications on modern
|
||||
hardware
|
||||
- [spdlog](https://github.com/gabime/spdlog): super fast C++ logging
|
||||
library
|
||||
- [Stellar](https://www.stellar.org/): financial platform
|
||||
- [Touch Surgery](https://www.touchsurgery.com/): surgery simulator
|
||||
- [TrinityCore](https://github.com/TrinityCore/TrinityCore):
|
||||
open-source MMORPG framework
|
||||
- [🐙 userver framework](https://userver.tech/): open-source
|
||||
asynchronous framework with a rich set of abstractions and database
|
||||
drivers
|
||||
- [Windows Terminal](https://github.com/microsoft/terminal): the new
|
||||
Windows terminal
|
||||
|
||||
[More\...](https://github.com/search?q=fmtlib&type=Code)
|
||||
|
||||
If you are aware of other projects using this library, please let me
|
||||
know by [email](mailto:victor.zverovich@gmail.com) or by submitting an
|
||||
[issue](https://github.com/fmtlib/fmt/issues).
|
||||
|
||||
# Motivation
|
||||
|
||||
So why yet another formatting library?
|
||||
|
||||
There are plenty of methods for doing this task, from standard ones like
|
||||
the printf family of function and iostreams to Boost Format and
|
||||
FastFormat libraries. The reason for creating a new library is that
|
||||
every existing solution that I found either had serious issues or
|
||||
didn\'t provide all the features I needed.
|
||||
|
||||
## printf
|
||||
|
||||
The good thing about `printf` is that it is pretty fast and readily
|
||||
available being a part of the C standard library. The main drawback is
|
||||
that it doesn\'t support user-defined types. `printf` also has safety
|
||||
issues although they are somewhat mitigated with [\_\_attribute\_\_
|
||||
((format (printf,
|
||||
\...))](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html) in
|
||||
GCC. There is a POSIX extension that adds positional arguments required
|
||||
for
|
||||
[i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization)
|
||||
to `printf` but it is not a part of C99 and may not be available on some
|
||||
platforms.
|
||||
|
||||
## iostreams
|
||||
|
||||
The main issue with iostreams is best illustrated with an example:
|
||||
|
||||
``` c++
|
||||
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
|
||||
```
|
||||
|
||||
which is a lot of typing compared to printf:
|
||||
|
||||
``` c++
|
||||
printf("%.2f\n", 1.23456);
|
||||
```
|
||||
|
||||
Matthew Wilson, the author of FastFormat, called this \"chevron hell\".
|
||||
iostreams don\'t support positional arguments by design.
|
||||
|
||||
The good part is that iostreams support user-defined types and are safe
|
||||
although error handling is awkward.
|
||||
|
||||
## Boost Format
|
||||
|
||||
This is a very powerful library that supports both `printf`-like format
|
||||
strings and positional arguments. Its main drawback is performance.
|
||||
According to various benchmarks, it is much slower than other methods
|
||||
considered here. Boost Format also has excessive build times and severe
|
||||
code bloat issues (see [Benchmarks](#benchmarks)).
|
||||
|
||||
## FastFormat
|
||||
|
||||
This is an interesting library that is fast, safe and has positional
|
||||
arguments. However, it has significant limitations, citing its author:
|
||||
|
||||
> Three features that have no hope of being accommodated within the
|
||||
> current design are:
|
||||
>
|
||||
> - Leading zeros (or any other non-space padding)
|
||||
> - Octal/hexadecimal encoding
|
||||
> - Runtime width/alignment specification
|
||||
|
||||
It is also quite big and has a heavy dependency, on STLSoft, which might be
|
||||
too restrictive for use in some projects.
|
||||
|
||||
## Boost Spirit.Karma
|
||||
|
||||
This is not a formatting library but I decided to include it here for
|
||||
completeness. As iostreams, it suffers from the problem of mixing
|
||||
verbatim text with arguments. The library is pretty fast, but slower on
|
||||
integer formatting than `fmt::format_to` with format string compilation
|
||||
on Karma\'s own benchmark, see [Converting a hundred million integers to
|
||||
strings per
|
||||
second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html).
|
||||
|
||||
# License
|
||||
|
||||
{fmt} is distributed under the MIT
|
||||
[license](https://github.com/fmtlib/fmt/blob/master/LICENSE).
|
||||
|
||||
# Documentation License
|
||||
|
||||
The [Format String Syntax](https://fmt.dev/latest/syntax/) section
|
||||
in the documentation is based on the one from Python [string module
|
||||
documentation](https://docs.python.org/3/library/string.html#module-string).
|
||||
For this reason, the documentation is distributed under the Python
|
||||
Software Foundation license available in
|
||||
[doc/python-license.txt](https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt).
|
||||
It only applies if you distribute the documentation of {fmt}.
|
||||
|
||||
# Maintainers
|
||||
|
||||
The {fmt} library is maintained by Victor Zverovich
|
||||
([vitaut](https://github.com/vitaut)) with contributions from many other
|
||||
people. See
|
||||
[Contributors](https://github.com/fmtlib/fmt/graphs/contributors) and
|
||||
[Releases](https://github.com/fmtlib/fmt/releases) for some of the
|
||||
names. Let us know if your contribution is not listed or mentioned
|
||||
incorrectly and we\'ll make it right.
|
||||
|
||||
# Security Policy
|
||||
|
||||
To report a security issue, please disclose it at [security
|
||||
advisory](https://github.com/fmtlib/fmt/security/advisories/new).
|
||||
|
||||
This project is maintained by a team of volunteers on a
|
||||
reasonable-effort basis. As such, please give us at least *90* days to
|
||||
work on a fix before public exposure.
|
||||
405
README.rst
405
README.rst
@@ -1,405 +0,0 @@
|
||||
C++ Format
|
||||
==========
|
||||
|
||||
.. image:: https://travis-ci.org/cppformat/cppformat.png?branch=master
|
||||
:target: https://travis-ci.org/cppformat/cppformat
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/qk0bhyhqp1ekpat8
|
||||
:target: https://ci.appveyor.com/project/vitaut/cppformat
|
||||
|
||||
C++ Format is an open-source formatting library for C++.
|
||||
It can be used as a safe alternative to printf or as a fast
|
||||
alternative to IOStreams.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Two APIs: faster concatenation-based write API and slower (but still
|
||||
very fast) replacement-based format API with positional arguments for
|
||||
localization.
|
||||
* Write API similar to the one used by IOStreams but much faster and more
|
||||
consistent.
|
||||
* Format API with `format string syntax
|
||||
<http://cppformat.readthedocs.org/en/latest/#format-string-syntax>`__
|
||||
similar to the one used by `str.format
|
||||
<http://docs.python.org/2/library/stdtypes.html#str.format>`__ in Python.
|
||||
* Support for user-defined types.
|
||||
* High speed: performance of the format API is close to that of
|
||||
glibc's `printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`__
|
||||
and better than performance of IOStreams. See `Speed tests`_ and
|
||||
`Fast integer to string conversion in C++
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||
* Small code size both in terms of source code (format consists of a single
|
||||
header file and a single source file) and compiled code.
|
||||
See `Compile time and code bloat`_.
|
||||
* Reliability: the library has an extensive set of `unit tests
|
||||
<https://github.com/cppformat/cppformat/tree/master/test>`__.
|
||||
* Safety: the library is fully type safe, errors in format strings are
|
||||
reported using exceptions, automatic memory management prevents buffer
|
||||
overflow errors.
|
||||
* Ease of use: small self-contained code base, no external dependencies,
|
||||
permissive BSD `license`_.
|
||||
* `Portability <http://cppformat.github.io#portability>`__ with consistent output
|
||||
across platforms and support for older compilers.
|
||||
* Clean warning-free codebase even on high warning levels
|
||||
(-Wall -Wextra -pedantic).
|
||||
* Support for wide strings.
|
||||
|
||||
See the `documentation <http://cppformat.readthedocs.org/en/latest/>`__ for more details.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
This prints ``Hello, world!`` to stdout:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
|
||||
fmt::printf("Hello, %s!", "world"); // uses printf format string syntax
|
||||
|
||||
Arguments can be accessed by position and arguments' indices can be repeated:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
|
||||
// s == "abracadabra"
|
||||
|
||||
C++ Format can be used as a safe portable replacement for ``itoa``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
fmt::MemoryWriter w;
|
||||
w << 42; // replaces itoa(42, buffer, 10)
|
||||
w << fmt::hex(42); // replaces itoa(42, buffer, 16)
|
||||
// access the string using w.str() or w.c_str()
|
||||
|
||||
An object of any user-defined type for which there is an overloaded
|
||||
:code:`std::ostream` insertion operator (``operator<<``) can be formatted:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
|
||||
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
||||
}
|
||||
};
|
||||
|
||||
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
|
||||
// s == "The date is 2012-12-9"
|
||||
|
||||
You can use the `FMT_VARIADIC
|
||||
<http://cppformat.readthedocs.org/en/latest/#project0format_8h_1a65215c7dfcc0e942cd0798860877e86b>`__
|
||||
macro to create your own functions similar to `format
|
||||
<http://cppformat.github.io/doc/latest#fmt::format__StringRef.ArgListCR>`__ and
|
||||
`print <http://cppformat.readthedocs.org/en/latest#fmt::print__StringRef.ArgListCR>`__
|
||||
which take arbitrary arguments:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// Prints formatted error message.
|
||||
void report_error(const char *format, fmt::ArgList args) {
|
||||
fmt::print("Error: ");
|
||||
fmt::print(format, args);
|
||||
}
|
||||
FMT_VARIADIC(void, report_error, const char *)
|
||||
|
||||
report_error("file not found: {}", path);
|
||||
|
||||
Note that you only need to define one function that takes ``fmt::ArgList``
|
||||
argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that
|
||||
accept variable number of arguments.
|
||||
|
||||
Projects using this library
|
||||
---------------------------
|
||||
|
||||
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||
An open-source library for mathematical programming
|
||||
|
||||
* `Saddy <https://code.google.com/p/saddy/>`_:
|
||||
Small crossplatform 2D graphic engine
|
||||
|
||||
* `HarpyWar/pvpgn <https://github.com/HarpyWar/pvpgn>`_:
|
||||
Player vs Player Gaming Network with tweaks
|
||||
|
||||
* `KBEngine <http://www.kbengine.org/>`_: An open-source MMOG server engine
|
||||
|
||||
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
|
||||
|
||||
If you are aware of other projects using this library, please let me know
|
||||
by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an
|
||||
`issue <https://github.com/cppformat/cppformat/issues>`_.
|
||||
|
||||
Motivation
|
||||
----------
|
||||
|
||||
So why yet another formatting library?
|
||||
|
||||
There are plenty of methods for doing this task, from standard ones like
|
||||
the printf family of function and IOStreams to Boost Format library and
|
||||
FastFormat. The reason for creating a new library is that every existing
|
||||
solution that I found either had serious issues or didn't provide
|
||||
all the features I needed.
|
||||
|
||||
Printf
|
||||
~~~~~~
|
||||
|
||||
The good thing about printf is that it is very fast and readily available
|
||||
being a part of the C standard library. The main drawback is that it
|
||||
doesn't support user-defined types. Printf also has safety issues although
|
||||
they are mostly solved with `__attribute__ ((format (printf, ...))
|
||||
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`__ in GCC.
|
||||
There is a POSIX extension that adds positional arguments required for
|
||||
`i18n <http://en.wikipedia.org/wiki/Internationalization_and_localization>`__
|
||||
to printf but it is not a part of C99 and may not be available on some
|
||||
platforms.
|
||||
|
||||
IOStreams
|
||||
~~~~~~~~~
|
||||
|
||||
The main issue with IOStreams is best illustrated with an example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
|
||||
|
||||
which is a lot of typing compared to printf:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
printf("%.2f\n", 1.23456);
|
||||
|
||||
Matthew Wilson, the author of FastFormat, referred to this situation with
|
||||
IOStreams as "chevron hell". IOStreams doesn't support positional arguments
|
||||
by design.
|
||||
|
||||
The good part is that IOStreams supports user-defined types and is safe
|
||||
although error reporting is awkward.
|
||||
|
||||
Boost Format library
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is a very powerful library which supports both printf-like format
|
||||
strings and positional arguments. The main its drawback is performance.
|
||||
According to various benchmarks it is much slower than other methods
|
||||
considered here. Boost Format also has excessive build times and severe
|
||||
code bloat issues (see `Benchmarks`_).
|
||||
|
||||
FastFormat
|
||||
~~~~~~~~~~
|
||||
|
||||
This is an interesting library which is fast, safe and has positional
|
||||
arguments. However it has significant limitations, citing its author:
|
||||
|
||||
Three features that have no hope of being accommodated within the
|
||||
current design are:
|
||||
|
||||
* Leading zeros (or any other non-space padding)
|
||||
* Octal/hexadecimal encoding
|
||||
* Runtime width/alignment specification
|
||||
|
||||
It is also quite big and has a heavy dependency, STLSoft, which might be
|
||||
too restrictive for using it in some projects.
|
||||
|
||||
Loki SafeFormat
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
SafeFormat is a formatting library which uses printf-like format strings
|
||||
and is type safe. It doesn't support user-defined types or positional
|
||||
arguments. It makes unconventional use of ``operator()`` for passing
|
||||
format arguments.
|
||||
|
||||
Tinyformat
|
||||
~~~~~~~~~~
|
||||
|
||||
This library supports printf-like format strings and is very small and
|
||||
fast. Unfortunately it doesn't support positional arguments and wrapping
|
||||
it in C++98 is somewhat difficult. However if you only need a type-safe
|
||||
printf replacement with support for user-defined types, I highly recommend
|
||||
this library.
|
||||
|
||||
Boost Spirit.Karma
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is not really a formatting library but I decided to include it here
|
||||
for completeness. As IOStreams it suffers from the problem of mixing
|
||||
verbatim text with arguments. The library is pretty fast, but slower
|
||||
on integer formatting than ``fmt::Writer`` on Karma's own benchmark,
|
||||
see `Fast integer to string conversion in C++
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`__.
|
||||
|
||||
Benchmarks
|
||||
----------
|
||||
|
||||
Speed tests
|
||||
~~~~~~~~~~~
|
||||
|
||||
The following speed tests results were generated by building
|
||||
``tinyformat_test.cpp`` on Ubuntu GNU/Linux 12.10 with
|
||||
``g++-4.7.2 -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of three
|
||||
runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or
|
||||
equivalent is filled 2000000 times with output sent to ``/dev/null``; for
|
||||
further details see the `source
|
||||
<https://github.com/cppformat/format-benchmark/blob/master/tinyformat_test.cpp>`__.
|
||||
|
||||
============== ========
|
||||
test name run time
|
||||
============== ========
|
||||
libc printf 1.28s
|
||||
std::ostream 2.09s
|
||||
cppformat 1.32s
|
||||
tinyformat 2.55s
|
||||
boost::format 10.42s
|
||||
============== ========
|
||||
|
||||
As you can see boost::format is much slower than the alternative methods; this
|
||||
is confirmed by `other tests <http://accu.org/index.php/journals/1539>`__.
|
||||
Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat
|
||||
cannot be faster than the IOStreams because it uses them internally.
|
||||
Performance of format is close to that of printf.
|
||||
|
||||
Compile time and code bloat
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The script `bloat-test.py
|
||||
<https://github.com/cppformat/format-benchmark/blob/master/bloat-test.py>`__
|
||||
from `format-benchmark <https://github.com/cppformat/format-benchmark>`__
|
||||
tests compile time and code bloat for nontrivial projects.
|
||||
It generates 100 translation units and uses ``printf()`` or its alternative
|
||||
five times in each to simulate a medium sized project. The resulting
|
||||
executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10,
|
||||
best of three) is shown in the following tables.
|
||||
|
||||
**Optimized build (-O3)**
|
||||
|
||||
============ =============== ==================== ==================
|
||||
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||
============ =============== ==================== ==================
|
||||
printf 2.6 41 30
|
||||
IOStreams 19.4 92 70
|
||||
C++ Format 46.8 46 34
|
||||
tinyformat 64.6 418 386
|
||||
Boost Format 222.8 990 923
|
||||
============ =============== ==================== ==================
|
||||
|
||||
As you can see, C++ Format has 80% less overhead in terms of resulting
|
||||
code size compared to IOStreams and comes pretty close to ``printf``.
|
||||
Boost Format has by far the largest overheads.
|
||||
|
||||
**Non-optimized build**
|
||||
|
||||
============ =============== ==================== ==================
|
||||
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||
============ =============== ==================== ==================
|
||||
printf 2.1 41 30
|
||||
IOStreams 19.7 86 62
|
||||
C++ Format 47.9 108 86
|
||||
tinyformat 27.7 234 190
|
||||
Boost Format 122.6 884 763
|
||||
============ =============== ==================== ==================
|
||||
|
||||
``libc``, ``libstdc++`` and ``libformat`` are all linked as shared
|
||||
libraries to compare formatting function overhead only. Boost Format
|
||||
and tinyformat are header-only libraries so they don't provide any
|
||||
linkage options.
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
To run the unit tests first get the source code by cloning the repository::
|
||||
|
||||
$ git clone https://github.com/cppformat/cppformat.git
|
||||
|
||||
or downloading a package from
|
||||
`Releases <https://github.com/cppformat/cppformat/releases>`__.
|
||||
|
||||
Then go to the cppformat directory, generate Makefiles with
|
||||
`CMake <http://www.cmake.org/>`__ and build the project::
|
||||
|
||||
$ cd cppformat
|
||||
$ cmake .
|
||||
$ make
|
||||
|
||||
Now you can run the unit tests::
|
||||
|
||||
$ make test
|
||||
|
||||
Benchmarks reside in a separate repository,
|
||||
`format-benchmarks <https://github.com/cppformat/format-benchmark>`__,
|
||||
so to run the benchmarks you first need to clone this repository and
|
||||
generate Makefiles with CMake::
|
||||
|
||||
$ git clone --recursive https://github.com/cppformat/format-benchmark.git
|
||||
$ cd format-benchmark
|
||||
$ cmake .
|
||||
|
||||
Then you can run the speed test::
|
||||
|
||||
$ make speed-test
|
||||
|
||||
or the bloat test::
|
||||
|
||||
$ make bloat-test
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright (c) 2012, Victor Zverovich
|
||||
|
||||
All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
|
||||
|
||||
Documentation License
|
||||
---------------------
|
||||
|
||||
The `Format String Syntax
|
||||
<http://cppformat.readthedocs.org/en/latest/#format-string-syntax>`__
|
||||
section in the documentation is based on the one from Python `string module
|
||||
documentation <http://docs.python.org/3/library/string.html#module-string>`__
|
||||
adapted for the current library. For this reason the documentation is
|
||||
distributed under the Python Software Foundation license available in
|
||||
`doc/LICENSE.python
|
||||
<https://raw.github.com/cppformat/cppformat/master/doc/LICENSE.python>`__.
|
||||
|
||||
Acknowledgments
|
||||
---------------
|
||||
|
||||
The benchmark section of this readme file and the performance tests are taken
|
||||
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`__ library
|
||||
written by Chris Foster. Boost Format library is acknowledged transitively
|
||||
since it had some influence on tinyformat.
|
||||
Some ideas used in the implementation are borrowed from `Loki
|
||||
<http://loki-lib.sourceforge.net/>`__ SafeFormat and `Diagnostic API
|
||||
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`__ in
|
||||
`Clang <http://clang.llvm.org/>`__.
|
||||
Format string syntax and the documentation are based on Python's `str.format
|
||||
<http://docs.python.org/2/library/stdtypes.html#str.format>`__.
|
||||
Thanks `Doug Turnbull <https://github.com/softwaredoug>`__ for his valuable
|
||||
comments and contribution to the design of the type-safe API and
|
||||
`Gregory Czajkowski <https://github.com/gcflymoto>`__ for implementing binary
|
||||
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`__ for comprehensive
|
||||
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`__
|
||||
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`__ for
|
||||
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`__.
|
||||
54
appveyor.yml
54
appveyor.yml
@@ -1,54 +0,0 @@
|
||||
environment:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
matrix:
|
||||
- Build: msvc
|
||||
Config: Debug
|
||||
- Build: msvc
|
||||
Config: Release
|
||||
- Build: mingw
|
||||
Config: Debug
|
||||
- Build: mingw
|
||||
Config: Release
|
||||
|
||||
install:
|
||||
- ps: |
|
||||
if ($env:Build -eq "mingw") {
|
||||
# Install MinGW.
|
||||
$url = "http://sourceforge.net/projects/mingw-w64/files/"
|
||||
$url += "Toolchains%20targetting%20Win64/Personal%20Builds/"
|
||||
$url += "mingw-builds/4.9.0/threads-win32/seh/"
|
||||
$url += "x86_64-4.9.0-release-win32-seh-rt_v3-rev2.7z/download"
|
||||
Invoke-WebRequest -UserAgent wget -Uri $url -OutFile mingw.7z
|
||||
&7z x -oC:\ mingw.7z > $null
|
||||
}
|
||||
- set PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%;C:\mingw64\bin
|
||||
|
||||
before_build:
|
||||
- ps: |
|
||||
if ($env:Build -eq "mingw") {
|
||||
# Remove path to Git bin directory from PATH because it breaks MinGW config.
|
||||
$env:PATH = $env:PATH -replace "C:\\Program Files \(x86\)\\Git\\bin",""
|
||||
$generator = "-GMinGW Makefiles"
|
||||
}
|
||||
echo "-DCMAKE_BUILD_TYPE=$env:Config"
|
||||
cmake -DFMT_EXTRA_TESTS=ON "-DCMAKE_BUILD_TYPE=$env:Config" "$generator" .
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
if ($env:Build -eq "mingw") {
|
||||
mingw32-make -j4
|
||||
} else {
|
||||
msbuild /m:4 /p:Config=$env:Config FORMAT.sln
|
||||
}
|
||||
|
||||
test_script:
|
||||
- ps: |
|
||||
if ($env:Build -eq "mingw") {
|
||||
mingw32-make test
|
||||
} else {
|
||||
msbuild RUN_TESTS.vcxproj
|
||||
}
|
||||
|
||||
on_failure:
|
||||
- appveyor PushArtifact Testing/Temporary/LastTest.log
|
||||
- appveyor AddTest test
|
||||
1
breathe
1
breathe
Submodule breathe deleted from 66ebb90f6a
@@ -1,11 +0,0 @@
|
||||
@echo on
|
||||
rem This scripts configures build environment and runs CMake.
|
||||
rem Use it instead of running CMake directly when building with
|
||||
rem the Microsoft SDK toolchain rather than Visual Studio.
|
||||
rem It is used in the same way as cmake, for example:
|
||||
rem
|
||||
rem run-cmake -G "Visual Studio 10 Win64" .
|
||||
|
||||
for /F "delims=" %%i IN ('cmake "-DPRINT_PATH=1" -P %~dp0/FindSetEnv.cmake') DO set setenv=%%i
|
||||
if NOT "%setenv%" == "" call "%setenv%"
|
||||
cmake %*
|
||||
@@ -1,7 +0,0 @@
|
||||
add_custom_command(OUTPUT html/index.html
|
||||
COMMAND doxygen
|
||||
COMMAND rm -rf html
|
||||
COMMAND sphinx-build -b html . html
|
||||
DEPENDS ../CMakeLists.txt ../format.h Doxyfile
|
||||
conf.py index.rst _templates/layout.html)
|
||||
add_custom_target(doc DEPENDS html/index.html)
|
||||
3290
doc/ChangeLog-old.md
Normal file
3290
doc/ChangeLog-old.md
Normal file
File diff suppressed because it is too large
Load Diff
20
doc/Doxyfile
20
doc/Doxyfile
@@ -1,20 +0,0 @@
|
||||
PROJECT_NAME = C++ Format
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_MAN = NO
|
||||
GENERATE_RTF = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
INPUT = ../format.h
|
||||
QUIET = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
AUTOLINK_SUPPORT = NO
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_XML = YES
|
||||
XML_OUTPUT = doxyxml
|
||||
ALIASES = "rst=\verbatim embed:rst"
|
||||
ALIASES += "endrst=\endverbatim"
|
||||
PREDEFINED = _WIN32=1 \
|
||||
FMT_NO_DEPRECATED=1 \
|
||||
FMT_USE_VARIADIC_TEMPLATES=1 \
|
||||
FMT_USE_RVALUE_REFERENCES=1
|
||||
EXCLUDE_SYMBOLS = fmt::internal::* BasicArg FormatParser StringValue \
|
||||
write_str
|
||||
13
doc/_static/breathe.css
vendored
13
doc/_static/breathe.css
vendored
@@ -1,13 +0,0 @@
|
||||
|
||||
/* -- breathe specific styles ----------------------------------------------- */
|
||||
|
||||
/* So enum value descriptions are displayed inline to the item */
|
||||
.breatheenumvalues li tt + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* So parameter descriptions are displayed inline to the item */
|
||||
.breatheparameterlist li tt + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
7
doc/_static/cppformat.css
vendored
7
doc/_static/cppformat.css
vendored
@@ -1,7 +0,0 @@
|
||||
.class dd, .define dd, .function dd {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.public-func dd {
|
||||
margin-left: 0px;
|
||||
}
|
||||
14
doc/_templates/layout.html
vendored
14
doc/_templates/layout.html
vendored
@@ -1,14 +0,0 @@
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{% block footer %}
|
||||
{{ super() }}
|
||||
<!-- Google Analytics -->
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-20116650-4', 'cppformat.github.io');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
{% endblock %}
|
||||
673
doc/api.md
Normal file
673
doc/api.md
Normal file
@@ -0,0 +1,673 @@
|
||||
# API Reference
|
||||
|
||||
The {fmt} library API consists of the following components:
|
||||
|
||||
- [`fmt/base.h`](#base-api): the base API providing main formatting functions
|
||||
for `char`/UTF-8 with C++20 compile-time checks and minimal dependencies
|
||||
- [`fmt/format.h`](#format-api): `fmt::format` and other formatting functions
|
||||
as well as locale support
|
||||
- [`fmt/ranges.h`](#ranges-api): formatting of ranges and tuples
|
||||
- [`fmt/chrono.h`](#chrono-api): date and time formatting
|
||||
- [`fmt/std.h`](#std-api): formatters for standard library types
|
||||
- [`fmt/compile.h`](#compile-api): format string compilation
|
||||
- [`fmt/color.h`](#color-api): terminal colors and text styles
|
||||
- [`fmt/os.h`](#os-api): system APIs
|
||||
- [`fmt/ostream.h`](#ostream-api): `std::ostream` support
|
||||
- [`fmt/args.h`](#args-api): dynamic argument lists
|
||||
- [`fmt/printf.h`](#printf-api): safe `printf`
|
||||
- [`fmt/xchar.h`](#xchar-api): optional `wchar_t` support
|
||||
|
||||
All functions and types provided by the library reside in namespace `fmt`
|
||||
and macros have prefix `FMT_`.
|
||||
|
||||
## Base API
|
||||
|
||||
`fmt/base.h` defines the base API which provides main formatting functions
|
||||
for `char`/UTF-8 with C++20 compile-time checks. It has minimal include
|
||||
dependencies for better compile times. This header is only beneficial when
|
||||
using {fmt} as a library (the default) and not in the header-only mode.
|
||||
It also provides `formatter` specializations for the following types:
|
||||
|
||||
- `int`, `long long`,
|
||||
- `unsigned`, `unsigned long long`
|
||||
- `float`, `double`, `long double`
|
||||
- `bool`
|
||||
- `char`
|
||||
- `const char*`, [`fmt::string_view`](#basic_string_view)
|
||||
- `const void*`
|
||||
|
||||
The following functions use [format string syntax](syntax.md) similar to that
|
||||
of [str.format](https://docs.python.org/3/library/stdtypes.html#str.format)
|
||||
in Python. They take *fmt* and *args* as arguments.
|
||||
|
||||
*fmt* is a format string that contains literal text and replacement fields
|
||||
surrounded by braces `{}`. The fields are replaced with formatted arguments
|
||||
in the resulting string. [`fmt::format_string`](#format_string) is a format
|
||||
string which can be implicitly constructed from a string literal or a
|
||||
`constexpr` string and is checked at compile time in C++20. To pass a runtime
|
||||
format string wrap it in [`fmt::runtime`](#runtime).
|
||||
|
||||
*args* is an argument list representing objects to be formatted.
|
||||
|
||||
I/O errors are reported as [`std::system_error`](
|
||||
https://en.cppreference.com/w/cpp/error/system_error) exceptions unless
|
||||
specified otherwise.
|
||||
|
||||
::: print(format_string<T...>, T&&...)
|
||||
|
||||
::: print(FILE*, format_string<T...>, T&&...)
|
||||
|
||||
::: println(format_string<T...>, T&&...)
|
||||
|
||||
::: println(FILE*, format_string<T...>, T&&...)
|
||||
|
||||
::: format_to(OutputIt&&, format_string<T...>, T&&...)
|
||||
|
||||
::: format_to_n(OutputIt, size_t, format_string<T...>, T&&...)
|
||||
|
||||
::: format_to_n_result
|
||||
|
||||
::: formatted_size(format_string<T...>, T&&...)
|
||||
|
||||
<a id="udt"></a>
|
||||
### Formatting User-Defined Types
|
||||
|
||||
The {fmt} library provides formatters for many standard C++ types.
|
||||
See [`fmt/ranges.h`](#ranges-api) for ranges and tuples including standard
|
||||
containers such as `std::vector`, [`fmt/chrono.h`](#chrono-api) for date and
|
||||
time formatting and [`fmt/std.h`](#std-api) for other standard library types.
|
||||
|
||||
There are two ways to make a user-defined type formattable: providing a
|
||||
`format_as` function or specializing the `formatter` struct template.
|
||||
|
||||
Use `format_as` if you want to make your type formattable as some other
|
||||
type with the same format specifiers. The `format_as` function should
|
||||
take an object of your type and return an object of a formattable type.
|
||||
It should be defined in the same namespace as your type.
|
||||
|
||||
Example ([run](https://godbolt.org/z/nvME4arz8)):
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace kevin_namespacy {
|
||||
|
||||
enum class film {
|
||||
house_of_cards, american_beauty, se7en = 7
|
||||
};
|
||||
|
||||
auto format_as(film f) { return fmt::underlying(f); }
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
fmt::print("{}\n", kevin_namespacy::film::se7en); // Output: 7
|
||||
}
|
||||
|
||||
Using specialization is more complex but gives you full control over
|
||||
parsing and formatting. To use this method specialize the `formatter`
|
||||
struct template for your type and implement `parse` and `format`
|
||||
methods.
|
||||
|
||||
The recommended way of defining a formatter is by reusing an existing
|
||||
one via inheritance or composition. This way you can support standard
|
||||
format specifiers without implementing them yourself. For example:
|
||||
|
||||
```c++
|
||||
// color.h:
|
||||
#include <fmt/base.h>
|
||||
|
||||
enum class color {red, green, blue};
|
||||
|
||||
template <> struct fmt::formatter<color>: formatter<string_view> {
|
||||
// parse is inherited from formatter<string_view>.
|
||||
|
||||
auto format(color c, format_context& ctx) const
|
||||
-> format_context::iterator;
|
||||
};
|
||||
```
|
||||
|
||||
```c++
|
||||
// color.cc:
|
||||
#include "color.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
auto fmt::formatter<color>::format(color c, format_context& ctx) const
|
||||
-> format_context::iterator {
|
||||
string_view name = "unknown";
|
||||
switch (c) {
|
||||
case color::red: name = "red"; break;
|
||||
case color::green: name = "green"; break;
|
||||
case color::blue: name = "blue"; break;
|
||||
}
|
||||
return formatter<string_view>::format(name, ctx);
|
||||
}
|
||||
```
|
||||
|
||||
Note that `formatter<string_view>::format` is defined in `fmt/format.h`
|
||||
so it has to be included in the source file. Since `parse` is inherited
|
||||
from `formatter<string_view>` it will recognize all string format
|
||||
specifications, for example
|
||||
|
||||
```c++
|
||||
fmt::format("{:>10}", color::blue)
|
||||
```
|
||||
|
||||
will return `" blue"`.
|
||||
|
||||
<!-- The experimental `nested_formatter` provides an easy way of applying a
|
||||
formatter to one or more subobjects.
|
||||
|
||||
For example:
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
struct point {
|
||||
double x, y;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<point> : nested_formatter<double> {
|
||||
auto format(point p, format_context& ctx) const {
|
||||
return write_padded(ctx, [=](auto out) {
|
||||
return format_to(out, "({}, {})", this->nested(p.x),
|
||||
this->nested(p.y));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
fmt::print("[{:>20.2f}]", point{1, 2});
|
||||
}
|
||||
|
||||
prints:
|
||||
|
||||
[ (1.00, 2.00)]
|
||||
|
||||
Notice that fill, align and width are applied to the whole object which
|
||||
is the recommended behavior while the remaining specifiers apply to
|
||||
elements. -->
|
||||
|
||||
In general the formatter has the following form:
|
||||
|
||||
template <> struct fmt::formatter<T> {
|
||||
// Parses format specifiers and stores them in the formatter.
|
||||
//
|
||||
// [ctx.begin(), ctx.end()) is a, possibly empty, character range that
|
||||
// contains a part of the format string starting from the format
|
||||
// specifications to be parsed, e.g. in
|
||||
//
|
||||
// fmt::format("{:f} continued", ...);
|
||||
//
|
||||
// the range will contain "f} continued". The formatter should parse
|
||||
// specifiers until '}' or the end of the range. In this example the
|
||||
// formatter should parse the 'f' specifier and return an iterator
|
||||
// pointing to '}'.
|
||||
constexpr auto parse(format_parse_context& ctx)
|
||||
-> format_parse_context::iterator;
|
||||
|
||||
// Formats value using the parsed format specification stored in this
|
||||
// formatter and writes the output to ctx.out().
|
||||
auto format(const T& value, format_context& ctx) const
|
||||
-> format_context::iterator;
|
||||
};
|
||||
|
||||
It is recommended to at least support fill, align and width that apply
|
||||
to the whole object and have the same semantics as in standard
|
||||
formatters.
|
||||
|
||||
You can also write a formatter for a hierarchy of classes:
|
||||
|
||||
```c++
|
||||
// demo.h:
|
||||
#include <type_traits>
|
||||
#include <fmt/core.h>
|
||||
|
||||
struct A {
|
||||
virtual ~A() {}
|
||||
virtual std::string name() const { return "A"; }
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
virtual std::string name() const { return "B"; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt::formatter<T, std::enable_if_t<std::is_base_of_v<A, T>, char>> :
|
||||
fmt::formatter<std::string> {
|
||||
auto format(const A& a, format_context& ctx) const {
|
||||
return formatter<std::string>::format(a.name(), ctx);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
```c++
|
||||
// demo.cc:
|
||||
#include "demo.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
int main() {
|
||||
B b;
|
||||
A& a = b;
|
||||
fmt::print("{}", a); // Output: B
|
||||
}
|
||||
```
|
||||
|
||||
Providing both a `formatter` specialization and a `format_as` overload is
|
||||
disallowed.
|
||||
|
||||
::: basic_format_parse_context
|
||||
|
||||
::: context
|
||||
|
||||
::: format_context
|
||||
|
||||
### Compile-Time Checks
|
||||
|
||||
Compile-time format string checks are enabled by default on compilers
|
||||
that support C++20 `consteval`. On older compilers you can use the
|
||||
[FMT_STRING](#legacy-checks) macro defined in `fmt/format.h` instead.
|
||||
|
||||
Unused arguments are allowed as in Python's `str.format` and ordinary functions.
|
||||
|
||||
See [Type Erasure](#type-erasure) for an example of how to enable compile-time
|
||||
checks in your own functions with `fmt::format_string` while avoiding template
|
||||
bloat.
|
||||
|
||||
::: fstring
|
||||
|
||||
::: format_string
|
||||
|
||||
::: runtime(string_view)
|
||||
|
||||
### Type Erasure
|
||||
|
||||
You can create your own formatting function with compile-time checks and
|
||||
small binary footprint, for example ([run](https://godbolt.org/z/b9Pbasvzc)):
|
||||
|
||||
```c++
|
||||
#include <fmt/format.h>
|
||||
|
||||
void vlog(const char* file, int line,
|
||||
fmt::string_view fmt, fmt::format_args args) {
|
||||
fmt::print("{}: {}: {}", file, line, fmt::vformat(fmt, args));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void log(const char* file, int line,
|
||||
fmt::format_string<T...> fmt, T&&... args) {
|
||||
vlog(file, line, fmt, fmt::make_format_args(args...));
|
||||
}
|
||||
|
||||
#define MY_LOG(fmt, ...) log(__FILE__, __LINE__, fmt, __VA_ARGS__)
|
||||
|
||||
MY_LOG("invalid squishiness: {}", 42);
|
||||
```
|
||||
|
||||
Note that `vlog` is not parameterized on argument types which improves
|
||||
compile times and reduces binary code size compared to a fully
|
||||
parameterized version.
|
||||
|
||||
::: make_format_args(T&...)
|
||||
|
||||
::: basic_format_args
|
||||
|
||||
::: format_args
|
||||
|
||||
::: basic_format_arg
|
||||
|
||||
### Named Arguments
|
||||
|
||||
::: arg(const Char*, const T&)
|
||||
|
||||
Named arguments are not supported in compile-time checks at the moment.
|
||||
|
||||
### Compatibility
|
||||
|
||||
::: basic_string_view
|
||||
|
||||
::: string_view
|
||||
|
||||
## Format API
|
||||
|
||||
`fmt/format.h` defines the full format API providing additional
|
||||
formatting functions and locale support.
|
||||
|
||||
<a id="format"></a>
|
||||
::: format(format_string<T...>, T&&...)
|
||||
|
||||
::: vformat(string_view, format_args)
|
||||
|
||||
::: operator""_a()
|
||||
|
||||
### Utilities
|
||||
|
||||
::: ptr(T)
|
||||
|
||||
::: underlying(Enum)
|
||||
|
||||
::: to_string(const T&)
|
||||
|
||||
::: group_digits(T)
|
||||
|
||||
::: detail::buffer
|
||||
|
||||
::: basic_memory_buffer
|
||||
|
||||
### System Errors
|
||||
|
||||
{fmt} does not use `errno` to communicate errors to the user, but it may
|
||||
call system functions which set `errno`. Users should not make any
|
||||
assumptions about the value of `errno` being preserved by library
|
||||
functions.
|
||||
|
||||
::: system_error
|
||||
|
||||
::: format_system_error
|
||||
|
||||
### Custom Allocators
|
||||
|
||||
The {fmt} library supports custom dynamic memory allocators. A custom
|
||||
allocator class can be specified as a template argument to
|
||||
[`fmt::basic_memory_buffer`](#basic_memory_buffer):
|
||||
|
||||
using custom_memory_buffer =
|
||||
fmt::basic_memory_buffer<char, fmt::inline_buffer_size, custom_allocator>;
|
||||
|
||||
It is also possible to write a formatting function that uses a custom
|
||||
allocator:
|
||||
|
||||
using custom_string =
|
||||
std::basic_string<char, std::char_traits<char>, custom_allocator>;
|
||||
|
||||
auto vformat(custom_allocator alloc, fmt::string_view fmt,
|
||||
fmt::format_args args) -> custom_string {
|
||||
auto buf = custom_memory_buffer(alloc);
|
||||
fmt::vformat_to(std::back_inserter(buf), fmt, args);
|
||||
return custom_string(buf.data(), buf.size(), alloc);
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
auto format(custom_allocator alloc, fmt::string_view fmt,
|
||||
const Args& ... args) -> custom_string {
|
||||
return vformat(alloc, fmt, fmt::make_format_args(args...));
|
||||
}
|
||||
|
||||
The allocator will be used for the output container only. Formatting
|
||||
functions normally don't do any allocations for built-in and string
|
||||
types except for non-default floating-point formatting that occasionally
|
||||
falls back on `sprintf`.
|
||||
|
||||
### Locale
|
||||
|
||||
All formatting is locale-independent by default. Use the `'L'` format
|
||||
specifier to insert the appropriate number separator characters from the
|
||||
locale:
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <locale>
|
||||
|
||||
std::locale::global(std::locale("en_US.UTF-8"));
|
||||
auto s = fmt::format("{:L}", 1000000); // s == "1,000,000"
|
||||
|
||||
`fmt/format.h` provides the following overloads of formatting functions
|
||||
that take `std::locale` as a parameter. The locale type is a template
|
||||
parameter to avoid the expensive `<locale>` include.
|
||||
|
||||
::: format(const Locale&, format_string<T...>, T&&...)
|
||||
|
||||
::: format_to(OutputIt, const Locale&, format_string<T...>, T&&...)
|
||||
|
||||
::: formatted_size(const Locale&, format_string<T...>, T&&...)
|
||||
|
||||
<a id="legacy-checks"></a>
|
||||
### Legacy Compile-Time Checks
|
||||
|
||||
`FMT_STRING` enables compile-time checks on older compilers. It requires
|
||||
C++14 or later and is a no-op in C++11.
|
||||
|
||||
::: FMT_STRING
|
||||
|
||||
To force the use of legacy compile-time checks, define the preprocessor
|
||||
variable `FMT_ENFORCE_COMPILE_STRING`. When set, functions accepting
|
||||
`FMT_STRING` will fail to compile with regular strings.
|
||||
|
||||
<a id="ranges-api"></a>
|
||||
## Range and Tuple Formatting
|
||||
|
||||
`fmt/ranges.h` provides formatting support for ranges and tuples:
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
fmt::print("{}", std::tuple<char, int>{'a', 42});
|
||||
// Output: ('a', 42)
|
||||
|
||||
Using `fmt::join`, you can separate tuple elements with a custom separator:
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
auto t = std::tuple<int, char>{1, 'a'};
|
||||
fmt::print("{}", fmt::join(t, ", "));
|
||||
// Output: 1, a
|
||||
|
||||
::: join(Range&&, string_view)
|
||||
|
||||
::: join(It, Sentinel, string_view)
|
||||
|
||||
::: join(std::initializer_list<T>, string_view)
|
||||
|
||||
<a id="chrono-api"></a>
|
||||
## Date and Time Formatting
|
||||
|
||||
`fmt/chrono.h` provides formatters for
|
||||
|
||||
- [`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration)
|
||||
- [`std::chrono::time_point`](
|
||||
https://en.cppreference.com/w/cpp/chrono/time_point)
|
||||
- [`std::tm`](https://en.cppreference.com/w/cpp/chrono/c/tm)
|
||||
|
||||
The format syntax is described in [Chrono Format Specifications](syntax.md#
|
||||
chrono-format-specifications).
|
||||
|
||||
**Example**:
|
||||
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
int main() {
|
||||
std::time_t t = std::time(nullptr);
|
||||
|
||||
fmt::print("The date is {:%Y-%m-%d}.", fmt::localtime(t));
|
||||
// Output: The date is 2020-11-07.
|
||||
// (with 2020-11-07 replaced by the current date)
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
fmt::print("Default format: {} {}\n", 42s, 100ms);
|
||||
// Output: Default format: 42s 100ms
|
||||
|
||||
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
|
||||
// Output: strftime-like format: 03:15:30
|
||||
}
|
||||
|
||||
::: localtime(std::time_t)
|
||||
|
||||
::: gmtime(std::time_t)
|
||||
|
||||
<a id="std-api"></a>
|
||||
## Standard Library Types Formatting
|
||||
|
||||
`fmt/std.h` provides formatters for:
|
||||
|
||||
- [`std::atomic`](https://en.cppreference.com/w/cpp/atomic/atomic)
|
||||
- [`std::atomic_flag`](https://en.cppreference.com/w/cpp/atomic/atomic_flag)
|
||||
- [`std::bitset`](https://en.cppreference.com/w/cpp/utility/bitset)
|
||||
- [`std::error_code`](https://en.cppreference.com/w/cpp/error/error_code)
|
||||
- [`std::exception`](https://en.cppreference.com/w/cpp/error/exception)
|
||||
- [`std::filesystem::path`](https://en.cppreference.com/w/cpp/filesystem/path)
|
||||
- [`std::monostate`](
|
||||
https://en.cppreference.com/w/cpp/utility/variant/monostate)
|
||||
- [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional)
|
||||
- [`std::source_location`](
|
||||
https://en.cppreference.com/w/cpp/utility/source_location)
|
||||
- [`std::thread::id`](https://en.cppreference.com/w/cpp/thread/thread/id)
|
||||
- [`std::variant`](https://en.cppreference.com/w/cpp/utility/variant/variant)
|
||||
|
||||
::: ptr(const std::unique_ptr<T, Deleter>&)
|
||||
|
||||
::: ptr(const std::shared_ptr<T>&)
|
||||
|
||||
### Variants
|
||||
|
||||
A `std::variant` is only formattable if every variant alternative is
|
||||
formattable, and requires the `__cpp_lib_variant` [library
|
||||
feature](https://en.cppreference.com/w/cpp/feature_test).
|
||||
|
||||
**Example**:
|
||||
|
||||
#include <fmt/std.h>
|
||||
|
||||
fmt::print("{}", std::variant<char, float>('x'));
|
||||
// Output: variant('x')
|
||||
|
||||
fmt::print("{}", std::variant<std::monostate, char>());
|
||||
// Output: variant(monostate)
|
||||
|
||||
## Bit-Fields and Packed Structs
|
||||
|
||||
To format a bit-field or a field of a struct with `__attribute__((packed))`
|
||||
applied to it, you need to convert it to the underlying or compatible type via
|
||||
a cast or a unary `+` ([godbolt](https://www.godbolt.org/z/3qKKs6T5Y)):
|
||||
|
||||
```c++
|
||||
struct smol {
|
||||
int bit : 1;
|
||||
};
|
||||
|
||||
auto s = smol();
|
||||
fmt::print("{}", +s.bit);
|
||||
```
|
||||
|
||||
This is a known limitation of "perfect" forwarding in C++.
|
||||
|
||||
<a id="compile-api"></a>
|
||||
## Format String Compilation
|
||||
|
||||
`fmt/compile.h` provides format string compilation and compile-time
|
||||
(`constexpr`) formatting enabled via the `FMT_COMPILE` macro or the `_cf`
|
||||
user-defined literal defined in namespace `fmt::literals`. Format strings
|
||||
marked with `FMT_COMPILE` or `_cf` are parsed, checked and converted into
|
||||
efficient formatting code at compile-time. This supports arguments of built-in
|
||||
and string types as well as user-defined types with `format` functions taking
|
||||
the format context type as a template parameter in their `formatter`
|
||||
specializations. For example:
|
||||
|
||||
template <> struct fmt::formatter<point> {
|
||||
constexpr auto parse(format_parse_context& ctx);
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const point& p, FormatContext& ctx) const;
|
||||
};
|
||||
|
||||
Format string compilation can generate more binary code compared to the
|
||||
default API and is only recommended in places where formatting is a
|
||||
performance bottleneck.
|
||||
|
||||
::: FMT_COMPILE
|
||||
|
||||
::: operator""_cf
|
||||
|
||||
<a id="color-api"></a>
|
||||
## Terminal Colors and Text Styles
|
||||
|
||||
`fmt/color.h` provides support for terminal color and text style output.
|
||||
|
||||
::: print(const text_style&, format_string<T...>, T&&...)
|
||||
|
||||
::: fg(detail::color_type)
|
||||
|
||||
::: bg(detail::color_type)
|
||||
|
||||
::: styled(const T&, text_style)
|
||||
|
||||
<a id="os-api"></a>
|
||||
## System APIs
|
||||
|
||||
::: ostream
|
||||
|
||||
::: windows_error
|
||||
|
||||
<a id="ostream-api"></a>
|
||||
## `std::ostream` Support
|
||||
|
||||
`fmt/ostream.h` provides `std::ostream` support including formatting of
|
||||
user-defined types that have an overloaded insertion operator
|
||||
(`operator<<`). In order to make a type formattable via `std::ostream`
|
||||
you should provide a `formatter` specialization inherited from
|
||||
`ostream_formatter`:
|
||||
|
||||
#include <fmt/ostream.h>
|
||||
|
||||
struct date {
|
||||
int year, month, day;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const date& d) {
|
||||
return os << d.year << '-' << d.month << '-' << d.day;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct fmt::formatter<date> : ostream_formatter {};
|
||||
|
||||
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
|
||||
// s == "The date is 2012-12-9"
|
||||
|
||||
::: streamed(const T&)
|
||||
|
||||
::: print(std::ostream&, format_string<T...>, T&&...)
|
||||
|
||||
<a id="args-api"></a>
|
||||
## Dynamic Argument Lists
|
||||
|
||||
The header `fmt/args.h` provides `dynamic_format_arg_store`, a builder-like API
|
||||
that can be used to construct format argument lists dynamically.
|
||||
|
||||
::: dynamic_format_arg_store
|
||||
|
||||
<a id="printf-api"></a>
|
||||
## Safe `printf`
|
||||
|
||||
The header `fmt/printf.h` provides `printf`-like formatting
|
||||
functionality. The following functions use [printf format string
|
||||
syntax](https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html)
|
||||
with the POSIX extension for positional arguments. Unlike their standard
|
||||
counterparts, the `fmt` functions are type-safe and throw an exception
|
||||
if an argument type doesn't match its format specification.
|
||||
|
||||
::: printf(string_view, const T&...)
|
||||
|
||||
::: fprintf(std::FILE*, const S&, const T&...)
|
||||
|
||||
::: sprintf(const S&, const T&...)
|
||||
|
||||
<a id="xchar-api"></a>
|
||||
## Wide Strings
|
||||
|
||||
The optional header `fmt/xchar.h` provides support for `wchar_t` and
|
||||
exotic character types.
|
||||
|
||||
::: is_char
|
||||
|
||||
::: wstring_view
|
||||
|
||||
::: wformat_context
|
||||
|
||||
::: to_wstring(const T&)
|
||||
|
||||
## Compatibility with C++20 `std::format`
|
||||
|
||||
{fmt} implements nearly all of the [C++20 formatting
|
||||
library](https://en.cppreference.com/w/cpp/utility/format) with the
|
||||
following differences:
|
||||
|
||||
- Names are defined in the `fmt` namespace instead of `std` to avoid
|
||||
collisions with standard library implementations.
|
||||
- Width calculation doesn't use grapheme clusterization. The latter has
|
||||
been implemented in a separate branch but hasn't been integrated yet.
|
||||
278
doc/conf.py
278
doc/conf.py
@@ -1,278 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# format documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Dec 18 06:46:16 2012.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os, re, subprocess
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
sys.path.append("../breathe")
|
||||
|
||||
if os.environ.get('READTHEDOCS', None) == 'True':
|
||||
subprocess.call('doxygen')
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.ifconfig', 'breathe']
|
||||
|
||||
breathe_projects = { "format": "doxyxml" }
|
||||
breathe_default_project = "format"
|
||||
breathe_domain_by_extension = {"h" : "cpp"}
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'C++ Format'
|
||||
copyright = u'2012-2014, Victor Zverovich'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
|
||||
# Get version from CMakeLists.txt.
|
||||
version = {}
|
||||
with open('../CMakeLists.txt') as f:
|
||||
for line in f:
|
||||
m = re.match(r'set\(CPACK_PACKAGE_VERSION_([A-Z]+) ([0-9]+)\)', line.strip())
|
||||
if m:
|
||||
kind, value = m.groups()
|
||||
version[kind] = value
|
||||
version = '{}.{}.{}'.format(version['MAJOR'], version['MINOR'], version['PATCH'])
|
||||
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
#exclude_patterns = []
|
||||
|
||||
exclude_trees = ['sphinx-bootstrap-theme']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'bootstrap'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
html_theme_options = {
|
||||
# HTML navbar class (Default: "navbar") to attach to <div>.
|
||||
# For black navbar, do "navbar navbar-inverse"
|
||||
#'navbar_class': "navbar navbar-inverse",
|
||||
|
||||
# Fix navigation bar to top of page?
|
||||
# Values: "true" (default) or "false"
|
||||
'navbar_fixed_top': "true",
|
||||
|
||||
# Location of link to source.
|
||||
# Options are "nav" (default), "footer".
|
||||
'source_link_position': "footer",
|
||||
|
||||
# Render the next and previous page links in navbar. (Default: true)
|
||||
'navbar_sidebarrel': False
|
||||
}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ['sphinx-bootstrap-theme']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'formatdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'format.tex', u'C++ Format Documentation',
|
||||
u'Victor Zverovich', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'format', u'format Documentation',
|
||||
[u'Victor Zverovich'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'format', u'format Documentation',
|
||||
u'Victor Zverovich', 'format', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
61
doc/fmt.css
Normal file
61
doc/fmt.css
Normal file
@@ -0,0 +1,61 @@
|
||||
:root {
|
||||
--md-primary-fg-color: #0050D0;
|
||||
}
|
||||
|
||||
.md-grid {
|
||||
max-width: 960px;
|
||||
}
|
||||
|
||||
@media (min-width: 400px) {
|
||||
.md-tabs {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.docblock {
|
||||
border-left: .05rem solid var(--md-primary-fg-color);
|
||||
}
|
||||
|
||||
.docblock-desc {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
pre > code.decl {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
|
||||
code.decl > div {
|
||||
text-indent: -2ch; /* Negative indent to counteract the indent on the first line */
|
||||
padding-left: 2ch; /* Add padding to the left to create an indent */
|
||||
}
|
||||
|
||||
.features-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
justify-content: center; /* Center the items horizontally */
|
||||
}
|
||||
|
||||
.feature {
|
||||
flex: 1 1 calc(50% - 20px); /* Two columns with space between */
|
||||
max-width: 600px; /* Set the maximum width for the feature boxes */
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
overflow: hidden; /* Hide overflow content */
|
||||
text-overflow: ellipsis; /* Handle text overflow */
|
||||
white-space: normal; /* Allow text wrapping */
|
||||
}
|
||||
|
||||
.feature h2 {
|
||||
margin-top: 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.feature {
|
||||
flex: 1 1 100%; /* Stack columns on smaller screens */
|
||||
max-width: 100%; /* Allow full width on smaller screens */
|
||||
white-space: normal; /* Allow text wrapping on smaller screens */
|
||||
}
|
||||
}
|
||||
4
doc/fmt.js
Normal file
4
doc/fmt.js
Normal file
@@ -0,0 +1,4 @@
|
||||
document$.subscribe(() => {
|
||||
hljs.highlightAll(),
|
||||
{ language: 'c++' }
|
||||
})
|
||||
222
doc/get-started.md
Normal file
222
doc/get-started.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# Get Started
|
||||
|
||||
Compile and run {fmt} examples online with [Compiler Explorer](
|
||||
https://godbolt.org/z/P7h6cd6o3).
|
||||
|
||||
{fmt} is compatible with any build system. The next section describes its usage
|
||||
with CMake, while the [Build Systems](#build-systems) section covers the rest.
|
||||
|
||||
## CMake
|
||||
|
||||
{fmt} provides two CMake targets: `fmt::fmt` for the compiled library and
|
||||
`fmt::fmt-header-only` for the header-only library. It is recommended to use
|
||||
the compiled library for improved build times.
|
||||
|
||||
There are three primary ways to use {fmt} with CMake:
|
||||
|
||||
* **FetchContent**: Starting from CMake 3.11, you can use [`FetchContent`](
|
||||
https://cmake.org/cmake/help/v3.30/module/FetchContent.html) to automatically
|
||||
download {fmt} as a dependency at configure time:
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
fmt
|
||||
GIT_REPOSITORY https://github.com/fmtlib/fmt
|
||||
GIT_TAG e69e5f977d458f2650bb346dadf2ad30c5320281) # 10.2.1
|
||||
FetchContent_MakeAvailable(fmt)
|
||||
|
||||
target_link_libraries(<your-target> fmt::fmt)
|
||||
|
||||
* **Installed**: You can find and use an [installed](#installation) version of
|
||||
{fmt} in your `CMakeLists.txt` file as follows:
|
||||
|
||||
find_package(fmt)
|
||||
target_link_libraries(<your-target> fmt::fmt)
|
||||
|
||||
* **Embedded**: You can add the {fmt} source tree to your project and include it
|
||||
in your `CMakeLists.txt` file:
|
||||
|
||||
add_subdirectory(fmt)
|
||||
target_link_libraries(<your-target> fmt::fmt)
|
||||
|
||||
## Installation
|
||||
|
||||
### Debian/Ubuntu
|
||||
|
||||
To install {fmt} on Debian, Ubuntu, or any other Debian-based Linux
|
||||
distribution, use the following command:
|
||||
|
||||
apt install libfmt-dev
|
||||
|
||||
### Homebrew
|
||||
|
||||
Install {fmt} on macOS using [Homebrew](https://brew.sh/):
|
||||
|
||||
brew install fmt
|
||||
|
||||
### Conda
|
||||
|
||||
Install {fmt} on Linux, macOS, and Windows with [Conda](
|
||||
https://docs.conda.io/en/latest/), using its [conda-forge package](
|
||||
https://github.com/conda-forge/fmt-feedstock):
|
||||
|
||||
conda install -c conda-forge fmt
|
||||
|
||||
### vcpkg
|
||||
|
||||
Download and install {fmt} using the vcpkg package manager:
|
||||
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
./vcpkg install fmt
|
||||
|
||||
<!-- The fmt package in vcpkg is kept up to date by Microsoft team members and
|
||||
community contributors. If the version is out of date, please [create an
|
||||
issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg
|
||||
repository. -->
|
||||
|
||||
## Building from Source
|
||||
|
||||
CMake works by generating native makefiles or project files that can be
|
||||
used in the compiler environment of your choice. The typical workflow
|
||||
starts with:
|
||||
|
||||
mkdir build # Create a directory to hold the build output.
|
||||
cd build
|
||||
cmake .. # Generate native build scripts.
|
||||
|
||||
run in the `fmt` repository.
|
||||
|
||||
If you are on a Unix-like system, you should now see a Makefile in the
|
||||
current directory. Now you can build the library by running `make`.
|
||||
|
||||
Once the library has been built you can invoke `make test` to run the tests.
|
||||
|
||||
You can control generation of the make `test` target with the `FMT_TEST`
|
||||
CMake option. This can be useful if you include fmt as a subdirectory in
|
||||
your project but don't want to add fmt's tests to your `test` target.
|
||||
|
||||
To build a shared library set the `BUILD_SHARED_LIBS` CMake variable to `TRUE`:
|
||||
|
||||
cmake -DBUILD_SHARED_LIBS=TRUE ..
|
||||
|
||||
To build a static library with position-independent code (e.g. for
|
||||
linking it into another shared library such as a Python extension), set the
|
||||
`CMAKE_POSITION_INDEPENDENT_CODE` CMake variable to `TRUE`:
|
||||
|
||||
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ..
|
||||
|
||||
After building the library you can install it on a Unix-like system by
|
||||
running `sudo make install`.
|
||||
|
||||
### Building the Docs
|
||||
|
||||
To build the documentation you need the following software installed on
|
||||
your system:
|
||||
|
||||
- [Python](https://www.python.org/)
|
||||
- [Doxygen](http://www.stack.nl/~dimitri/doxygen/)
|
||||
- [MkDocs](https://www.mkdocs.org/) with `mkdocs-material`, `mkdocstrings`,
|
||||
`pymdown-extensions` and `mike`
|
||||
|
||||
First generate makefiles or project files using CMake as described in
|
||||
the previous section. Then compile the `doc` target/project, for example:
|
||||
|
||||
make doc
|
||||
|
||||
This will generate the HTML documentation in `doc/html`.
|
||||
|
||||
## Build Systems
|
||||
|
||||
### build2
|
||||
|
||||
You can use [build2](https://build2.org), a dependency manager and a build
|
||||
system, to use {fmt}.
|
||||
|
||||
Currently this package is available in these package repositories:
|
||||
|
||||
- <https://cppget.org/fmt/> for released and published versions.
|
||||
- <https://github.com/build2-packaging/fmt> for unreleased or custom versions.
|
||||
|
||||
**Usage:**
|
||||
|
||||
- `build2` package name: `fmt`
|
||||
- Library target name: `lib{fmt}`
|
||||
|
||||
To make your `build2` project depend on `fmt`:
|
||||
|
||||
- Add one of the repositories to your configurations, or in your
|
||||
`repositories.manifest`, if not already there:
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://pkg.cppget.org/1/stable
|
||||
|
||||
- Add this package as a dependency to your `manifest` file (example
|
||||
for version 10):
|
||||
|
||||
depends: fmt ~10.0.0
|
||||
|
||||
- Import the target and use it as a prerequisite to your own target
|
||||
using `fmt` in the appropriate `buildfile`:
|
||||
|
||||
import fmt = fmt%lib{fmt}
|
||||
lib{mylib} : cxx{**} ... $fmt
|
||||
|
||||
Then build your project as usual with `b` or `bdep update`.
|
||||
|
||||
### Meson
|
||||
|
||||
[Meson WrapDB](https://mesonbuild.com/Wrapdb-projects.html) includes an `fmt`
|
||||
package.
|
||||
|
||||
**Usage:**
|
||||
|
||||
- Install the `fmt` subproject from the WrapDB by running:
|
||||
|
||||
meson wrap install fmt
|
||||
|
||||
from the root of your project.
|
||||
|
||||
- In your project's `meson.build` file, add an entry for the new subproject:
|
||||
|
||||
fmt = subproject('fmt')
|
||||
fmt_dep = fmt.get_variable('fmt_dep')
|
||||
|
||||
- Include the new dependency object to link with fmt:
|
||||
|
||||
my_build_target = executable(
|
||||
'name', 'src/main.cc', dependencies: [fmt_dep])
|
||||
|
||||
**Options:**
|
||||
|
||||
If desired, {fmt} can be built as a static library, or as a header-only library.
|
||||
|
||||
For a static build, use the following subproject definition:
|
||||
|
||||
fmt = subproject('fmt', default_options: 'default_library=static')
|
||||
fmt_dep = fmt.get_variable('fmt_dep')
|
||||
|
||||
For the header-only version, use:
|
||||
|
||||
fmt = subproject('fmt', default_options: ['header-only=true'])
|
||||
fmt_dep = fmt.get_variable('fmt_header_only_dep')
|
||||
|
||||
### Android NDK
|
||||
|
||||
{fmt} provides [Android.mk file](
|
||||
https://github.com/fmtlib/fmt/blob/master/support/Android.mk) that can be used
|
||||
to build the library with [Android NDK](
|
||||
https://developer.android.com/tools/sdk/ndk/index.html).
|
||||
|
||||
### Other
|
||||
|
||||
To use the {fmt} library with any other build system, add
|
||||
`include/fmt/base.h`, `include/fmt/format.h`, `include/fmt/format-inl.h`,
|
||||
`src/format.cc` and optionally other headers from a [release archive](
|
||||
https://github.com/fmtlib/fmt/releases) or the [git repository](
|
||||
https://github.com/fmtlib/fmt) to your project, add `include` to include
|
||||
directories and make sure `src/format.cc` is compiled and linked with your code.
|
||||
151
doc/index.md
Normal file
151
doc/index.md
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
hide:
|
||||
- navigation
|
||||
- toc
|
||||
---
|
||||
|
||||
# A modern formatting library
|
||||
|
||||
<div class="features-container">
|
||||
|
||||
<div class="feature">
|
||||
<h2>Safety</h2>
|
||||
<p>
|
||||
Inspired by Python's formatting facility, {fmt} provides a safe replacement
|
||||
for the <code>printf</code> family of functions. Errors in format strings,
|
||||
which are a common source of vulnerabilities in C, are <b>reported at
|
||||
compile time</b>. For example:
|
||||
|
||||
<pre><code class="language-cpp"
|
||||
>fmt::format("{:d}", "I am not a number");</code></pre>
|
||||
|
||||
will give a compile-time error because <code>d</code> is not a valid
|
||||
format specifier for strings. APIs like <a href="api/#format">
|
||||
<code>fmt::format</code></a> <b>prevent buffer overflow errors</b> via
|
||||
automatic memory management.
|
||||
</p>
|
||||
<a href="api#compile-time-checks">→ Learn more</a>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h2>Extensibility</h2>
|
||||
<p>
|
||||
Formatting of most <b>standard types</b>, including all containers, dates,
|
||||
and times is <b>supported out-of-the-box</b>. For example:
|
||||
|
||||
<pre><code class="language-cpp"
|
||||
>fmt::print("{}", std::vector{1, 2, 3});</code></pre>
|
||||
|
||||
prints the vector in a JSON-like format:
|
||||
|
||||
<pre><code>[1, 2, 3]</code></pre>
|
||||
|
||||
You can <b>make your own types formattable</b> and even make compile-time
|
||||
checks work for them.
|
||||
</p>
|
||||
<a href="api#udt">→ Learn more</a>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h2>Performance</h2>
|
||||
<p>
|
||||
{fmt} can be anywhere from <b>tens of percent to 20-30 times faster</b> than
|
||||
iostreams and <code>sprintf</code>, especially for numeric formatting.
|
||||
|
||||
<a href="https://github.com/fmtlib/fmt?tab=readme-ov-file#benchmarks">
|
||||
<img src="perf.svg">
|
||||
</a>
|
||||
|
||||
The library <b>minimizes dynamic memory allocations</b> and can optionally
|
||||
<a href="api#compile-api">compile format strings</a> to optimal code.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h2>Unicode support</h2>
|
||||
<p>
|
||||
{fmt} provides <b>portable Unicode support</b> on major operating systems
|
||||
with UTF-8 and <code>char</code> strings. For example:
|
||||
|
||||
<pre><code class="language-cpp"
|
||||
>fmt::print("Слава Україні!");</code></pre>
|
||||
|
||||
will be printed correctly on Linux, macOS, and even Windows console,
|
||||
irrespective of the codepages.
|
||||
</p>
|
||||
<p>
|
||||
The default is <b>locale-independent</b>, but you can opt into localized
|
||||
formatting and {fmt} makes it work with Unicode, addressing issues in the
|
||||
standard libary.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h2>Fast compilation</h2>
|
||||
<p>
|
||||
The library makes extensive use of <b>type erasure</b> to achieve fast
|
||||
compilation. <code>fmt/base.h</code> provides a subset of the API with
|
||||
<b>minimal include dependencies</b> and enough functionality to replace
|
||||
all uses of <code>*printf</code>.
|
||||
</p>
|
||||
<p>
|
||||
Code using {fmt} is usually several times faster to compile than the
|
||||
equivalent iostreams code, and while <code>printf</code> compiles faster
|
||||
still, the gap is narrowing.
|
||||
</p>
|
||||
<a href=
|
||||
"https://github.com/fmtlib/fmt?tab=readme-ov-file#compile-time-and-code-bloat">
|
||||
→ Learn more</a>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h2>Small binary footprint</h2>
|
||||
<p>
|
||||
Type erasure is also used to prevent template bloat, resulting in <b>compact
|
||||
per-call binary code</b>. For example, a call to <code>fmt::print</code> with
|
||||
a single argument is just <a href="https://godbolt.org/g/TZU4KF">a few
|
||||
instructions</a>, comparable to <code>printf</code> despite adding
|
||||
runtime safety, and much smaller than the equivalent iostreams code.
|
||||
</p>
|
||||
<p>
|
||||
The library itself has small binary footprint and some components such as
|
||||
floating-point formatting can be disabled to make it even smaller for
|
||||
resource-constrained devices.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h2>Portability</h2>
|
||||
<p>
|
||||
{fmt} has a <b>small self-contained codebase</b> with the core consisting of
|
||||
just three headers and no external dependencies.
|
||||
</p>
|
||||
<p>
|
||||
The library is highly portable and requires only a minimal <b>subset of
|
||||
C++11</b> features which are available in GCC 4.9, Clang 3.4, MSVC 19.10
|
||||
(2017) and later. Newer compiler and standard library features are used
|
||||
if available, and enable additional functionality.
|
||||
</p>
|
||||
<p>
|
||||
Where possible, the output of formatting functions is <b>consistent across
|
||||
platforms</b>.
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h2>Open source</h2>
|
||||
<p>
|
||||
{fmt} is in the top hundred open-source C++ libraries on GitHub and has
|
||||
<a href="https://github.com/fmtlib/fmt/graphs/contributors">hundreds of
|
||||
all-time contributors</a>.
|
||||
</p>
|
||||
<p>
|
||||
The library is distributed under a permissive MIT
|
||||
<a href="https://github.com/fmtlib/fmt#license">license</a> and is
|
||||
<b>relied upon by many open-source projects</b>, including Blender, PyTorch,
|
||||
Apple's FoundationDB, Windows Terminal, MongoDB, and others.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,10 +0,0 @@
|
||||
##########
|
||||
C++ Format
|
||||
##########
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
usage
|
||||
reference
|
||||
syntax
|
||||
1
doc/perf.svg
Normal file
1
doc/perf.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="20 0 550 300" aria-label="A chart." style="overflow: hidden;"><defs id="_ABSTRACT_RENDERER_ID_0"><clipPath id="_ABSTRACT_RENDERER_ID_1"><rect x="120" y="45" width="560" height="210"></rect></clipPath></defs><rect x="0" y="0" width="800" height="300" stroke="none" stroke-width="0" fill="#ffffff"></rect><g><text text-anchor="start" x="120" y="27.05" font-family="Arial" font-size="13" font-weight="bold" stroke="none" stroke-width="0" fill="#000000">double to string</text><rect x="120" y="16" width="560" height="13" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect></g><g><rect x="120" y="45" width="560" height="210" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect><g clip-path="url(#_ABSTRACT_RENDERER_ID_1)"><g><rect x="120" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="213" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="306" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="400" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="493" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="586" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="679" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#cccccc"></rect></g><g><rect x="121" y="53" width="450" height="26" stroke="#ff9900" stroke-width="1" fill="#ff9900"></rect><rect x="121" y="95" width="421" height="26" stroke="#109618" stroke-width="1" fill="#109618"></rect><rect x="121" y="137" width="341" height="26" stroke="#990099" stroke-width="1" fill="#990099"></rect><rect x="121" y="179" width="31" height="26" stroke="#3366cc" stroke-width="1" fill="#3366cc"></rect><rect x="121" y="221" width="15" height="26" stroke="#dc3912" stroke-width="1" fill="#dc3912"></rect></g><g><rect x="120" y="45" width="1" height="210" stroke="none" stroke-width="0" fill="#333333"></rect></g></g><g></g><g><g><text text-anchor="middle" x="120.5" y="272.3833333333333" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">0</text></g><g><text text-anchor="middle" x="213.6667" y="272.3833333333333" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">250</text></g><g><text text-anchor="middle" x="306.8333" y="272.3833333333333" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">500</text></g><g><text text-anchor="middle" x="400" y="272.3833333333333" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">750</text></g><g><text text-anchor="middle" x="493.1667" y="272.3833333333333" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">1,000</text></g><g><text text-anchor="middle" x="586.3333" y="272.3833333333333" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">1,250</text></g><g><text text-anchor="middle" x="679.5" y="272.3833333333333" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">1,500</text></g><g><text text-anchor="end" x="107" y="70.95" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">ostringstream</text></g><g><text text-anchor="end" x="107" y="112.74999999999999" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">ostrstream</text></g><g><text text-anchor="end" x="107" y="154.55" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">sprintf</text></g><g><text text-anchor="end" x="107" y="196.35" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">doubleconv</text></g><g><text text-anchor="end" x="107" y="238.15" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">fmt</text></g></g></g><g><g><text text-anchor="middle" x="300" y="291.71666666666664" font-family="Arial" font-size="13" font-style="italic" stroke="none" stroke-width="0" fill="#222222">Time (ns), smaller is better</text><rect x="120" y="280.66666666666663" width="560" height="13" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect></g></g><g></g></svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@@ -1,113 +0,0 @@
|
||||
.. highlight:: c++
|
||||
|
||||
.. _string-formatting-api:
|
||||
|
||||
*************
|
||||
API Reference
|
||||
*************
|
||||
|
||||
All functions and classes provided by the C++ Format library reside
|
||||
in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the
|
||||
namespace is usually omitted in examples.
|
||||
|
||||
Formatting functions
|
||||
====================
|
||||
|
||||
The following functions use :ref:`format string syntax <syntax>` similar
|
||||
to the one used by Python's `str.format
|
||||
<http://docs.python.org/3/library/stdtypes.html#str.format>`_ function.
|
||||
They take *format_str* and *args* as arguments.
|
||||
|
||||
*format_str* is a format string that contains literal text and replacement
|
||||
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
||||
arguments in the resulting string.
|
||||
|
||||
*args* is an argument list representing arbitrary arguments.
|
||||
|
||||
.. _format:
|
||||
|
||||
.. doxygenfunction:: fmt::format(StringRef, ArgList)
|
||||
|
||||
.. _print:
|
||||
|
||||
.. doxygenfunction:: fmt::print(StringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fmt::print(std::FILE *, StringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fmt::print(std::ostream &, StringRef, ArgList)
|
||||
|
||||
Printf formatting functions
|
||||
===========================
|
||||
|
||||
The following functions use `printf format string syntax
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
|
||||
a POSIX extension for positional arguments.
|
||||
|
||||
.. doxygenfunction:: fmt::printf(StringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fmt::fprintf(std::FILE *, StringRef, ArgList)
|
||||
|
||||
.. doxygenfunction:: fmt::sprintf(StringRef, ArgList)
|
||||
|
||||
Write API
|
||||
=========
|
||||
|
||||
.. doxygenclass:: fmt::BasicWriter
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicMemoryWriter
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: fmt::bin
|
||||
|
||||
.. doxygenfunction:: fmt::oct
|
||||
|
||||
.. doxygenfunction:: fmt::hex
|
||||
|
||||
.. doxygenfunction:: fmt::hexu
|
||||
|
||||
.. doxygenfunction:: fmt::pad(int, unsigned, Char)
|
||||
|
||||
Utilities
|
||||
=========
|
||||
|
||||
.. doxygendefine:: FMT_VARIADIC
|
||||
|
||||
.. doxygenclass:: fmt::ArgList
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::BasicStringRef
|
||||
:members:
|
||||
|
||||
System Errors
|
||||
=============
|
||||
|
||||
.. doxygenclass:: fmt::SystemError
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: fmt::WindowsError
|
||||
:members:
|
||||
|
||||
.. _formatstrings:
|
||||
|
||||
Custom allocators
|
||||
=================
|
||||
|
||||
The C++ Format library supports custom dynamic memory allocators.
|
||||
A custom allocator class can be specified as a template argument to
|
||||
:cpp:class:`fmt::BasicMemoryWriter`::
|
||||
|
||||
typedef fmt::BasicMemoryWriter<char, CustomAllocator> CustomMemoryWriter;
|
||||
|
||||
It is also possible to write a formatting function that uses a custom
|
||||
allocator::
|
||||
|
||||
typedef std::basic_string<char, std::char_traits<char>, CustomAllocator> CustomString;
|
||||
|
||||
CustomString format(CustomAllocator alloc, fmt::StringRef format_str,
|
||||
fmt::ArgList args) {
|
||||
CustomMemoryWriter writer(alloc);
|
||||
writer.write(format_str, args);
|
||||
return CustomString(writer.data(), writer.size(), alloc);
|
||||
}
|
||||
FMT_VARIADIC(CustomString, format, CustomAllocator, fmt::StringRef)
|
||||
Submodule doc/sphinx-bootstrap-theme deleted from c26c975e8a
886
doc/syntax.md
Normal file
886
doc/syntax.md
Normal file
@@ -0,0 +1,886 @@
|
||||
# Format String Syntax
|
||||
|
||||
Formatting functions such as [`fmt::format`](api.md#format) and [`fmt::print`](
|
||||
api.md#print) use the same format string syntax described in this section.
|
||||
|
||||
Format strings contain "replacement fields" surrounded by curly braces `{}`.
|
||||
Anything that is not contained in braces is considered literal text, which is
|
||||
copied unchanged to the output. If you need to include a brace character in
|
||||
the literal text, it can be escaped by doubling: `{{` and `}}`.
|
||||
|
||||
The grammar for a replacement field is as follows:
|
||||
|
||||
<a id="replacement-field"></a>
|
||||
<pre><code class="language-json"
|
||||
>replacement_field ::= "{" [arg_id] [":" (<a href="#format-spec"
|
||||
>format_spec</a> | <a href="#chrono-format-spec">chrono_format_spec</a>)] "}"
|
||||
arg_id ::= integer | identifier
|
||||
integer ::= digit+
|
||||
digit ::= "0"..."9"
|
||||
identifier ::= id_start id_continue*
|
||||
id_start ::= "a"..."z" | "A"..."Z" | "_"
|
||||
id_continue ::= id_start | digit</code>
|
||||
</pre>
|
||||
|
||||
In less formal terms, the replacement field can start with an *arg_id* that
|
||||
specifies the argument whose value is to be formatted and inserted into the
|
||||
output instead of the replacement field. The *arg_id* is optionally followed
|
||||
by a *format_spec*, which is preceded by a colon `':'`. These specify a
|
||||
non-default format for the replacement value.
|
||||
|
||||
See also the [Format Specification
|
||||
Mini-Language](#format-specification-mini-language) section.
|
||||
|
||||
If the numerical arg_ids in a format string are 0, 1, 2, ... in sequence,
|
||||
they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
|
||||
automatically inserted in that order.
|
||||
|
||||
Named arguments can be referred to by their names or indices.
|
||||
|
||||
Some simple format string examples:
|
||||
|
||||
```c++
|
||||
"First, thou shalt count to {0}" // References the first argument
|
||||
"Bring me a {}" // Implicitly references the first argument
|
||||
"From {} to {}" // Same as "From {0} to {1}"
|
||||
```
|
||||
|
||||
The *format_spec* field contains a specification of how the value should
|
||||
be presented, including such details as field width, alignment, padding,
|
||||
decimal precision and so on. Each value type can define its own
|
||||
"formatting mini-language" or interpretation of the *format_spec*.
|
||||
|
||||
Most built-in types support a common formatting mini-language, which is
|
||||
described in the next section.
|
||||
|
||||
A *format_spec* field can also include nested replacement fields in
|
||||
certain positions within it. These nested replacement fields can contain
|
||||
only an argument id; format specifications are not allowed. This allows
|
||||
the formatting of a value to be dynamically specified.
|
||||
|
||||
See the [Format Examples](#format-examples) section for some examples.
|
||||
|
||||
## Format Specification Mini-Language
|
||||
|
||||
"Format specifications" are used within replacement fields contained within a
|
||||
format string to define how individual values are presented. Each formattable
|
||||
type may define how the format specification is to be interpreted.
|
||||
|
||||
Most built-in types implement the following options for format
|
||||
specifications, although some of the formatting options are only
|
||||
supported by the numeric types.
|
||||
|
||||
The general form of a *standard format specifier* is:
|
||||
|
||||
<a id="format-spec"></a>
|
||||
<pre><code class="language-json"
|
||||
>format_spec ::= [[fill]align][sign]["#"]["0"][width]["." precision]["L"][type]
|
||||
fill ::= <a character other than '{' or '}'>
|
||||
align ::= "<" | ">" | "^"
|
||||
sign ::= "+" | "-" | " "
|
||||
width ::= <a href="#replacement-field">integer</a> | "{" [<a
|
||||
href="#replacement-field">arg_id</a>] "}"
|
||||
precision ::= <a href="#replacement-field">integer</a> | "{" [<a
|
||||
href="#replacement-field">arg_id</a>] "}"
|
||||
type ::= "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" |
|
||||
"g" | "G" | "o" | "p" | "s" | "x" | "X" | "?"</code>
|
||||
</pre>
|
||||
|
||||
The *fill* character can be any Unicode code point other than `'{'` or `'}'`.
|
||||
The presence of a fill character is signaled by the character following it,
|
||||
which must be one of the alignment options. If the second character of
|
||||
*format_spec* is not a valid alignment option, then it is assumed that both
|
||||
the fill character and the alignment option are absent.
|
||||
|
||||
The meaning of the various alignment options is as follows:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'<'</code></td>
|
||||
<td>
|
||||
Forces the field to be left-aligned within the available space (this is the
|
||||
default for most objects).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'>'</code></td>
|
||||
<td>
|
||||
Forces the field to be right-aligned within the available space (this is
|
||||
the default for numbers).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'^'</code></td>
|
||||
<td>Forces the field to be centered within the available space.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Note that unless a minimum field width is defined, the field width will
|
||||
always be the same size as the data to fill it, so that the alignment
|
||||
option has no meaning in this case.
|
||||
|
||||
The *sign* option is only valid for floating point and signed integer types,
|
||||
and can be one of the following:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'+'</code></td>
|
||||
<td>
|
||||
Indicates that a sign should be used for both nonnegative as well as
|
||||
negative numbers.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'-'</code></td>
|
||||
<td>
|
||||
Indicates that a sign should be used only for negative numbers (this is the
|
||||
default behavior).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>space</td>
|
||||
<td>
|
||||
Indicates that a leading space should be used on nonnegative numbers, and a
|
||||
minus sign on negative numbers.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The `'#'` option causes the "alternate form" to be used for the
|
||||
conversion. The alternate form is defined differently for different
|
||||
types. This option is only valid for integer and floating-point types.
|
||||
For integers, when binary, octal, or hexadecimal output is used, this
|
||||
option adds the prefix respective `"0b"` (`"0B"`), `"0"`, or `"0x"`
|
||||
(`"0X"`) to the output value. Whether the prefix is lower-case or
|
||||
upper-case is determined by the case of the type specifier, for example,
|
||||
the prefix `"0x"` is used for the type `'x'` and `"0X"` is used for
|
||||
`'X'`. For floating-point numbers the alternate form causes the result
|
||||
of the conversion to always contain a decimal-point character, even if
|
||||
no digits follow it. Normally, a decimal-point character appears in the
|
||||
result of these conversions only if a digit follows it. In addition, for
|
||||
`'g'` and `'G'` conversions, trailing zeros are not removed from the
|
||||
result.
|
||||
|
||||
*width* is a decimal integer defining the minimum field width. If not
|
||||
specified, then the field width will be determined by the content.
|
||||
|
||||
Preceding the *width* field by a zero (`'0'`) character enables
|
||||
sign-aware zero-padding for numeric types. It forces the padding to be
|
||||
placed after the sign or base (if any) but before the digits. This is
|
||||
used for printing fields in the form "+000000120". This option is only
|
||||
valid for numeric types and it has no effect on formatting of infinity
|
||||
and NaN. This option is ignored when any alignment specifier is present.
|
||||
|
||||
The *precision* is a decimal number indicating how many digits should be
|
||||
displayed after the decimal point for a floating-point value formatted
|
||||
with `'f'` and `'F'`, or before and after the decimal point for a
|
||||
floating-point value formatted with `'g'` or `'G'`. For non-number types
|
||||
the field indicates the maximum field size - in other words, how many
|
||||
characters will be used from the field content. The *precision* is not
|
||||
allowed for integer, character, Boolean, and pointer values. Note that a
|
||||
C string must be null-terminated even if precision is specified.
|
||||
|
||||
The `'L'` option uses the current locale setting to insert the appropriate
|
||||
number separator characters. This option is only valid for numeric types.
|
||||
|
||||
Finally, the *type* determines how the data should be presented.
|
||||
|
||||
The available string presentation types are:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'s'</code></td>
|
||||
<td>
|
||||
String format. This is the default type for strings and may be omitted.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'?'</code></td>
|
||||
<td>Debug format. The string is quoted and special characters escaped.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'s'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The available character presentation types are:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'c'</code></td>
|
||||
<td>
|
||||
Character format. This is the default type for characters and may be
|
||||
omitted.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'?'</code></td>
|
||||
<td>Debug format. The character is quoted and special characters escaped.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'c'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The available integer presentation types are:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'b'</code></td>
|
||||
<td>
|
||||
Binary format. Outputs the number in base 2. Using the <code>'#'</code>
|
||||
option with this type adds the prefix <code>"0b"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'B'</code></td>
|
||||
<td>
|
||||
Binary format. Outputs the number in base 2. Using the <code>'#'</code>
|
||||
option with this type adds the prefix <code>"0B"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'c'</code></td>
|
||||
<td>Character format. Outputs the number as a character.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'d'</code></td>
|
||||
<td>Decimal integer. Outputs the number in base 10.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'o'</code></td>
|
||||
<td>Octal format. Outputs the number in base 8.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'x'</code></td>
|
||||
<td>
|
||||
Hex format. Outputs the number in base 16, using lower-case letters for the
|
||||
digits above 9. Using the <code>'#'</code> option with this type adds the
|
||||
prefix <code>"0x"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'X'</code></td>
|
||||
<td>
|
||||
Hex format. Outputs the number in base 16, using upper-case letters for the
|
||||
digits above 9. Using the <code>'#'</code> option with this type adds the
|
||||
prefix <code>"0X"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'d'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Integer presentation types can also be used with character and Boolean values
|
||||
with the only exception that `'c'` cannot be used with `bool`. Boolean values
|
||||
are formatted using textual representation, either `true` or `false`, if the
|
||||
presentation type is not specified.
|
||||
|
||||
The available presentation types for floating-point values are:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'a'</code></td>
|
||||
<td>
|
||||
Hexadecimal floating point format. Prints the number in base 16 with
|
||||
prefix <code>"0x"</code> and lower-case letters for digits above 9.
|
||||
Uses <code>'p'</code> to indicate the exponent.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'A'</code></td>
|
||||
<td>
|
||||
Same as <code>'a'</code> except it uses upper-case letters for the
|
||||
prefix, digits above 9 and to indicate the exponent.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'e'</code></td>
|
||||
<td>
|
||||
Exponent notation. Prints the number in scientific notation using
|
||||
the letter 'e' to indicate the exponent.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'E'</code></td>
|
||||
<td>
|
||||
Exponent notation. Same as <code>'e'</code> except it uses an
|
||||
upper-case <code>'E'</code> as the separator character.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'f'</code></td>
|
||||
<td>Fixed point. Displays the number as a fixed-point number.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'F'</code></td>
|
||||
<td>
|
||||
Fixed point. Same as <code>'f'</code>, but converts <code>nan</code>
|
||||
to <code>NAN</code> and <code>inf</code> to <code>INF</code>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'g'</code></td>
|
||||
<td>
|
||||
<p>General format. For a given precision <code>p >= 1</code>,
|
||||
this rounds the number to <code>p</code> significant digits and then
|
||||
formats the result in either fixed-point format or in scientific
|
||||
notation, depending on its magnitude.</p>
|
||||
<p>A precision of <code>0</code> is treated as equivalent to a precision
|
||||
of <code>1</code>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'G'</code></td>
|
||||
<td>
|
||||
General format. Same as <code>'g'</code> except switches to
|
||||
<code>'E'</code> if the number gets too large. The representations of
|
||||
infinity and NaN are uppercased, too.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>
|
||||
Similar to <code>'g'</code>, except that the default precision is as
|
||||
high as needed to represent the particular value.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The available presentation types for pointers are:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'p'</code></td>
|
||||
<td>
|
||||
Pointer format. This is the default type for pointers and may be omitted.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'p'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Chrono Format Specifications
|
||||
|
||||
Format specifications for chrono duration and time point types as well as
|
||||
`std::tm` have the following syntax:
|
||||
|
||||
<a id="chrono-format-spec"></a>
|
||||
<pre><code class="language-json"
|
||||
>chrono_format_spec ::= [[<a href="#format-spec">fill</a>]<a href="#format-spec"
|
||||
>align</a>][<a href="#format-spec">width</a>]["." <a href="#format-spec"
|
||||
>precision</a>][chrono_specs]
|
||||
chrono_specs ::= conversion_spec |
|
||||
chrono_specs (conversion_spec | literal_char)
|
||||
conversion_spec ::= "%" [padding_modifier] [locale_modifier] chrono_type
|
||||
literal_char ::= <a character other than '{', '}' or '%'>
|
||||
padding_modifier ::= "-" | "_" | "0"
|
||||
locale_modifier ::= "E" | "O"
|
||||
chrono_type ::= "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" |
|
||||
"F" | "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" |
|
||||
"n" | "p" | "q" | "Q" | "r" | "R" | "S" | "t" | "T" |
|
||||
"u" | "U" | "V" | "w" | "W" | "x" | "X" | "y" | "Y" |
|
||||
"z" | "Z" | "%"</code>
|
||||
</pre>
|
||||
|
||||
Literal chars are copied unchanged to the output. Precision is valid only
|
||||
for `std::chrono::duration` types with a floating-point representation type.
|
||||
|
||||
The available presentation types (*chrono_type*) are:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'a'</code></td>
|
||||
<td>
|
||||
The abbreviated weekday name, e.g. "Sat". If the value does not contain a
|
||||
valid weekday, an exception of type <code>format_error</code> is thrown.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'A'</code></td>
|
||||
<td>
|
||||
The full weekday name, e.g. "Saturday". If the value does not contain a
|
||||
valid weekday, an exception of type <code>format_error</code> is thrown.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'b'</code></td>
|
||||
<td>
|
||||
The abbreviated month name, e.g. "Nov". If the value does not contain a
|
||||
valid month, an exception of type <code>format_error</code> is thrown.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'B'</code></td>
|
||||
<td>
|
||||
The full month name, e.g. "November". If the value does not contain a valid
|
||||
month, an exception of type <code>format_error</code> is thrown.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'c'</code></td>
|
||||
<td>
|
||||
The date and time representation, e.g. "Sat Nov 12 22:04:00 1955". The
|
||||
modified command <code>%Ec</code> produces the locale's alternate date and
|
||||
time representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'C'</code></td>
|
||||
<td>
|
||||
The year divided by 100 using floored division, e.g. "19". If the result
|
||||
is a single decimal digit, it is prefixed with 0. The modified command
|
||||
<code>%EC</code> produces the locale's alternative representation of the
|
||||
century.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'d'</code></td>
|
||||
<td>
|
||||
The day of month as a decimal number. If the result is a single decimal
|
||||
digit, it is prefixed with 0. The modified command <code>%Od</code>
|
||||
produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'D'</code></td>
|
||||
<td>Equivalent to <code>%m/%d/%y</code>, e.g. "11/12/55".</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'e'</code></td>
|
||||
<td>
|
||||
The day of month as a decimal number. If the result is a single decimal
|
||||
digit, it is prefixed with a space. The modified command <code>%Oe</code>
|
||||
produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'F'</code></td>
|
||||
<td>Equivalent to <code>%Y-%m-%d</code>, e.g. "1955-11-12".</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'g'</code></td>
|
||||
<td>
|
||||
The last two decimal digits of the ISO week-based year. If the result is a
|
||||
single digit it is prefixed by 0.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'G'</code></td>
|
||||
<td>
|
||||
The ISO week-based year as a decimal number. If the result is less than
|
||||
four digits it is left-padded with 0 to four digits.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'h'</code></td>
|
||||
<td>Equivalent to <code>%b</code>, e.g. "Nov".</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'H'</code></td>
|
||||
<td>
|
||||
The hour (24-hour clock) as a decimal number. If the result is a single
|
||||
digit, it is prefixed with 0. The modified command <code>%OH</code>
|
||||
produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'I'</code></td>
|
||||
<td>
|
||||
The hour (12-hour clock) as a decimal number. If the result is a single
|
||||
digit, it is prefixed with 0. The modified command <code>%OI</code>
|
||||
produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'j'</code></td>
|
||||
<td>
|
||||
If the type being formatted is a specialization of duration, the decimal
|
||||
number of days without padding. Otherwise, the day of the year as a decimal
|
||||
number. Jan 1 is 001. If the result is less than three digits, it is
|
||||
left-padded with 0 to three digits.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'m'</code></td>
|
||||
<td>
|
||||
The month as a decimal number. Jan is 01. If the result is a single digit,
|
||||
it is prefixed with 0. The modified command <code>%Om</code> produces the
|
||||
locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'M'</code></td>
|
||||
<td>
|
||||
The minute as a decimal number. If the result is a single digit, it
|
||||
is prefixed with 0. The modified command <code>%OM</code> produces the
|
||||
locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'n'</code></td>
|
||||
<td>A new-line character.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'p'</code></td>
|
||||
<td>The AM/PM designations associated with a 12-hour clock.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'q'</code></td>
|
||||
<td>The duration's unit suffix.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'Q'</code></td>
|
||||
<td>
|
||||
The duration's numeric value (as if extracted via <code>.count()</code>).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'r'</code></td>
|
||||
<td>The 12-hour clock time, e.g. "10:04:00 PM".</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'R'</code></td>
|
||||
<td>Equivalent to <code>%H:%M</code>, e.g. "22:04".</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'S'</code></td>
|
||||
<td>
|
||||
Seconds as a decimal number. If the number of seconds is less than 10, the
|
||||
result is prefixed with 0. If the precision of the input cannot be exactly
|
||||
represented with seconds, then the format is a decimal floating-point number
|
||||
with a fixed format and a precision matching that of the precision of the
|
||||
input (or to a microseconds precision if the conversion to floating-point
|
||||
decimal seconds cannot be made within 18 fractional digits). The modified
|
||||
command <code>%OS</code> produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'t'</code></td>
|
||||
<td>A horizontal-tab character.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'T'</code></td>
|
||||
<td>Equivalent to <code>%H:%M:%S</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'u'</code></td>
|
||||
<td>
|
||||
The ISO weekday as a decimal number (1-7), where Monday is 1. The modified
|
||||
command <code>%Ou</code> produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'U'</code></td>
|
||||
<td>
|
||||
The week number of the year as a decimal number. The first Sunday of the
|
||||
year is the first day of week 01. Days of the same year prior to that are
|
||||
in week 00. If the result is a single digit, it is prefixed with 0.
|
||||
The modified command <code>%OU</code> produces the locale's alternative
|
||||
representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'V'</code></td>
|
||||
<td>
|
||||
The ISO week-based week number as a decimal number. If the result is a
|
||||
single digit, it is prefixed with 0. The modified command <code>%OV</code>
|
||||
produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'w'</code></td>
|
||||
<td>
|
||||
The weekday as a decimal number (0-6), where Sunday is 0. The modified
|
||||
command <code>%Ow</code> produces the locale's alternative representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'W'</code></td>
|
||||
<td>
|
||||
The week number of the year as a decimal number. The first Monday of the
|
||||
year is the first day of week 01. Days of the same year prior to that are
|
||||
in week 00. If the result is a single digit, it is prefixed with 0.
|
||||
The modified command <code>%OW</code> produces the locale's alternative
|
||||
representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'x'</code></td>
|
||||
<td>
|
||||
The date representation, e.g. "11/12/55". The modified command
|
||||
<code>%Ex</code> produces the locale's alternate date representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'X'</code></td>
|
||||
<td>
|
||||
The time representation, e.g. "10:04:00". The modified command
|
||||
<code>%EX</code> produces the locale's alternate time representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'y'</code></td>
|
||||
<td>
|
||||
The last two decimal digits of the year. If the result is a single digit
|
||||
it is prefixed by 0. The modified command <code>%Oy</code> produces the
|
||||
locale's alternative representation. The modified command <code>%Ey</code>
|
||||
produces the locale's alternative representation of offset from
|
||||
<code>%EC</code> (year only).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'Y'</code></td>
|
||||
<td>
|
||||
The year as a decimal number. If the result is less than four digits it is
|
||||
left-padded with 0 to four digits. The modified command <code>%EY</code>
|
||||
produces the locale's alternative full year representation.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'z'</code></td>
|
||||
<td>
|
||||
The offset from UTC in the ISO 8601:2004 format. For example -0430 refers
|
||||
to 4 hours 30 minutes behind UTC. If the offset is zero, +0000 is used.
|
||||
The modified commands <code>%Ez</code> and <code>%Oz</code> insert a
|
||||
<code>:</code> between the hours and minutes: -04:30. If the offset
|
||||
information is not available, an exception of type
|
||||
<code>format_error</code> is thrown.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'Z'</code></td>
|
||||
<td>
|
||||
The time zone abbreviation. If the time zone abbreviation is not available,
|
||||
an exception of type <code>format_error</code> is thrown.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'%'</code></td>
|
||||
<td>A % character.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Specifiers that have a calendaric component such as `'d'` (the day of month)
|
||||
are valid only for `std::tm` and time points but not durations.
|
||||
|
||||
The available padding modifiers (*padding_modifier*) are:
|
||||
|
||||
| Type | Meaning |
|
||||
|-------|-----------------------------------------|
|
||||
| `'_'` | Pad a numeric result with spaces. |
|
||||
| `'-'` | Do not pad a numeric result string. |
|
||||
| `'0'` | Pad a numeric result string with zeros. |
|
||||
|
||||
These modifiers are only supported for the `'H'`, `'I'`, `'M'`, `'S'`, `'U'`,
|
||||
`'V'`, `'W'`, `'Y'`, `'d'`, `'j'` and `'m'` presentation types.
|
||||
|
||||
## Range Format Specifications
|
||||
|
||||
Format specifications for range types have the following syntax:
|
||||
|
||||
<pre><code class="language-json"
|
||||
>range_format_spec ::= ["n"][range_type][range_underlying_spec]</code>
|
||||
</pre>
|
||||
|
||||
The `'n'` option formats the range without the opening and closing brackets.
|
||||
|
||||
The available presentation types for `range_type` are:
|
||||
|
||||
| Type | Meaning |
|
||||
|--------|------------------------------------------------------------|
|
||||
| none | Default format. |
|
||||
| `'s'` | String format. The range is formatted as a string. |
|
||||
| `'?s'` | Debug format. The range is formatted as an escaped string. |
|
||||
|
||||
If `range_type` is `'s'` or `'?s'`, the range element type must be a character
|
||||
type. The `'n'` option and `range_underlying_spec` are mutually exclusive with
|
||||
`'s'` and `'?s'`.
|
||||
|
||||
The `range_underlying_spec` is parsed based on the formatter of the range's
|
||||
element type.
|
||||
|
||||
By default, a range of characters or strings is printed escaped and quoted.
|
||||
But if any `range_underlying_spec` is provided (even if it is empty), then the
|
||||
characters or strings are printed according to the provided specification.
|
||||
|
||||
Examples:
|
||||
|
||||
```c++
|
||||
fmt::print("{}", std::vector{10, 20, 30});
|
||||
// Output: [10, 20, 30]
|
||||
fmt::print("{::#x}", std::vector{10, 20, 30});
|
||||
// Output: [0xa, 0x14, 0x1e]
|
||||
fmt::print("{}", std::vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Output: ['h', 'e', 'l', 'l', 'o']
|
||||
fmt::print("{:n}", std::vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Output: 'h', 'e', 'l', 'l', 'o'
|
||||
fmt::print("{:s}", std::vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Output: "hello"
|
||||
fmt::print("{:?s}", std::vector{'h', 'e', 'l', 'l', 'o', '\n'});
|
||||
// Output: "hello\n"
|
||||
fmt::print("{::}", std::vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Output: [h, e, l, l, o]
|
||||
fmt::print("{::d}", std::vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Output: [104, 101, 108, 108, 111]
|
||||
```
|
||||
|
||||
## Format Examples
|
||||
|
||||
This section contains examples of the format syntax and comparison with
|
||||
the printf formatting.
|
||||
|
||||
In most of the cases the syntax is similar to the printf formatting,
|
||||
with the addition of the `{}` and with `:` used instead of `%`. For
|
||||
example, `"%03.2f"` can be translated to `"{:03.2f}"`.
|
||||
|
||||
The new format syntax also supports new and different options, shown in
|
||||
the following examples.
|
||||
|
||||
Accessing arguments by position:
|
||||
|
||||
```c++
|
||||
fmt::format("{0}, {1}, {2}", 'a', 'b', 'c');
|
||||
// Result: "a, b, c"
|
||||
fmt::format("{}, {}, {}", 'a', 'b', 'c');
|
||||
// Result: "a, b, c"
|
||||
fmt::format("{2}, {1}, {0}", 'a', 'b', 'c');
|
||||
// Result: "c, b, a"
|
||||
fmt::format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
|
||||
// Result: "abracadabra"
|
||||
```
|
||||
|
||||
Aligning the text and specifying a width:
|
||||
|
||||
```c++
|
||||
fmt::format("{:<30}", "left aligned");
|
||||
// Result: "left aligned "
|
||||
fmt::format("{:>30}", "right aligned");
|
||||
// Result: " right aligned"
|
||||
fmt::format("{:^30}", "centered");
|
||||
// Result: " centered "
|
||||
fmt::format("{:*^30}", "centered"); // use '*' as a fill char
|
||||
// Result: "***********centered***********"
|
||||
```
|
||||
|
||||
Dynamic width:
|
||||
|
||||
```c++
|
||||
fmt::format("{:<{}}", "left aligned", 30);
|
||||
// Result: "left aligned "
|
||||
```
|
||||
|
||||
Dynamic precision:
|
||||
|
||||
```c++
|
||||
fmt::format("{:.{}f}", 3.14, 1);
|
||||
// Result: "3.1"
|
||||
```
|
||||
|
||||
Replacing `%+f`, `%-f`, and `% f` and specifying a sign:
|
||||
|
||||
```c++
|
||||
fmt::format("{:+f}; {:+f}", 3.14, -3.14); // show it always
|
||||
// Result: "+3.140000; -3.140000"
|
||||
fmt::format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
|
||||
// Result: " 3.140000; -3.140000"
|
||||
fmt::format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
|
||||
// Result: "3.140000; -3.140000"
|
||||
```
|
||||
|
||||
Replacing `%x` and `%o` and converting the value to different bases:
|
||||
|
||||
```c++
|
||||
fmt::format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||
// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
|
||||
// with 0x or 0 or 0b as prefix:
|
||||
fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
|
||||
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
|
||||
```
|
||||
|
||||
Padded hex byte with prefix and always prints both hex characters:
|
||||
|
||||
```c++
|
||||
fmt::format("{:#04x}", 0);
|
||||
// Result: "0x00"
|
||||
```
|
||||
|
||||
Box drawing using Unicode fill:
|
||||
|
||||
```c++
|
||||
fmt::print(
|
||||
"┌{0:─^{2}}┐\n"
|
||||
"│{1: ^{2}}│\n"
|
||||
"└{0:─^{2}}┘\n", "", "Hello, world!", 20);
|
||||
```
|
||||
|
||||
prints:
|
||||
|
||||
```
|
||||
┌────────────────────┐
|
||||
│ Hello, world! │
|
||||
└────────────────────┘
|
||||
```
|
||||
|
||||
Using type-specific formatting:
|
||||
|
||||
```c++
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
auto t = tm();
|
||||
t.tm_year = 2010 - 1900;
|
||||
t.tm_mon = 7;
|
||||
t.tm_mday = 4;
|
||||
t.tm_hour = 12;
|
||||
t.tm_min = 15;
|
||||
t.tm_sec = 58;
|
||||
fmt::print("{:%Y-%m-%d %H:%M:%S}", t);
|
||||
// Prints: 2010-08-04 12:15:58
|
||||
```
|
||||
|
||||
Using the comma as a thousands separator:
|
||||
|
||||
```c++
|
||||
#include <fmt/format.h>
|
||||
|
||||
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
|
||||
// s == "1,234,567,890"
|
||||
```
|
||||
393
doc/syntax.rst
393
doc/syntax.rst
@@ -1,393 +0,0 @@
|
||||
.. highlight:: c++
|
||||
|
||||
.. _syntax:
|
||||
|
||||
********************
|
||||
Format String Syntax
|
||||
********************
|
||||
|
||||
Formatting functions such as :ref:`fmt::format() <format>` and :ref:`fmt::print() <print>`
|
||||
use the same format string syntax described in this section.
|
||||
|
||||
Format strings contain "replacement fields" surrounded by curly braces ``{}``.
|
||||
Anything that is not contained in braces is considered literal text, which is
|
||||
copied unchanged to the output. If you need to include a brace character in the
|
||||
literal text, it can be escaped by doubling: ``{{`` and ``}}``.
|
||||
|
||||
The grammar for a replacement field is as follows:
|
||||
|
||||
.. productionlist:: sf
|
||||
replacement_field: "{" [`arg_index`] [":" `format_spec`] "}"
|
||||
arg_index: `integer`
|
||||
|
||||
In less formal terms, the replacement field can start with an *arg_index*
|
||||
that specifies the argument whose value is to be formatted and inserted into
|
||||
the output instead of the replacement field.
|
||||
The *arg_index* is optionally followed by a *format_spec*, which is preceded
|
||||
by a colon ``':'``. These specify a non-default format for the replacement value.
|
||||
|
||||
See also the :ref:`formatspec` section.
|
||||
|
||||
If the numerical arg_indexes in a format string are 0, 1, 2, ... in sequence,
|
||||
they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
|
||||
automatically inserted in that order.
|
||||
|
||||
Some simple format string examples::
|
||||
|
||||
"First, thou shalt count to {0}" // References the first argument
|
||||
"Bring me a {}" // Implicitly references the first argument
|
||||
"From {} to {}" // Same as "From {0} to {1}"
|
||||
|
||||
The *format_spec* field contains a specification of how the value should be
|
||||
presented, including such details as field width, alignment, padding, decimal
|
||||
precision and so on. Each value type can define its own "formatting
|
||||
mini-language" or interpretation of the *format_spec*.
|
||||
|
||||
Most built-in types support a common formatting mini-language, which is
|
||||
described in the next section.
|
||||
|
||||
A *format_spec* field can also include nested replacement fields within it.
|
||||
These nested replacement fields can contain only an argument index;
|
||||
format specifications are not allowed. Formatting is performed as if the
|
||||
replacement fields within the format_spec are substituted before the
|
||||
*format_spec* string is interpreted. This allows the formatting of a value
|
||||
to be dynamically specified.
|
||||
|
||||
See the :ref:`formatexamples` section for some examples.
|
||||
|
||||
|
||||
.. _formatspec:
|
||||
|
||||
Format Specification Mini-Language
|
||||
==================================
|
||||
|
||||
"Format specifications" are used within replacement fields contained within a
|
||||
format string to define how individual values are presented (see
|
||||
:ref:`formatstrings`). Each formattable type may define how the format
|
||||
specification is to be interpreted.
|
||||
|
||||
Most built-in types implement the following options for format specifications,
|
||||
although some of the formatting options are only supported by the numeric types.
|
||||
|
||||
The general form of a *standard format specifier* is:
|
||||
|
||||
.. productionlist:: sf
|
||||
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`]
|
||||
fill: <a character other than '{' or '}'>
|
||||
align: "<" | ">" | "=" | "^"
|
||||
sign: "+" | "-" | " "
|
||||
width: `integer`
|
||||
precision: `integer` | "{" `arg_index` "}"
|
||||
type: `int_type` | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||
int_type: "b" | "B" | "d" | "o" | "x" | "X"
|
||||
|
||||
The *fill* character can be any character other than '{' or '}'. The presence
|
||||
of a fill character is signaled by the character following it, which must be
|
||||
one of the alignment options. If the second character of *format_spec* is not
|
||||
a valid alignment option, then it is assumed that both the fill character and
|
||||
the alignment option are absent.
|
||||
|
||||
The meaning of the various alignment options is as follows:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| Option | Meaning |
|
||||
+=========+==========================================================+
|
||||
| ``'<'`` | Forces the field to be left-aligned within the available |
|
||||
| | space (this is the default for most objects). |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'>'`` | Forces the field to be right-aligned within the |
|
||||
| | available space (this is the default for numbers). |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'='`` | Forces the padding to be placed after the sign (if any) |
|
||||
| | but before the digits. This is used for printing fields |
|
||||
| | in the form '+000000120'. This alignment option is only |
|
||||
| | valid for numeric types. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'^'`` | Forces the field to be centered within the available |
|
||||
| | space. |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
Note that unless a minimum field width is defined, the field width will always
|
||||
be the same size as the data to fill it, so that the alignment option has no
|
||||
meaning in this case.
|
||||
|
||||
The *sign* option is only valid for number types, and can be one of the
|
||||
following:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| Option | Meaning |
|
||||
+=========+==========================================================+
|
||||
| ``'+'`` | indicates that a sign should be used for both |
|
||||
| | positive as well as negative numbers. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'-'`` | indicates that a sign should be used only for negative |
|
||||
| | numbers (this is the default behavior). |
|
||||
+---------+----------------------------------------------------------+
|
||||
| space | indicates that a leading space should be used on |
|
||||
| | positive numbers, and a minus sign on negative numbers. |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
The ``'#'`` option causes the "alternate form" to be used for the
|
||||
conversion. The alternate form is defined differently for different
|
||||
types. This option is only valid for integer and floating-point types.
|
||||
For integers, when binary, octal, or hexadecimal output is used, this
|
||||
option adds the prefix respective ``"0b"`` (``"0B"``), ``"0"``, or
|
||||
``"0x"`` (``"0X"``) to the output value. Whether the prefix is
|
||||
lower-case or upper-case is determined by the case of the type
|
||||
specifier, for example, the prefix ``"0x"`` is used for the type ``'x'``
|
||||
and ``"0X"`` is used for ``'X'``. For floating-point numbers the
|
||||
alternate form causes the result of the conversion to always contain a
|
||||
decimal-point character, even if no digits follow it. Normally, a
|
||||
decimal-point character appears in the result of these conversions
|
||||
only if a digit follows it. In addition, for ``'g'`` and ``'G'``
|
||||
conversions, trailing zeros are not removed from the result.
|
||||
|
||||
.. ifconfig:: False
|
||||
|
||||
The ``','`` option signals the use of a comma for a thousands separator.
|
||||
For a locale aware separator, use the ``'n'`` integer presentation type
|
||||
instead.
|
||||
|
||||
*width* is a decimal integer defining the minimum field width. If not
|
||||
specified, then the field width will be determined by the content.
|
||||
|
||||
Preceding the *width* field by a zero (``'0'``) character enables
|
||||
sign-aware zero-padding for numeric types. This is equivalent to a *fill*
|
||||
character of ``'0'`` with an *alignment* type of ``'='``.
|
||||
|
||||
The *precision* is a decimal number indicating how many digits should be
|
||||
displayed after the decimal point for a floating-point value formatted with
|
||||
``'f'`` and ``'F'``, or before and after the decimal point for a floating-point
|
||||
value formatted with ``'g'`` or ``'G'``. For non-number types the field
|
||||
indicates the maximum field size - in other words, how many characters will be
|
||||
used from the field content. The *precision* is not allowed for integer values.
|
||||
|
||||
Finally, the *type* determines how the data should be presented.
|
||||
|
||||
The available string presentation types are:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| Type | Meaning |
|
||||
+=========+==========================================================+
|
||||
| ``'s'`` | String format. This is the default type for strings and |
|
||||
| | may be omitted. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| none | The same as ``'s'``. |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
The available character presentation types are:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| Type | Meaning |
|
||||
+=========+==========================================================+
|
||||
| ``'c'`` | Character format. This is the default type for |
|
||||
| | characters and may be omitted. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| none | The same as ``'c'``. |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
The available integer presentation types are:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| Type | Meaning |
|
||||
+=========+==========================================================+
|
||||
| ``'b'`` | Binary format. Outputs the number in base 2. Using the |
|
||||
| | ``'#'`` option with this type adds the prefix ``"0b"`` |
|
||||
| | to the output value. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'B'`` | Binary format. Outputs the number in base 2. Using the |
|
||||
| | ``'#'`` option with this type adds the prefix ``"0B"`` |
|
||||
| | to the output value. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'d'`` | Decimal integer. Outputs the number in base 10. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'o'`` | Octal format. Outputs the number in base 8. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'x'`` | Hex format. Outputs the number in base 16, using |
|
||||
| | lower-case letters for the digits above 9. Using the |
|
||||
| | ``'#'`` option with this type adds the prefix ``"0x"`` |
|
||||
| | to the output value. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'X'`` | Hex format. Outputs the number in base 16, using |
|
||||
| | upper-case letters for the digits above 9. Using the |
|
||||
| | ``'#'`` option with this type adds the prefix ``"0X"`` |
|
||||
| | to the output value. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| none | The same as ``'d'``. |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
The available presentation types for floating-point values are:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| Type | Meaning |
|
||||
+=========+==========================================================+
|
||||
| ``'a'`` | Hexadecimal floating point format. Prints the number in |
|
||||
| | base 16 with prefix ``"0x"`` and lower-case letters for |
|
||||
| | digits above 9. Uses 'p' to indicate the exponent. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'A'`` | Same as ``'a'`` except it uses upper-case letters for |
|
||||
| | the prefix, digits above 9 and to indicate the exponent. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'e'`` | Exponent notation. Prints the number in scientific |
|
||||
| | notation using the letter 'e' to indicate the exponent. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'E'`` | Exponent notation. Same as ``'e'`` except it uses an |
|
||||
| | upper-case 'E' as the separator character. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'f'`` | Fixed point. Displays the number as a fixed-point |
|
||||
| | number. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'F'`` | Fixed point. Same as ``'f'``, but converts ``nan`` to |
|
||||
| | ``NAN`` and ``inf`` to ``INF``. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'g'`` | General format. For a given precision ``p >= 1``, |
|
||||
| | this rounds the number to ``p`` significant digits and |
|
||||
| | then formats the result in either fixed-point format |
|
||||
| | or in scientific notation, depending on its magnitude. |
|
||||
| | |
|
||||
| | A precision of ``0`` is treated as equivalent to a |
|
||||
| | precision of ``1``. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| ``'G'`` | General format. Same as ``'g'`` except switches to |
|
||||
| | ``'E'`` if the number gets too large. The |
|
||||
| | representations of infinity and NaN are uppercased, too. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| none | The same as ``'g'``. |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
.. ifconfig:: False
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| | The precise rules are as follows: suppose that the |
|
||||
| | result formatted with presentation type ``'e'`` and |
|
||||
| | precision ``p-1`` would have exponent ``exp``. Then |
|
||||
| | if ``-4 <= exp < p``, the number is formatted |
|
||||
| | with presentation type ``'f'`` and precision |
|
||||
| | ``p-1-exp``. Otherwise, the number is formatted |
|
||||
| | with presentation type ``'e'`` and precision ``p-1``. |
|
||||
| | In both cases insignificant trailing zeros are removed |
|
||||
| | from the significand, and the decimal point is also |
|
||||
| | removed if there are no remaining digits following it. |
|
||||
| | |
|
||||
| | Positive and negative infinity, positive and negative |
|
||||
| | zero, and nans, are formatted as ``inf``, ``-inf``, |
|
||||
| | ``0``, ``-0`` and ``nan`` respectively, regardless of |
|
||||
| | the precision. |
|
||||
| | |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
The available presentation types for pointers are:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
| Type | Meaning |
|
||||
+=========+==========================================================+
|
||||
| ``'p'`` | Pointer format. This is the default type for |
|
||||
| | pointers and may be omitted. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| none | The same as ``'p'``. |
|
||||
+---------+----------------------------------------------------------+
|
||||
|
||||
.. _formatexamples:
|
||||
|
||||
Format examples
|
||||
===============
|
||||
|
||||
This section contains examples of the format syntax and comparison with
|
||||
the printf formatting.
|
||||
|
||||
In most of the cases the syntax is similar to the printf formatting, with the
|
||||
addition of the ``{}`` and with ``:`` used instead of ``%``.
|
||||
For example, ``"%03.2f"`` can be translated to ``"{:03.2f}"``.
|
||||
|
||||
The new format syntax also supports new and different options, shown in the
|
||||
following examples.
|
||||
|
||||
Accessing arguments by position::
|
||||
|
||||
format("{0}, {1}, {2}", 'a', 'b', 'c');
|
||||
// Result: "a, b, c"
|
||||
format("{}, {}, {}", 'a', 'b', 'c');
|
||||
// Result: "a, b, c"
|
||||
format("{2}, {1}, {0}", 'a', 'b', 'c');
|
||||
// Result: "c, b, a"
|
||||
format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
|
||||
// Result: "abracadabra"
|
||||
|
||||
Aligning the text and specifying a width::
|
||||
|
||||
format("{:<30}", "left aligned");
|
||||
// Result: "left aligned "
|
||||
format("{:>30}", "right aligned");
|
||||
// Result: " right aligned"
|
||||
format("{:^30}", "centered");
|
||||
// Result: " centered "
|
||||
format("{:*^30}", "centered"); // use '*' as a fill char
|
||||
// Result: "***********centered***********"
|
||||
|
||||
Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
|
||||
|
||||
format("{:+f}; {:+f}", 3.14, -3.14); // show it always
|
||||
// Result: "+3.140000; -3.140000"
|
||||
format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
|
||||
// Result: " 3.140000; -3.140000"
|
||||
format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
|
||||
// Result: "3.140000; -3.140000"
|
||||
|
||||
Replacing ``%x`` and ``%o`` and converting the value to different bases::
|
||||
|
||||
format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||
// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
|
||||
// with 0x or 0 or 0b as prefix:
|
||||
format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
|
||||
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
|
||||
|
||||
.. ifconfig:: False
|
||||
|
||||
Using the comma as a thousands separator::
|
||||
|
||||
format("{:,}", 1234567890);
|
||||
'1,234,567,890'
|
||||
|
||||
Expressing a percentage::
|
||||
|
||||
>>> points = 19
|
||||
>>> total = 22
|
||||
Format("Correct answers: {:.2%}") << points/total)
|
||||
'Correct answers: 86.36%'
|
||||
|
||||
Using type-specific formatting::
|
||||
|
||||
>>> import datetime
|
||||
>>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
|
||||
Format("{:%Y-%m-%d %H:%M:%S}") << d)
|
||||
'2010-07-04 12:15:58'
|
||||
|
||||
Nesting arguments and more complex examples::
|
||||
|
||||
>>> for align, text in zip('<^>', ['left', 'center', 'right']):
|
||||
... '{0:{fill}{align}16}") << text, fill=align, align=align)
|
||||
...
|
||||
'left<<<<<<<<<<<<'
|
||||
'^^^^^center^^^^^'
|
||||
'>>>>>>>>>>>right'
|
||||
>>>
|
||||
>>> octets = [192, 168, 0, 1]
|
||||
Format("{:02X}{:02X}{:02X}{:02X}") << *octets)
|
||||
'C0A80001'
|
||||
>>> int(_, 16)
|
||||
3232235521
|
||||
>>>
|
||||
>>> width = 5
|
||||
>>> for num in range(5,12):
|
||||
... for base in 'dXob':
|
||||
... print('{0:{width}{base}}") << num, base=base, width=width), end=' ')
|
||||
... print()
|
||||
...
|
||||
5 5 5 101
|
||||
6 6 6 110
|
||||
7 7 7 111
|
||||
8 8 10 1000
|
||||
9 9 11 1001
|
||||
10 A 12 1010
|
||||
11 B 13 1011
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
.. highlight:: c++
|
||||
|
||||
*****
|
||||
Usage
|
||||
*****
|
||||
|
||||
To use the C++ Format library, add ``format.h`` and ``format.cc`` from
|
||||
a `release archive <https://github.com/cppformat/cppformat/releases/latest>`_
|
||||
or the `Git repository <https://github.com/cppformat/cppformat>`_ to your project.
|
||||
|
||||
If you are using Visual C++ with precompiled headers, you might need to add
|
||||
the line
|
||||
|
||||
::
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
before other includes in ``format.cc``.
|
||||
14198
gmock/gmock/gmock.h
14198
gmock/gmock/gmock.h
File diff suppressed because it is too large
Load Diff
20061
gmock/gtest/gtest.h
20061
gmock/gtest/gtest.h
File diff suppressed because it is too large
Load Diff
220
include/fmt/args.h
Normal file
220
include/fmt/args.h
Normal file
@@ -0,0 +1,220 @@
|
||||
// Formatting library for C++ - dynamic argument lists
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_ARGS_H_
|
||||
#define FMT_ARGS_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <functional> // std::reference_wrapper
|
||||
# include <memory> // std::unique_ptr
|
||||
# include <vector>
|
||||
#endif
|
||||
|
||||
#include "format.h" // std_string_view
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename T> struct is_reference_wrapper : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||
|
||||
template <typename T> auto unwrap(const T& v) -> const T& { return v; }
|
||||
template <typename T>
|
||||
auto unwrap(const std::reference_wrapper<T>& v) -> const T& {
|
||||
return static_cast<const T&>(v);
|
||||
}
|
||||
|
||||
// node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC
|
||||
// 2022 (v17.10.0).
|
||||
//
|
||||
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
|
||||
// templates it doesn't complain about inability to deduce single translation
|
||||
// unit for placing vtable. So node is made a fake template.
|
||||
template <typename = void> struct node {
|
||||
virtual ~node() = default;
|
||||
std::unique_ptr<node<>> next;
|
||||
};
|
||||
|
||||
class dynamic_arg_list {
|
||||
template <typename T> struct typed_node : node<> {
|
||||
T value;
|
||||
|
||||
template <typename Arg>
|
||||
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
|
||||
: value(arg.data(), arg.size()) {}
|
||||
};
|
||||
|
||||
std::unique_ptr<node<>> head_;
|
||||
|
||||
public:
|
||||
template <typename T, typename Arg> auto push(const Arg& arg) -> const T& {
|
||||
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
||||
auto& value = new_node->value;
|
||||
new_node->next = std::move(head_);
|
||||
head_ = std::move(new_node);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* A dynamic list of formatting arguments with storage.
|
||||
*
|
||||
* It can be implicitly converted into `fmt::basic_format_args` for passing
|
||||
* into type-erased formatting functions such as `fmt::vformat`.
|
||||
*/
|
||||
template <typename Context> class dynamic_format_arg_store {
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
template <typename T> struct need_copy {
|
||||
static constexpr detail::type mapped_type =
|
||||
detail::mapped_type_constant<T, char_type>::value;
|
||||
|
||||
enum {
|
||||
value = !(detail::is_reference_wrapper<T>::value ||
|
||||
std::is_same<T, basic_string_view<char_type>>::value ||
|
||||
std::is_same<T, detail::std_string_view<char_type>>::value ||
|
||||
(mapped_type != detail::type::cstring_type &&
|
||||
mapped_type != detail::type::string_type &&
|
||||
mapped_type != detail::type::custom_type))
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using stored_t = conditional_t<
|
||||
std::is_convertible<T, std::basic_string<char_type>>::value &&
|
||||
!detail::is_reference_wrapper<T>::value,
|
||||
std::basic_string<char_type>, T>;
|
||||
|
||||
// Storage of basic_format_arg must be contiguous.
|
||||
std::vector<basic_format_arg<Context>> data_;
|
||||
std::vector<detail::named_arg_info<char_type>> named_info_;
|
||||
|
||||
// Storage of arguments not fitting into basic_format_arg must grow
|
||||
// without relocation because items in data_ refer to it.
|
||||
detail::dynamic_arg_list dynamic_args_;
|
||||
|
||||
friend class basic_format_args<Context>;
|
||||
|
||||
auto data() const -> const basic_format_arg<Context>* {
|
||||
return named_info_.empty() ? data_.data() : data_.data() + 1;
|
||||
}
|
||||
|
||||
template <typename T> void emplace_arg(const T& arg) {
|
||||
data_.emplace_back(arg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
|
||||
if (named_info_.empty())
|
||||
data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0));
|
||||
data_.emplace_back(detail::unwrap(arg.value));
|
||||
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
|
||||
data->pop_back();
|
||||
};
|
||||
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
|
||||
guard{&data_, pop_one};
|
||||
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
|
||||
data_[0] = {named_info_.data(), named_info_.size()};
|
||||
guard.release();
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr dynamic_format_arg_store() = default;
|
||||
|
||||
operator basic_format_args<Context>() const {
|
||||
return basic_format_args<Context>(data(), static_cast<int>(data_.size()),
|
||||
!named_info_.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument into the dynamic store for later passing to a formatting
|
||||
* function.
|
||||
*
|
||||
* Note that custom types and string types (but not string views) are copied
|
||||
* into the store dynamically allocating memory if necessary.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
* store.push_back(42);
|
||||
* store.push_back("abc");
|
||||
* store.push_back(1.5f);
|
||||
* std::string result = fmt::vformat("{} and {} and {}", store);
|
||||
*/
|
||||
template <typename T> void push_back(const T& arg) {
|
||||
if (detail::const_check(need_copy<T>::value))
|
||||
emplace_arg(dynamic_args_.push<stored_t<T>>(arg));
|
||||
else
|
||||
emplace_arg(detail::unwrap(arg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a reference to the argument into the dynamic store for later passing
|
||||
* to a formatting function.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
* char band[] = "Rolling Stones";
|
||||
* store.push_back(std::cref(band));
|
||||
* band[9] = 'c'; // Changing str affects the output.
|
||||
* std::string result = fmt::vformat("{}", store);
|
||||
* // result == "Rolling Scones"
|
||||
*/
|
||||
template <typename T> void push_back(std::reference_wrapper<T> arg) {
|
||||
static_assert(
|
||||
need_copy<T>::value,
|
||||
"objects of built-in types and string views are always copied");
|
||||
emplace_arg(arg.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds named argument into the dynamic store for later passing to a
|
||||
* formatting function. `std::reference_wrapper` is supported to avoid
|
||||
* copying of the argument. The name is always copied into the store.
|
||||
*/
|
||||
template <typename T>
|
||||
void push_back(const detail::named_arg<char_type, T>& arg) {
|
||||
const char_type* arg_name =
|
||||
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
|
||||
if (detail::const_check(need_copy<T>::value)) {
|
||||
emplace_arg(
|
||||
fmt::arg(arg_name, dynamic_args_.push<stored_t<T>>(arg.value)));
|
||||
} else {
|
||||
emplace_arg(fmt::arg(arg_name, arg.value));
|
||||
}
|
||||
}
|
||||
|
||||
/// Erase all elements from the store.
|
||||
void clear() {
|
||||
data_.clear();
|
||||
named_info_.clear();
|
||||
dynamic_args_ = {};
|
||||
}
|
||||
|
||||
/// Reserves space to store at least `new_cap` arguments including
|
||||
/// `new_cap_named` named arguments.
|
||||
void reserve(size_t new_cap, size_t new_cap_named) {
|
||||
FMT_ASSERT(new_cap >= new_cap_named,
|
||||
"set of arguments includes set of named arguments");
|
||||
data_.reserve(new_cap);
|
||||
named_info_.reserve(new_cap_named);
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the store.
|
||||
size_t size() const noexcept { return data_.size(); }
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_ARGS_H_
|
||||
2961
include/fmt/base.h
Normal file
2961
include/fmt/base.h
Normal file
File diff suppressed because it is too large
Load Diff
2338
include/fmt/chrono.h
Normal file
2338
include/fmt/chrono.h
Normal file
File diff suppressed because it is too large
Load Diff
610
include/fmt/color.h
Normal file
610
include/fmt/color.h
Normal file
@@ -0,0 +1,610 @@
|
||||
// Formatting library for C++ - color support
|
||||
//
|
||||
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_COLOR_H_
|
||||
#define FMT_COLOR_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
enum class color : uint32_t {
|
||||
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||
black = 0x000000, // rgb(0,0,0)
|
||||
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||
blue = 0x0000FF, // rgb(0,0,255)
|
||||
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||
brown = 0xA52A2A, // rgb(165,42,42)
|
||||
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||
coral = 0xFF7F50, // rgb(255,127,80)
|
||||
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||
crimson = 0xDC143C, // rgb(220,20,60)
|
||||
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||
dark_green = 0x006400, // rgb(0,100,0)
|
||||
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||
dim_gray = 0x696969, // rgb(105,105,105)
|
||||
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||
forest_green = 0x228B22, // rgb(34,139,34)
|
||||
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||
gold = 0xFFD700, // rgb(255,215,0)
|
||||
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||
gray = 0x808080, // rgb(128,128,128)
|
||||
green = 0x008000, // rgb(0,128,0)
|
||||
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||
indigo = 0x4B0082, // rgb(75,0,130)
|
||||
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||
light_coral = 0xF08080, // rgb(240,128,128)
|
||||
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||
light_green = 0x90EE90, // rgb(144,238,144)
|
||||
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||
lime = 0x00FF00, // rgb(0,255,0)
|
||||
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||
maroon = 0x800000, // rgb(128,0,0)
|
||||
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||
navy = 0x000080, // rgb(0,0,128)
|
||||
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||
olive = 0x808000, // rgb(128,128,0)
|
||||
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||
orange = 0xFFA500, // rgb(255,165,0)
|
||||
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||
peru = 0xCD853F, // rgb(205,133,63)
|
||||
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||
purple = 0x800080, // rgb(128,0,128)
|
||||
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||
red = 0xFF0000, // rgb(255,0,0)
|
||||
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||
salmon = 0xFA8072, // rgb(250,128,114)
|
||||
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||
sienna = 0xA0522D, // rgb(160,82,45)
|
||||
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||
slate_gray = 0x708090, // rgb(112,128,144)
|
||||
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||
tan = 0xD2B48C, // rgb(210,180,140)
|
||||
teal = 0x008080, // rgb(0,128,128)
|
||||
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||
tomato = 0xFF6347, // rgb(255,99,71)
|
||||
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||
violet = 0xEE82EE, // rgb(238,130,238)
|
||||
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||
white = 0xFFFFFF, // rgb(255,255,255)
|
||||
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||
}; // enum class color
|
||||
|
||||
enum class terminal_color : uint8_t {
|
||||
black = 30,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
bright_black = 90,
|
||||
bright_red,
|
||||
bright_green,
|
||||
bright_yellow,
|
||||
bright_blue,
|
||||
bright_magenta,
|
||||
bright_cyan,
|
||||
bright_white
|
||||
};
|
||||
|
||||
enum class emphasis : uint8_t {
|
||||
bold = 1,
|
||||
faint = 1 << 1,
|
||||
italic = 1 << 2,
|
||||
underline = 1 << 3,
|
||||
blink = 1 << 4,
|
||||
reverse = 1 << 5,
|
||||
conceal = 1 << 6,
|
||||
strikethrough = 1 << 7,
|
||||
};
|
||||
|
||||
// rgb is a struct for red, green and blue colors.
|
||||
// Using the name "rgb" makes some editors show the color in a tooltip.
|
||||
struct rgb {
|
||||
FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {}
|
||||
FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
|
||||
FMT_CONSTEXPR rgb(uint32_t hex)
|
||||
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
|
||||
FMT_CONSTEXPR rgb(color hex)
|
||||
: r((uint32_t(hex) >> 16) & 0xFF),
|
||||
g((uint32_t(hex) >> 8) & 0xFF),
|
||||
b(uint32_t(hex) & 0xFF) {}
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// color is a struct of either a rgb color or a terminal color.
|
||||
struct color_type {
|
||||
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
|
||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||
}
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
|
||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||
}
|
||||
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
|
||||
: is_rgb(), value{} {
|
||||
value.term_color = static_cast<uint8_t>(term_color);
|
||||
}
|
||||
bool is_rgb;
|
||||
union color_union {
|
||||
uint8_t term_color;
|
||||
uint32_t rgb_color;
|
||||
} value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// A text style consisting of foreground and background colors and emphasis.
|
||||
class text_style {
|
||||
public:
|
||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
|
||||
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||
|
||||
FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& {
|
||||
if (!set_foreground_color) {
|
||||
set_foreground_color = rhs.set_foreground_color;
|
||||
foreground_color = rhs.foreground_color;
|
||||
} else if (rhs.set_foreground_color) {
|
||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||
report_error("can't OR a terminal color");
|
||||
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
|
||||
}
|
||||
|
||||
if (!set_background_color) {
|
||||
set_background_color = rhs.set_background_color;
|
||||
background_color = rhs.background_color;
|
||||
} else if (rhs.set_background_color) {
|
||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||
report_error("can't OR a terminal color");
|
||||
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
|
||||
}
|
||||
|
||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
|
||||
static_cast<uint8_t>(rhs.ems));
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR auto operator|(text_style lhs, const text_style& rhs)
|
||||
-> text_style {
|
||||
return lhs |= rhs;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto has_foreground() const noexcept -> bool {
|
||||
return set_foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR auto has_background() const noexcept -> bool {
|
||||
return set_background_color;
|
||||
}
|
||||
FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool {
|
||||
return static_cast<uint8_t>(ems) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type {
|
||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||
return foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type {
|
||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||
return background_color;
|
||||
}
|
||||
FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis {
|
||||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||
return ems;
|
||||
}
|
||||
|
||||
private:
|
||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||
detail::color_type text_color) noexcept
|
||||
: set_foreground_color(), set_background_color(), ems() {
|
||||
if (is_foreground) {
|
||||
foreground_color = text_color;
|
||||
set_foreground_color = true;
|
||||
} else {
|
||||
background_color = text_color;
|
||||
set_background_color = true;
|
||||
}
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept
|
||||
-> text_style;
|
||||
|
||||
friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept
|
||||
-> text_style;
|
||||
|
||||
detail::color_type foreground_color;
|
||||
detail::color_type background_color;
|
||||
bool set_foreground_color;
|
||||
bool set_background_color;
|
||||
emphasis ems;
|
||||
};
|
||||
|
||||
/// Creates a text style from the foreground (text) color.
|
||||
FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept
|
||||
-> text_style {
|
||||
return text_style(true, foreground);
|
||||
}
|
||||
|
||||
/// Creates a text style from the background color.
|
||||
FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept
|
||||
-> text_style {
|
||||
return text_style(false, background);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept
|
||||
-> text_style {
|
||||
return text_style(lhs) | rhs;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char> struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(color_type text_color,
|
||||
const char* esc) noexcept {
|
||||
// If we have a terminal color, we need to output another escape code
|
||||
// sequence.
|
||||
if (!text_color.is_rgb) {
|
||||
bool is_background = esc == string_view("\x1b[48;2;");
|
||||
uint32_t value = text_color.value.term_color;
|
||||
// Background ASCII codes are the same as the foreground ones but with
|
||||
// 10 more.
|
||||
if (is_background) value += 10u;
|
||||
|
||||
size_t index = 0;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
|
||||
if (value >= 100u) {
|
||||
buffer[index++] = static_cast<Char>('1');
|
||||
value %= 100u;
|
||||
}
|
||||
buffer[index++] = static_cast<Char>('0' + value / 10u);
|
||||
buffer[index++] = static_cast<Char>('0' + value % 10u);
|
||||
|
||||
buffer[index++] = static_cast<Char>('m');
|
||||
buffer[index++] = static_cast<Char>('\0');
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
buffer[i] = static_cast<Char>(esc[i]);
|
||||
}
|
||||
rgb color(text_color.value.rgb_color);
|
||||
to_esc(color.r, buffer + 7, ';');
|
||||
to_esc(color.g, buffer + 11, ';');
|
||||
to_esc(color.b, buffer + 15, 'm');
|
||||
buffer[19] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
|
||||
uint8_t em_codes[num_emphases] = {};
|
||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
||||
if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
|
||||
if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
|
||||
if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
|
||||
if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
|
||||
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
|
||||
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
|
||||
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < num_emphases; ++i) {
|
||||
if (!em_codes[i]) continue;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
|
||||
buffer[index++] = static_cast<Char>('m');
|
||||
}
|
||||
buffer[index++] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
|
||||
|
||||
FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; }
|
||||
FMT_CONSTEXPR20 auto end() const noexcept -> const Char* {
|
||||
return buffer + basic_string_view<Char>(buffer).size();
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t num_emphases = 8;
|
||||
Char buffer[7u + 3u * num_emphases + 1u];
|
||||
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||
char delimiter) noexcept {
|
||||
out[0] = static_cast<Char>('0' + c / 100);
|
||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||
out[2] = static_cast<Char>('0' + c % 10);
|
||||
out[3] = static_cast<Char>(delimiter);
|
||||
}
|
||||
static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept
|
||||
-> bool {
|
||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto make_foreground_color(color_type foreground) noexcept
|
||||
-> ansi_color_escape<Char> {
|
||||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto make_background_color(color_type background) noexcept
|
||||
-> ansi_color_escape<Char> {
|
||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept
|
||||
-> ansi_color_escape<Char> {
|
||||
return ansi_color_escape<Char>(em);
|
||||
}
|
||||
|
||||
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
buffer.append(reset_color.begin(), reset_color.end());
|
||||
}
|
||||
|
||||
template <typename T> struct styled_arg : view {
|
||||
const T& value;
|
||||
text_style style;
|
||||
styled_arg(const T& v, text_style s) : value(v), style(s) {}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||
basic_string_view<Char> fmt,
|
||||
basic_format_args<buffered_context<Char>> args) {
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
auto emphasis = make_emphasis<Char>(ts.get_emphasis());
|
||||
buf.append(emphasis.begin(), emphasis.end());
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
auto foreground = make_foreground_color<Char>(ts.get_foreground());
|
||||
buf.append(foreground.begin(), foreground.end());
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
has_style = true;
|
||||
auto background = make_background_color<Char>(ts.get_background());
|
||||
buf.append(background.begin(), background.end());
|
||||
}
|
||||
vformat_to(buf, fmt, args);
|
||||
if (has_style) reset_color<Char>(buf);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline void vprint(FILE* f, const text_style& ts, string_view fmt,
|
||||
format_args args) {
|
||||
auto buf = memory_buffer();
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string and prints it to the specified file stream using ANSI
|
||||
* escape sequences to specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
void print(FILE* f, const text_style& ts, format_string<T...> fmt,
|
||||
T&&... args) {
|
||||
vprint(f, ts, fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string and prints it to stdout using ANSI escape sequences to
|
||||
* specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
void print(const text_style& ts, format_string<T...> fmt, T&&... args) {
|
||||
return print(stdout, ts, fmt, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
inline auto vformat(const text_style& ts, string_view fmt, format_args args)
|
||||
-> std::string {
|
||||
auto buf = memory_buffer();
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
return fmt::to_string(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats arguments and returns the result as a string using ANSI escape
|
||||
* sequences to specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* ```
|
||||
* #include <fmt/color.h>
|
||||
* std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "The answer is {}", 42);
|
||||
* ```
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto format(const text_style& ts, format_string<T...> fmt, T&&... args)
|
||||
-> std::string {
|
||||
return fmt::vformat(ts, fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
/// Formats a string with the given text_style and writes the output to `out`.
|
||||
template <typename OutputIt,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
|
||||
auto vformat_to(OutputIt out, const text_style& ts, string_view fmt,
|
||||
format_args args) -> OutputIt {
|
||||
auto&& buf = detail::get_buffer<char>(out);
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
return detail::get_iterator(buf, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats arguments with the given text style, writes the result to the output
|
||||
* iterator `out` and returns the iterator past the end of the output range.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* std::vector<char> out;
|
||||
* fmt::format_to(std::back_inserter(out),
|
||||
* fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
|
||||
*/
|
||||
template <typename OutputIt, typename... T,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
|
||||
inline auto format_to(OutputIt out, const text_style& ts,
|
||||
format_string<T...> fmt, T&&... args) -> OutputIt {
|
||||
return vformat_to(out, ts, fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
const auto& ts = arg.style;
|
||||
auto out = ctx.out();
|
||||
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||
out = detail::copy<Char>(emphasis.begin(), emphasis.end(), out);
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
auto foreground =
|
||||
detail::make_foreground_color<Char>(ts.get_foreground());
|
||||
out = detail::copy<Char>(foreground.begin(), foreground.end(), out);
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
has_style = true;
|
||||
auto background =
|
||||
detail::make_background_color<Char>(ts.get_background());
|
||||
out = detail::copy<Char>(background.begin(), background.end(), out);
|
||||
}
|
||||
out = formatter<T, Char>::format(arg.value, ctx);
|
||||
if (has_style) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
out = detail::copy<Char>(reset_color.begin(), reset_color.end(), out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an argument that will be formatted using ANSI escape sequences,
|
||||
* to be used in a formatting function.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print("Elapsed time: {0:.2f} seconds",
|
||||
* fmt::styled(1.23, fmt::fg(fmt::color::green) |
|
||||
* fmt::bg(fmt::color::blue)));
|
||||
*/
|
||||
template <typename T>
|
||||
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
|
||||
-> detail::styled_arg<remove_cvref_t<T>> {
|
||||
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COLOR_H_
|
||||
551
include/fmt/compile.h
Normal file
551
include/fmt/compile.h
Normal file
@@ -0,0 +1,551 @@
|
||||
// Formatting library for C++ - experimental format string compilation
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_COMPILE_H_
|
||||
#define FMT_COMPILE_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <iterator> // std::back_inserter
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
// A compile-time string which is compiled into fast formatting code.
|
||||
FMT_EXPORT class compiled_string {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename S>
|
||||
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||
|
||||
/**
|
||||
* Converts a string literal `s` into a format string that will be parsed at
|
||||
* compile time and converted into efficient formatting code. Requires C++17
|
||||
* `constexpr if` compiler support.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // Converts 42 into std::string using the most efficient method and no
|
||||
* // runtime format string processing.
|
||||
* std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||
*/
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string)
|
||||
#else
|
||||
# define FMT_COMPILE(s) FMT_STRING(s)
|
||||
#endif
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
template <typename Char, size_t N, fmt::detail::fixed_string<Char, N> Str>
|
||||
struct udl_compiled_string : compiled_string {
|
||||
using char_type = Char;
|
||||
constexpr explicit operator basic_string_view<char_type>() const {
|
||||
return {Str.data, N - 1};
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, typename... Tail>
|
||||
auto first(const T& value, const Tail&...) -> const T& {
|
||||
return value;
|
||||
}
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
template <typename... Args> struct type_list {};
|
||||
|
||||
// Returns a reference to the argument at index N from [first, rest...].
|
||||
template <int N, typename T, typename... Args>
|
||||
constexpr const auto& get([[maybe_unused]] const T& first,
|
||||
[[maybe_unused]] const Args&... rest) {
|
||||
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||
if constexpr (N == 0)
|
||||
return first;
|
||||
else
|
||||
return detail::get<N - 1>(rest...);
|
||||
}
|
||||
|
||||
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
template <int N, typename T, typename... Args, typename Char>
|
||||
constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||
if constexpr (is_static_named_arg<T>()) {
|
||||
if (name == T::name) return N;
|
||||
}
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
return get_arg_index_by_name<N + 1, Args...>(name);
|
||||
(void)name; // Workaround an MSVC bug about "unused" parameter.
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
template <typename... Args, typename Char>
|
||||
FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
return get_arg_index_by_name<0, Args...>(name);
|
||||
# endif
|
||||
(void)name;
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename Char, typename... Args>
|
||||
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
|
||||
type_list<Args...>) {
|
||||
return get_arg_index_by_name<Args...>(name);
|
||||
}
|
||||
|
||||
template <int N, typename> struct get_type_impl;
|
||||
|
||||
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||
using type =
|
||||
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
|
||||
};
|
||||
|
||||
template <int N, typename T>
|
||||
using get_type = typename get_type_impl<N, T>::type;
|
||||
|
||||
template <typename T> struct is_compiled_format : std::false_type {};
|
||||
|
||||
template <typename Char> struct text {
|
||||
basic_string_view<Char> data;
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
||||
return write<Char>(out, data);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<text<Char>> : std::true_type {};
|
||||
|
||||
template <typename Char>
|
||||
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
|
||||
size_t size) {
|
||||
return {{&s[pos], size}};
|
||||
}
|
||||
|
||||
template <typename Char> struct code_unit {
|
||||
Char value;
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
||||
*out++ = value;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// This ensures that the argument type is convertible to `const T&`.
|
||||
template <typename T, int N, typename... Args>
|
||||
constexpr const T& get_arg_checked(const Args&... args) {
|
||||
const auto& arg = detail::get<N>(args...);
|
||||
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
||||
return arg.value;
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<code_unit<Char>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument N.
|
||||
template <typename Char, typename T, int N> struct field {
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
const T& arg = get_arg_checked<T, N>(args...);
|
||||
if constexpr (std::is_convertible<T, basic_string_view<Char>>::value) {
|
||||
auto s = basic_string_view<Char>(arg);
|
||||
return copy<Char>(s.begin(), s.end(), out);
|
||||
} else {
|
||||
return write<Char>(out, arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename T, int N>
|
||||
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument with name.
|
||||
template <typename Char> struct runtime_named_field {
|
||||
using char_type = Char;
|
||||
basic_string_view<Char> name;
|
||||
|
||||
template <typename OutputIt, typename T>
|
||||
constexpr static bool try_format_argument(
|
||||
OutputIt& out,
|
||||
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
|
||||
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
|
||||
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
|
||||
if (arg_name == arg.name) {
|
||||
out = write<Char>(out, arg.value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
bool found = (try_format_argument(out, name, args) || ...);
|
||||
if (!found) {
|
||||
FMT_THROW(format_error("argument with specified name is not found"));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument N and has format specifiers.
|
||||
template <typename Char, typename T, int N> struct spec_field {
|
||||
using char_type = Char;
|
||||
formatter<T, Char> fmt;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr FMT_INLINE OutputIt format(OutputIt out,
|
||||
const Args&... args) const {
|
||||
const auto& vargs =
|
||||
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
|
||||
basic_format_context<OutputIt, Char> ctx(out, vargs);
|
||||
return fmt.format(get_arg_checked<T, N>(args...), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename T, int N>
|
||||
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
|
||||
|
||||
template <typename L, typename R> struct concat {
|
||||
L lhs;
|
||||
R rhs;
|
||||
using char_type = typename L::char_type;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
out = lhs.format(out, args...);
|
||||
return rhs.format(out, args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct is_compiled_format<concat<L, R>> : std::true_type {};
|
||||
|
||||
template <typename L, typename R>
|
||||
constexpr concat<L, R> make_concat(L lhs, R rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
struct unknown_format {};
|
||||
|
||||
template <typename Char>
|
||||
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
|
||||
for (size_t size = str.size(); pos != size; ++pos) {
|
||||
if (str[pos] == '{' || str[pos] == '}') break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
template <typename Args, size_t POS, int ID, typename S>
|
||||
constexpr auto compile_format_string(S fmt);
|
||||
|
||||
template <typename Args, size_t POS, int ID, typename T, typename S>
|
||||
constexpr auto parse_tail(T head, S fmt) {
|
||||
if constexpr (POS != basic_string_view<typename S::char_type>(fmt).size()) {
|
||||
constexpr auto tail = compile_format_string<Args, POS, ID>(fmt);
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
|
||||
unknown_format>())
|
||||
return tail;
|
||||
else
|
||||
return make_concat(head, tail);
|
||||
} else {
|
||||
return head;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Char> struct parse_specs_result {
|
||||
formatter<T, Char> fmt;
|
||||
size_t end;
|
||||
int next_arg_id;
|
||||
};
|
||||
|
||||
enum { manual_indexing_id = -1 };
|
||||
|
||||
template <typename T, typename Char>
|
||||
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||
size_t pos, int next_arg_id) {
|
||||
str.remove_prefix(pos);
|
||||
auto ctx =
|
||||
compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
|
||||
auto f = formatter<T, Char>();
|
||||
auto end = f.parse(ctx);
|
||||
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
|
||||
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
|
||||
}
|
||||
|
||||
template <typename Char> struct arg_id_handler {
|
||||
arg_id_kind kind;
|
||||
arg_ref<Char> arg_id;
|
||||
|
||||
constexpr int on_auto() {
|
||||
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
||||
return 0;
|
||||
}
|
||||
constexpr int on_index(int id) {
|
||||
kind = arg_id_kind::index;
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
}
|
||||
constexpr int on_name(basic_string_view<Char> id) {
|
||||
kind = arg_id_kind::name;
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char> struct parse_arg_id_result {
|
||||
arg_id_kind kind;
|
||||
arg_ref<Char> arg_id;
|
||||
const Char* arg_id_end;
|
||||
};
|
||||
|
||||
template <int ID, typename Char>
|
||||
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
||||
auto handler = arg_id_handler<Char>{arg_id_kind::none, arg_ref<Char>{}};
|
||||
auto arg_id_end = parse_arg_id(begin, end, handler);
|
||||
return parse_arg_id_result<Char>{handler.kind, handler.arg_id, arg_id_end};
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void> struct field_type {
|
||||
using type = remove_cvref_t<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
|
||||
using type = remove_cvref_t<decltype(T::value)>;
|
||||
};
|
||||
|
||||
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
|
||||
typename S>
|
||||
constexpr auto parse_replacement_field_then_tail(S fmt) {
|
||||
using char_type = typename S::char_type;
|
||||
constexpr auto str = basic_string_view<char_type>(fmt);
|
||||
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
|
||||
if constexpr (c == '}') {
|
||||
return parse_tail<Args, END_POS + 1, NEXT_ID>(
|
||||
field<char_type, typename field_type<T>::type, ARG_INDEX>(), fmt);
|
||||
} else if constexpr (c != ':') {
|
||||
FMT_THROW(format_error("expected ':'"));
|
||||
} else {
|
||||
constexpr auto result = parse_specs<typename field_type<T>::type>(
|
||||
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
|
||||
if constexpr (result.end >= str.size() || str[result.end] != '}') {
|
||||
FMT_THROW(format_error("expected '}'"));
|
||||
return 0;
|
||||
} else {
|
||||
return parse_tail<Args, result.end + 1, result.next_arg_id>(
|
||||
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
|
||||
result.fmt},
|
||||
fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compiles a non-empty format string and returns the compiled representation
|
||||
// or unknown_format() on unrecognized input.
|
||||
template <typename Args, size_t POS, int ID, typename S>
|
||||
constexpr auto compile_format_string(S fmt) {
|
||||
using char_type = typename S::char_type;
|
||||
constexpr auto str = basic_string_view<char_type>(fmt);
|
||||
if constexpr (str[POS] == '{') {
|
||||
if constexpr (POS + 1 == str.size())
|
||||
FMT_THROW(format_error("unmatched '{' in format string"));
|
||||
if constexpr (str[POS + 1] == '{') {
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt);
|
||||
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
|
||||
static_assert(ID != manual_indexing_id,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
constexpr auto next_id =
|
||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||
return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
|
||||
POS + 1, ID, next_id>(fmt);
|
||||
} else {
|
||||
constexpr auto arg_id_result =
|
||||
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
|
||||
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
|
||||
constexpr char_type c =
|
||||
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
|
||||
static_assert(c == '}' || c == ':', "missing '}' in format string");
|
||||
if constexpr (arg_id_result.kind == arg_id_kind::index) {
|
||||
static_assert(
|
||||
ID == manual_indexing_id || ID == 0,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
constexpr auto arg_index = arg_id_result.arg_id.index;
|
||||
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
|
||||
Args, arg_id_end_pos,
|
||||
arg_index, manual_indexing_id>(
|
||||
fmt);
|
||||
} else if constexpr (arg_id_result.kind == arg_id_kind::name) {
|
||||
constexpr auto arg_index =
|
||||
get_arg_index_by_name(arg_id_result.arg_id.name, Args{});
|
||||
if constexpr (arg_index >= 0) {
|
||||
constexpr auto next_id =
|
||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||
return parse_replacement_field_then_tail<
|
||||
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
|
||||
arg_index, next_id>(fmt);
|
||||
} else if constexpr (c == '}') {
|
||||
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
||||
runtime_named_field<char_type>{arg_id_result.arg_id.name}, fmt);
|
||||
} else if constexpr (c == ':') {
|
||||
return unknown_format(); // no type info for specs parsing
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if constexpr (str[POS] == '}') {
|
||||
if constexpr (POS + 1 == str.size())
|
||||
FMT_THROW(format_error("unmatched '}' in format string"));
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt);
|
||||
} else {
|
||||
constexpr auto end = parse_text(str, POS + 1);
|
||||
if constexpr (end - POS > 1) {
|
||||
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), fmt);
|
||||
} else {
|
||||
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args, typename S,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
constexpr auto compile(S fmt) {
|
||||
constexpr auto str = basic_string_view<typename S::char_type>(fmt);
|
||||
if constexpr (str.size() == 0) {
|
||||
return detail::make_text(str, 0, 0);
|
||||
} else {
|
||||
constexpr auto result =
|
||||
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(fmt);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
} // namespace detail
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
|
||||
template <typename CompiledFormat, typename... Args,
|
||||
typename Char = typename CompiledFormat::char_type,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
auto s = std::basic_string<Char>();
|
||||
cf.format(std::back_inserter(s), args...);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
return cf.format(out, args...);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
Args&&... args) {
|
||||
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||
constexpr auto str = basic_string_view<typename S::char_type>(S());
|
||||
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
|
||||
const auto& first = detail::first(args...);
|
||||
if constexpr (detail::is_named_arg<
|
||||
remove_cvref_t<decltype(first)>>::value) {
|
||||
return fmt::to_string(first.value);
|
||||
} else {
|
||||
return fmt::to_string(first);
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return fmt::format(
|
||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return fmt::format(compiled, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return fmt::format_to(
|
||||
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
using traits = detail::fixed_buffer_traits;
|
||||
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
|
||||
fmt::format_to(std::back_inserter(buf), fmt, std::forward<Args>(args)...);
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args)
|
||||
-> size_t {
|
||||
auto buf = detail::counting_buffer<>();
|
||||
fmt::format_to(appender(buf), fmt, args...);
|
||||
return buf.count();
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
void print(std::FILE* f, const S& fmt, const Args&... args) {
|
||||
auto buf = memory_buffer();
|
||||
fmt::format_to(appender(buf), fmt, args...);
|
||||
detail::print(f, {buf.data(), buf.size()});
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
void print(const S& fmt, const Args&... args) {
|
||||
print(stdout, fmt, args...);
|
||||
}
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
inline namespace literals {
|
||||
template <detail::fixed_string Str> constexpr auto operator""_cf() {
|
||||
using char_t = remove_cvref_t<decltype(Str.data[0])>;
|
||||
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
|
||||
Str>();
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COMPILE_H_
|
||||
5
include/fmt/core.h
Normal file
5
include/fmt/core.h
Normal file
@@ -0,0 +1,5 @@
|
||||
// This file is only provided for compatibility and may be removed in future
|
||||
// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h
|
||||
// otherwise.
|
||||
|
||||
#include "format.h"
|
||||
1949
include/fmt/format-inl.h
Normal file
1949
include/fmt/format-inl.h
Normal file
File diff suppressed because it is too large
Load Diff
4234
include/fmt/format.h
Normal file
4234
include/fmt/format.h
Normal file
File diff suppressed because it is too large
Load Diff
427
include/fmt/os.h
Normal file
427
include/fmt/os.h
Normal file
@@ -0,0 +1,427 @@
|
||||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OS_H_
|
||||
#define FMT_OS_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <cerrno>
|
||||
# include <cstddef>
|
||||
# include <cstdio>
|
||||
# include <system_error> // std::system_error
|
||||
|
||||
# if FMT_HAS_INCLUDE(<xlocale.h>)
|
||||
# include <xlocale.h> // LC_NUMERIC_MASK on macOS
|
||||
# endif
|
||||
#endif // FMT_MODULE
|
||||
|
||||
#ifndef FMT_USE_FCNTL
|
||||
// UWP doesn't provide _pipe.
|
||||
# if FMT_HAS_INCLUDE("winapifamily.h")
|
||||
# include <winapifamily.h>
|
||||
# endif
|
||||
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
(!defined(WINAPI_FAMILY) || \
|
||||
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||
# include <fcntl.h> // for O_RDONLY
|
||||
# define FMT_USE_FCNTL 1
|
||||
# else
|
||||
# define FMT_USE_FCNTL 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FMT_POSIX
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX(call) _##call
|
||||
# else
|
||||
# define FMT_POSIX(call) call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
||||
#ifdef FMT_SYSTEM
|
||||
# define FMT_HAS_SYSTEM
|
||||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
||||
#else
|
||||
# define FMT_SYSTEM(call) ::call
|
||||
# ifdef _WIN32
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX_CALL(call) ::_##call
|
||||
# else
|
||||
# define FMT_POSIX_CALL(call) ::call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Retries the expression while it evaluates to error_result and errno
|
||||
// equals to EINTR.
|
||||
#ifndef _WIN32
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||
do { \
|
||||
(result) = (expression); \
|
||||
} while ((result) == (error_result) && errno == EINTR)
|
||||
#else
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||
#endif
|
||||
|
||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
/**
|
||||
* A reference to a null-terminated string. It can be constructed from a C
|
||||
* string or `std::string`.
|
||||
*
|
||||
* You can use one of the following type aliases for common character types:
|
||||
*
|
||||
* +---------------+-----------------------------+
|
||||
* | Type | Definition |
|
||||
* +===============+=============================+
|
||||
* | cstring_view | basic_cstring_view<char> |
|
||||
* +---------------+-----------------------------+
|
||||
* | wcstring_view | basic_cstring_view<wchar_t> |
|
||||
* +---------------+-----------------------------+
|
||||
*
|
||||
* This class is most useful as a parameter type for functions that wrap C APIs.
|
||||
*/
|
||||
template <typename Char> class basic_cstring_view {
|
||||
private:
|
||||
const Char* data_;
|
||||
|
||||
public:
|
||||
/// Constructs a string reference object from a C string.
|
||||
basic_cstring_view(const Char* s) : data_(s) {}
|
||||
|
||||
/// Constructs a string reference from an `std::string` object.
|
||||
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
|
||||
|
||||
/// Returns the pointer to a C string.
|
||||
auto c_str() const -> const Char* { return data_; }
|
||||
};
|
||||
|
||||
using cstring_view = basic_cstring_view<char>;
|
||||
using wcstring_view = basic_cstring_view<wchar_t>;
|
||||
|
||||
#ifdef _WIN32
|
||||
FMT_API const std::error_category& system_category() noexcept;
|
||||
|
||||
namespace detail {
|
||||
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||
const char* message) noexcept;
|
||||
}
|
||||
|
||||
FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
|
||||
format_args args);
|
||||
|
||||
/**
|
||||
* Constructs a `std::system_error` object with the description of the form
|
||||
*
|
||||
* <message>: <system-message>
|
||||
*
|
||||
* where `<message>` is the formatted message and `<system-message>` is the
|
||||
* system message corresponding to the error code.
|
||||
* `error_code` is a Windows error code as given by `GetLastError`.
|
||||
* If `error_code` is not a valid error code such as -1, the system message
|
||||
* will look like "error -1".
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // This throws a system_error with the description
|
||||
* // cannot open file 'madeup': The system cannot find the file
|
||||
* specified.
|
||||
* // or similar (system message may vary).
|
||||
* const char *filename = "madeup";
|
||||
* LPOFSTRUCT of = LPOFSTRUCT();
|
||||
* HFILE file = OpenFile(filename, &of, OF_READ);
|
||||
* if (file == HFILE_ERROR) {
|
||||
* throw fmt::windows_error(GetLastError(),
|
||||
* "cannot open file '{}'", filename);
|
||||
* }
|
||||
*/
|
||||
template <typename... T>
|
||||
auto windows_error(int error_code, string_view message, const T&... args)
|
||||
-> std::system_error {
|
||||
return vwindows_error(error_code, message, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
// Reports a Windows error without throwing an exception.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
||||
#else
|
||||
inline auto system_category() noexcept -> const std::error_category& {
|
||||
return std::system_category();
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// std::system is not available on some platforms such as iOS (#2248).
|
||||
#ifdef __OSX__
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
void say(const S& fmt, Args&&... args) {
|
||||
std::system(format("say \"{}\"", format(fmt, args...)).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
// A buffered file.
|
||||
class buffered_file {
|
||||
private:
|
||||
FILE* file_;
|
||||
|
||||
friend class file;
|
||||
|
||||
inline explicit buffered_file(FILE* f) : file_(f) {}
|
||||
|
||||
public:
|
||||
buffered_file(const buffered_file&) = delete;
|
||||
void operator=(const buffered_file&) = delete;
|
||||
|
||||
// Constructs a buffered_file object which doesn't represent any file.
|
||||
inline buffered_file() noexcept : file_(nullptr) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~buffered_file() noexcept;
|
||||
|
||||
public:
|
||||
inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
|
||||
inline auto operator=(buffered_file&& other) -> buffered_file& {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Opens a file.
|
||||
FMT_API buffered_file(cstring_view filename, cstring_view mode);
|
||||
|
||||
// Closes the file.
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the pointer to a FILE object representing this file.
|
||||
inline auto get() const noexcept -> FILE* { return file_; }
|
||||
|
||||
FMT_API auto descriptor() const -> int;
|
||||
|
||||
template <typename... T>
|
||||
inline void print(string_view fmt, const T&... args) {
|
||||
fmt::vargs<T...> vargs = {{args...}};
|
||||
detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs)
|
||||
: fmt::vprint(file_, fmt, vargs);
|
||||
}
|
||||
};
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
|
||||
// A file. Closed file is represented by a file object with descriptor -1.
|
||||
// Methods that are not declared with noexcept may throw
|
||||
// fmt::system_error in case of failure. Note that some errors such as
|
||||
// closing the file multiple times will cause a crash on Windows rather
|
||||
// than an exception. You can get standard behavior by overriding the
|
||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||
class FMT_API file {
|
||||
private:
|
||||
int fd_; // File descriptor.
|
||||
|
||||
// Constructs a file object with a given descriptor.
|
||||
explicit file(int fd) : fd_(fd) {}
|
||||
|
||||
friend struct pipe;
|
||||
|
||||
public:
|
||||
// Possible values for the oflag argument to the constructor.
|
||||
enum {
|
||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
||||
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
||||
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
|
||||
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
|
||||
};
|
||||
|
||||
// Constructs a file object which doesn't represent any file.
|
||||
inline file() noexcept : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a file object representing this file.
|
||||
file(cstring_view path, int oflag);
|
||||
|
||||
public:
|
||||
file(const file&) = delete;
|
||||
void operator=(const file&) = delete;
|
||||
|
||||
inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
|
||||
|
||||
// Move assignment is not noexcept because close may throw.
|
||||
inline auto operator=(file&& other) -> file& {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~file() noexcept;
|
||||
|
||||
// Returns the file descriptor.
|
||||
inline auto descriptor() const noexcept -> int { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
|
||||
// Returns the file size. The size has signed type for consistency with
|
||||
// stat::st_size.
|
||||
auto size() const -> long long;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
auto read(void* buffer, size_t count) -> size_t;
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
auto write(const void* buffer, size_t count) -> size_t;
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
static auto dup(int fd) -> file;
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd, std::error_code& ec) noexcept;
|
||||
|
||||
// Creates a buffered_file object associated with this file and detaches
|
||||
// this file object from the file.
|
||||
auto fdopen(const char* mode) -> buffered_file;
|
||||
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// Opens a file and constructs a file object representing this file by
|
||||
// wcstring_view filename. Windows only.
|
||||
static file open_windows_file(wcstring_view path, int oflag);
|
||||
# endif
|
||||
};
|
||||
|
||||
struct FMT_API pipe {
|
||||
file read_end;
|
||||
file write_end;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
pipe();
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
auto getpagesize() -> long;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct buffer_size {
|
||||
constexpr buffer_size() = default;
|
||||
size_t value = 0;
|
||||
FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size {
|
||||
auto bs = buffer_size();
|
||||
bs.value = val;
|
||||
return bs;
|
||||
}
|
||||
};
|
||||
|
||||
struct ostream_params {
|
||||
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
|
||||
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
||||
|
||||
constexpr ostream_params() {}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
|
||||
oflag = new_oflag;
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, detail::buffer_size bs)
|
||||
: ostream_params(params...) {
|
||||
this->buffer_size = bs.value;
|
||||
}
|
||||
|
||||
// Intel has a bug that results in failure to deduce a constructor
|
||||
// for empty parameter packs.
|
||||
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
|
||||
ostream_params(int new_oflag) : oflag(new_oflag) {}
|
||||
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
|
||||
# endif
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size();
|
||||
|
||||
/// A fast buffered output stream for writing from a single thread. Writing from
|
||||
/// multiple threads without external synchronization may result in a data race.
|
||||
class FMT_API ostream : private detail::buffer<char> {
|
||||
private:
|
||||
file file_;
|
||||
|
||||
ostream(cstring_view path, const detail::ostream_params& params);
|
||||
|
||||
static void grow(buffer<char>& buf, size_t);
|
||||
|
||||
public:
|
||||
ostream(ostream&& other) noexcept;
|
||||
~ostream();
|
||||
|
||||
operator writer() {
|
||||
detail::buffer<char>& buf = *this;
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline void flush() {
|
||||
if (size() == 0) return;
|
||||
file_.write(data(), size() * sizeof(data()[0]));
|
||||
clear();
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
friend auto output_file(cstring_view path, T... params) -> ostream;
|
||||
|
||||
inline void close() {
|
||||
flush();
|
||||
file_.close();
|
||||
}
|
||||
|
||||
/// Formats `args` according to specifications in `fmt` and writes the
|
||||
/// output to the file.
|
||||
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
|
||||
vformat_to(appender(*this), fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens a file for writing. Supported parameters passed in `params`:
|
||||
*
|
||||
* - `<integer>`: Flags passed to [open](
|
||||
* https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html)
|
||||
* (`file::WRONLY | file::CREATE | file::TRUNC` by default)
|
||||
* - `buffer_size=<integer>`: Output buffer size
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* auto out = fmt::output_file("guide.txt");
|
||||
* out.print("Don't {}", "Panic");
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto output_file(cstring_view path, T... params) -> ostream {
|
||||
return {path, detail::ostream_params(params...)};
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OS_H_
|
||||
166
include/fmt/ostream.h
Normal file
166
include/fmt/ostream.h
Normal file
@@ -0,0 +1,166 @@
|
||||
// Formatting library for C++ - std::ostream support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OSTREAM_H_
|
||||
#define FMT_OSTREAM_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <fstream> // std::filebuf
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef __GLIBCXX__
|
||||
# include <ext/stdio_filebuf.h>
|
||||
# include <ext/stdio_sync_filebuf.h>
|
||||
# endif
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "chrono.h" // formatbuf
|
||||
|
||||
#ifdef _MSVC_STL_UPDATE
|
||||
# define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5
|
||||
# define FMT_MSVC_STL_UPDATE _MSVC_LANG
|
||||
#else
|
||||
# define FMT_MSVC_STL_UPDATE 0
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
// Generate a unique explicit instantion in every translation unit using a tag
|
||||
// type in an anonymous namespace.
|
||||
namespace {
|
||||
struct file_access_tag {};
|
||||
} // namespace
|
||||
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
|
||||
class file_access {
|
||||
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
|
||||
};
|
||||
|
||||
#if FMT_MSVC_STL_UPDATE
|
||||
template class file_access<file_access_tag, std::filebuf,
|
||||
&std::filebuf::_Myfile>;
|
||||
auto get_file(std::filebuf&) -> FILE*;
|
||||
#endif
|
||||
|
||||
// Write the content of buf to os.
|
||||
// It is a separate function rather than a part of vprint to simplify testing.
|
||||
template <typename Char>
|
||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||
const Char* buf_data = buf.data();
|
||||
using unsigned_streamsize = make_unsigned_t<std::streamsize>;
|
||||
unsigned_streamsize size = buf.size();
|
||||
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
|
||||
do {
|
||||
unsigned_streamsize n = size <= max_size ? size : max_size;
|
||||
os.write(buf_data, static_cast<std::streamsize>(n));
|
||||
buf_data += n;
|
||||
size -= n;
|
||||
} while (size != 0);
|
||||
}
|
||||
|
||||
template <typename T> struct streamed_view {
|
||||
const T& value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename Char>
|
||||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||
void set_debug_format() = delete;
|
||||
|
||||
template <typename T, typename Context>
|
||||
auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer);
|
||||
auto&& output = std::basic_ostream<Char>(&formatbuf);
|
||||
output.imbue(std::locale::classic()); // The default is always unlocalized.
|
||||
output << value;
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
return formatter<basic_string_view<Char>, Char>::format(
|
||||
{buffer.data(), buffer.size()}, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
using ostream_formatter = basic_ostream_formatter<char>;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::streamed_view<T>, Char>
|
||||
: basic_ostream_formatter<Char> {
|
||||
template <typename Context>
|
||||
auto format(detail::streamed_view<T> view, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return basic_ostream_formatter<Char>::format(view.value, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a view that formats `value` via an ostream `operator<<`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print("Current thread id: {}\n",
|
||||
* fmt::streamed(std::this_thread::get_id()));
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
|
||||
return {value};
|
||||
}
|
||||
|
||||
inline void vprint(std::ostream& os, string_view fmt, format_args args) {
|
||||
auto buffer = memory_buffer();
|
||||
detail::vformat_to(buffer, fmt, args);
|
||||
FILE* f = nullptr;
|
||||
#if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI
|
||||
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
|
||||
f = detail::get_file(*buf);
|
||||
#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI
|
||||
auto* rdbuf = os.rdbuf();
|
||||
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
|
||||
f = sfbuf->file();
|
||||
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
|
||||
f = fbuf->file();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (f) {
|
||||
int fd = _fileno(f);
|
||||
if (_isatty(fd)) {
|
||||
os.flush();
|
||||
if (detail::write_console(fd, {buffer.data(), buffer.size()})) return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
detail::ignore_unused(f);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints formatted data to the stream `os`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print(cerr, "Don't {}!", "panic");
|
||||
*/
|
||||
FMT_EXPORT template <typename... T>
|
||||
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||
fmt::vargs<T...> vargs = {{args...}};
|
||||
if (detail::const_check(detail::use_utf8)) return vprint(os, fmt.str, vargs);
|
||||
auto buffer = memory_buffer();
|
||||
detail::vformat_to(buffer, fmt.str, vargs);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
FMT_EXPORT template <typename... T>
|
||||
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OSTREAM_H_
|
||||
633
include/fmt/printf.h
Normal file
633
include/fmt/printf.h
Normal file
@@ -0,0 +1,633 @@
|
||||
// Formatting library for C++ - legacy printf implementation
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_PRINTF_H_
|
||||
#define FMT_PRINTF_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <algorithm> // std::max
|
||||
# include <limits> // std::numeric_limits
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
template <typename T> struct printf_formatter {
|
||||
printf_formatter() = delete;
|
||||
};
|
||||
|
||||
template <typename Char> class basic_printf_context {
|
||||
private:
|
||||
basic_appender<Char> out_;
|
||||
basic_format_args<basic_printf_context> args_;
|
||||
|
||||
static_assert(std::is_same<Char, char>::value ||
|
||||
std::is_same<Char, wchar_t>::value,
|
||||
"Unsupported code unit type.");
|
||||
|
||||
public:
|
||||
using char_type = Char;
|
||||
using parse_context_type = parse_context<Char>;
|
||||
template <typename T> using formatter_type = printf_formatter<T>;
|
||||
enum { builtin_types = 1 };
|
||||
|
||||
/// Constructs a `printf_context` object. References to the arguments are
|
||||
/// stored in the context object so make sure they have appropriate lifetimes.
|
||||
basic_printf_context(basic_appender<Char> out,
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: out_(out), args_(args) {}
|
||||
|
||||
auto out() -> basic_appender<Char> { return out_; }
|
||||
void advance_to(basic_appender<Char>) {}
|
||||
|
||||
auto locale() -> detail::locale_ref { return {}; }
|
||||
|
||||
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
|
||||
return args_.get(id);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Return the result via the out param to workaround gcc bug 77539.
|
||||
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
|
||||
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
|
||||
for (out = first; out != last; ++out) {
|
||||
if (*out == value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline auto find<false, char>(const char* first, const char* last, char value,
|
||||
const char*& out) -> bool {
|
||||
out =
|
||||
static_cast<const char*>(memchr(first, value, to_unsigned(last - first)));
|
||||
return out != nullptr;
|
||||
}
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IsSigned> struct int_checker {
|
||||
template <typename T> static auto fits_in_int(T value) -> bool {
|
||||
unsigned max = to_unsigned(max_value<int>());
|
||||
return value <= max;
|
||||
}
|
||||
inline static auto fits_in_int(bool) -> bool { return true; }
|
||||
};
|
||||
|
||||
template <> struct int_checker<true> {
|
||||
template <typename T> static auto fits_in_int(T value) -> bool {
|
||||
return value >= (std::numeric_limits<int>::min)() &&
|
||||
value <= max_value<int>();
|
||||
}
|
||||
inline static auto fits_in_int(int) -> bool { return true; }
|
||||
};
|
||||
|
||||
struct printf_precision_handler {
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
auto operator()(T value) -> int {
|
||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
report_error("number is too big");
|
||||
return (std::max)(static_cast<int>(value), 0);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
auto operator()(T) -> int {
|
||||
report_error("precision is not integer");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// An argument visitor that returns true iff arg is a zero integer.
|
||||
struct is_zero_int {
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
auto operator()(T value) -> bool {
|
||||
return value == 0;
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
auto operator()(T) -> bool {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
|
||||
|
||||
template <> struct make_unsigned_or_bool<bool> {
|
||||
using type = bool;
|
||||
};
|
||||
|
||||
template <typename T, typename Context> class arg_converter {
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
basic_format_arg<Context>& arg_;
|
||||
char_type type_;
|
||||
|
||||
public:
|
||||
arg_converter(basic_format_arg<Context>& arg, char_type type)
|
||||
: arg_(arg), type_(type) {}
|
||||
|
||||
void operator()(bool value) {
|
||||
if (type_ != 's') operator()<bool>(value);
|
||||
}
|
||||
|
||||
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
|
||||
void operator()(U value) {
|
||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||
using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
|
||||
if (const_check(sizeof(target_type) <= sizeof(int))) {
|
||||
// Extra casts are used to silence warnings.
|
||||
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
|
||||
if (is_signed)
|
||||
arg_ = static_cast<int>(static_cast<target_type>(value));
|
||||
else
|
||||
arg_ = static_cast<unsigned>(static_cast<unsigned_type>(value));
|
||||
} else {
|
||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||
// std::printf("%lld", -42); // prints "4294967254"
|
||||
// but we don't have to do the same because it's a UB.
|
||||
if (is_signed)
|
||||
arg_ = static_cast<long long>(value);
|
||||
else
|
||||
arg_ = static_cast<typename make_unsigned_or_bool<U>::type>(value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)>
|
||||
void operator()(U) {} // No conversion needed for non-integral types.
|
||||
};
|
||||
|
||||
// Converts an integer argument to T for printf, if T is an integral type.
|
||||
// If T is void, the argument is converted to corresponding signed or unsigned
|
||||
// type depending on the type specifier: 'd' and 'i' - signed, other -
|
||||
// unsigned).
|
||||
template <typename T, typename Context, typename Char>
|
||||
void convert_arg(basic_format_arg<Context>& arg, Char type) {
|
||||
arg.visit(arg_converter<T, Context>(arg, type));
|
||||
}
|
||||
|
||||
// Converts an integer argument to char for printf.
|
||||
template <typename Context> class char_converter {
|
||||
private:
|
||||
basic_format_arg<Context>& arg_;
|
||||
|
||||
public:
|
||||
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
void operator()(T value) {
|
||||
arg_ = static_cast<typename Context::char_type>(value);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
void operator()(T) {} // No conversion needed for non-integral types.
|
||||
};
|
||||
|
||||
// An argument visitor that return a pointer to a C string if argument is a
|
||||
// string or null otherwise.
|
||||
template <typename Char> struct get_cstring {
|
||||
template <typename T> auto operator()(T) -> const Char* { return nullptr; }
|
||||
auto operator()(const Char* s) -> const Char* { return s; }
|
||||
};
|
||||
|
||||
// Checks if an argument is a valid printf width specifier and sets
|
||||
// left alignment if it is negative.
|
||||
class printf_width_handler {
|
||||
private:
|
||||
format_specs& specs_;
|
||||
|
||||
public:
|
||||
inline explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
auto operator()(T value) -> unsigned {
|
||||
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||
if (detail::is_negative(value)) {
|
||||
specs_.set_align(align::left);
|
||||
width = 0 - width;
|
||||
}
|
||||
unsigned int_max = to_unsigned(max_value<int>());
|
||||
if (width > int_max) report_error("number is too big");
|
||||
return static_cast<unsigned>(width);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
auto operator()(T) -> unsigned {
|
||||
report_error("width is not integer");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Workaround for a bug with the XL compiler when initializing
|
||||
// printf_arg_formatter's base class.
|
||||
template <typename Char>
|
||||
auto make_arg_formatter(basic_appender<Char> iter, format_specs& s)
|
||||
-> arg_formatter<Char> {
|
||||
return {iter, s, locale_ref()};
|
||||
}
|
||||
|
||||
// The `printf` argument formatter.
|
||||
template <typename Char>
|
||||
class printf_arg_formatter : public arg_formatter<Char> {
|
||||
private:
|
||||
using base = arg_formatter<Char>;
|
||||
using context_type = basic_printf_context<Char>;
|
||||
|
||||
context_type& context_;
|
||||
|
||||
void write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs;
|
||||
s.set_type(presentation_type::none);
|
||||
write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s);
|
||||
}
|
||||
|
||||
template <typename T> void write(T value) {
|
||||
detail::write<Char>(this->out, value, this->specs, this->locale);
|
||||
}
|
||||
|
||||
public:
|
||||
printf_arg_formatter(basic_appender<Char> iter, format_specs& s,
|
||||
context_type& ctx)
|
||||
: base(make_arg_formatter(iter, s)), context_(ctx) {}
|
||||
|
||||
void operator()(monostate value) { write(value); }
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
|
||||
void operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
||||
// std::is_same instead.
|
||||
if (!std::is_same<T, Char>::value) {
|
||||
write(value);
|
||||
return;
|
||||
}
|
||||
format_specs s = this->specs;
|
||||
if (s.type() != presentation_type::none &&
|
||||
s.type() != presentation_type::chr) {
|
||||
return (*this)(static_cast<int>(value));
|
||||
}
|
||||
s.set_sign(sign::none);
|
||||
s.clear_alt();
|
||||
s.set_fill(' '); // Ignore '0' flag for char types.
|
||||
// align::numeric needs to be overwritten here since the '0' flag is
|
||||
// ignored for non-numeric types
|
||||
if (s.align() == align::none || s.align() == align::numeric)
|
||||
s.set_align(align::right);
|
||||
detail::write<Char>(this->out, static_cast<Char>(value), s);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||
void operator()(T value) {
|
||||
write(value);
|
||||
}
|
||||
|
||||
void operator()(const char* value) {
|
||||
if (value)
|
||||
write(value);
|
||||
else
|
||||
write_null_pointer(this->specs.type() != presentation_type::pointer);
|
||||
}
|
||||
|
||||
void operator()(const wchar_t* value) {
|
||||
if (value)
|
||||
write(value);
|
||||
else
|
||||
write_null_pointer(this->specs.type() != presentation_type::pointer);
|
||||
}
|
||||
|
||||
void operator()(basic_string_view<Char> value) { write(value); }
|
||||
|
||||
void operator()(const void* value) {
|
||||
if (value)
|
||||
write(value);
|
||||
else
|
||||
write_null_pointer();
|
||||
}
|
||||
|
||||
void operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
auto parse_ctx = parse_context<Char>({});
|
||||
handle.format(parse_ctx, context_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
void parse_flags(format_specs& specs, const Char*& it, const Char* end) {
|
||||
for (; it != end; ++it) {
|
||||
switch (*it) {
|
||||
case '-': specs.set_align(align::left); break;
|
||||
case '+': specs.set_sign(sign::plus); break;
|
||||
case '0': specs.set_fill('0'); break;
|
||||
case ' ':
|
||||
if (specs.sign() != sign::plus) specs.set_sign(sign::space);
|
||||
break;
|
||||
case '#': specs.set_alt(); break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename GetArg>
|
||||
auto parse_header(const Char*& it, const Char* end, format_specs& specs,
|
||||
GetArg get_arg) -> int {
|
||||
int arg_index = -1;
|
||||
Char c = *it;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
// preceded with '0' flag(s).
|
||||
int value = parse_nonnegative_int(it, end, -1);
|
||||
if (it != end && *it == '$') { // value is an argument index
|
||||
++it;
|
||||
arg_index = value != -1 ? value : max_value<int>();
|
||||
} else {
|
||||
if (c == '0') specs.set_fill('0');
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
if (value == -1) report_error("number is too big");
|
||||
specs.width = value;
|
||||
return arg_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_flags(specs, it, end);
|
||||
// Parse width.
|
||||
if (it != end) {
|
||||
if (*it >= '0' && *it <= '9') {
|
||||
specs.width = parse_nonnegative_int(it, end, -1);
|
||||
if (specs.width == -1) report_error("number is too big");
|
||||
} else if (*it == '*') {
|
||||
++it;
|
||||
specs.width = static_cast<int>(
|
||||
get_arg(-1).visit(detail::printf_width_handler(specs)));
|
||||
}
|
||||
}
|
||||
return arg_index;
|
||||
}
|
||||
|
||||
inline auto parse_printf_presentation_type(char c, type t, bool& upper)
|
||||
-> presentation_type {
|
||||
using pt = presentation_type;
|
||||
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
|
||||
switch (c) {
|
||||
case 'd': return in(t, integral_set) ? pt::dec : pt::none;
|
||||
case 'o': return in(t, integral_set) ? pt::oct : pt::none;
|
||||
case 'X': upper = true; FMT_FALLTHROUGH;
|
||||
case 'x': return in(t, integral_set) ? pt::hex : pt::none;
|
||||
case 'E': upper = true; FMT_FALLTHROUGH;
|
||||
case 'e': return in(t, float_set) ? pt::exp : pt::none;
|
||||
case 'F': upper = true; FMT_FALLTHROUGH;
|
||||
case 'f': return in(t, float_set) ? pt::fixed : pt::none;
|
||||
case 'G': upper = true; FMT_FALLTHROUGH;
|
||||
case 'g': return in(t, float_set) ? pt::general : pt::none;
|
||||
case 'A': upper = true; FMT_FALLTHROUGH;
|
||||
case 'a': return in(t, float_set) ? pt::hexfloat : pt::none;
|
||||
case 'c': return in(t, integral_set) ? pt::chr : pt::none;
|
||||
case 's': return in(t, string_set | cstring_set) ? pt::string : pt::none;
|
||||
case 'p': return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
|
||||
default: return pt::none;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename Context>
|
||||
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
basic_format_args<Context> args) {
|
||||
using iterator = basic_appender<Char>;
|
||||
auto out = iterator(buf);
|
||||
auto context = basic_printf_context<Char>(out, args);
|
||||
auto parse_ctx = parse_context<Char>(format);
|
||||
|
||||
// Returns the argument with specified index or, if arg_index is -1, the next
|
||||
// argument.
|
||||
auto get_arg = [&](int arg_index) {
|
||||
if (arg_index < 0)
|
||||
arg_index = parse_ctx.next_arg_id();
|
||||
else
|
||||
parse_ctx.check_arg_id(--arg_index);
|
||||
return detail::get_arg(context, arg_index);
|
||||
};
|
||||
|
||||
const Char* start = parse_ctx.begin();
|
||||
const Char* end = parse_ctx.end();
|
||||
auto it = start;
|
||||
while (it != end) {
|
||||
if (!find<false, Char>(it, end, '%', it)) {
|
||||
it = end; // find leaves it == nullptr if it doesn't find '%'.
|
||||
break;
|
||||
}
|
||||
Char c = *it++;
|
||||
if (it != end && *it == c) {
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
||||
start = ++it;
|
||||
continue;
|
||||
}
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
|
||||
|
||||
auto specs = format_specs();
|
||||
specs.set_align(align::right);
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
int arg_index = parse_header(it, end, specs, get_arg);
|
||||
if (arg_index == 0) report_error("argument not found");
|
||||
|
||||
// Parse precision.
|
||||
if (it != end && *it == '.') {
|
||||
++it;
|
||||
c = it != end ? *it : 0;
|
||||
if ('0' <= c && c <= '9') {
|
||||
specs.precision = parse_nonnegative_int(it, end, 0);
|
||||
} else if (c == '*') {
|
||||
++it;
|
||||
specs.precision =
|
||||
static_cast<int>(get_arg(-1).visit(printf_precision_handler()));
|
||||
} else {
|
||||
specs.precision = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto arg = get_arg(arg_index);
|
||||
// For d, i, o, u, x, and X conversion specifiers, if a precision is
|
||||
// specified, the '0' flag is ignored
|
||||
if (specs.precision >= 0 && is_integral_type(arg.type())) {
|
||||
// Ignore '0' for non-numeric types or if '-' present.
|
||||
specs.set_fill(' ');
|
||||
}
|
||||
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
|
||||
auto str = arg.visit(get_cstring<Char>());
|
||||
auto str_end = str + specs.precision;
|
||||
auto nul = std::find(str, str_end, Char());
|
||||
auto sv = basic_string_view<Char>(
|
||||
str, to_unsigned(nul != str_end ? nul - str : specs.precision));
|
||||
arg = sv;
|
||||
}
|
||||
if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt();
|
||||
if (specs.fill_unit<Char>() == '0') {
|
||||
if (is_arithmetic_type(arg.type()) && specs.align() != align::left) {
|
||||
specs.set_align(align::numeric);
|
||||
} else {
|
||||
// Ignore '0' flag for non-numeric types or if '-' flag is also present.
|
||||
specs.set_fill(' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse length and convert the argument to the required type.
|
||||
c = it != end ? *it++ : 0;
|
||||
Char t = it != end ? *it : 0;
|
||||
switch (c) {
|
||||
case 'h':
|
||||
if (t == 'h') {
|
||||
++it;
|
||||
t = it != end ? *it : 0;
|
||||
convert_arg<signed char>(arg, t);
|
||||
} else {
|
||||
convert_arg<short>(arg, t);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (t == 'l') {
|
||||
++it;
|
||||
t = it != end ? *it : 0;
|
||||
convert_arg<long long>(arg, t);
|
||||
} else {
|
||||
convert_arg<long>(arg, t);
|
||||
}
|
||||
break;
|
||||
case 'j': convert_arg<intmax_t>(arg, t); break;
|
||||
case 'z': convert_arg<size_t>(arg, t); break;
|
||||
case 't': convert_arg<std::ptrdiff_t>(arg, t); break;
|
||||
case 'L':
|
||||
// printf produces garbage when 'L' is omitted for long double, no
|
||||
// need to do the same.
|
||||
break;
|
||||
default: --it; convert_arg<void>(arg, c);
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (it == end) report_error("invalid format string");
|
||||
char type = static_cast<char>(*it++);
|
||||
if (is_integral_type(arg.type())) {
|
||||
// Normalize type.
|
||||
switch (type) {
|
||||
case 'i':
|
||||
case 'u': type = 'd'; break;
|
||||
case 'c':
|
||||
arg.visit(char_converter<basic_printf_context<Char>>(arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool upper = false;
|
||||
specs.set_type(parse_printf_presentation_type(type, arg.type(), upper));
|
||||
if (specs.type() == presentation_type::none)
|
||||
report_error("invalid format specifier");
|
||||
if (upper) specs.set_upper();
|
||||
|
||||
start = it;
|
||||
|
||||
// Format argument.
|
||||
arg.visit(printf_arg_formatter<Char>(out, specs, context));
|
||||
}
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
using printf_context = basic_printf_context<char>;
|
||||
using wprintf_context = basic_printf_context<wchar_t>;
|
||||
|
||||
using printf_args = basic_format_args<printf_context>;
|
||||
using wprintf_args = basic_format_args<wprintf_context>;
|
||||
|
||||
/// Constructs an `format_arg_store` object that contains references to
|
||||
/// arguments and can be implicitly converted to `printf_args`.
|
||||
template <typename Char = char, typename... T>
|
||||
inline auto make_printf_args(T&... args)
|
||||
-> decltype(fmt::make_format_args<basic_printf_context<Char>>(args...)) {
|
||||
return fmt::make_format_args<basic_printf_context<Char>>(args...);
|
||||
}
|
||||
|
||||
template <typename Char> struct vprintf_args {
|
||||
using type = basic_format_args<basic_printf_context<Char>>;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
inline auto vsprintf(basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vprintf(buf, fmt, args);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats `args` according to specifications in `fmt` and returns the result
|
||||
* as as string.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* std::string message = fmt::sprintf("The answer is %d", 42);
|
||||
*/
|
||||
template <typename S, typename... T, typename Char = detail::char_t<S>>
|
||||
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
||||
return vsprintf(detail::to_string_view(fmt),
|
||||
fmt::make_format_args<basic_printf_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline auto vfprintf(std::FILE* f, basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args) -> int {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vprintf(buf, fmt, args);
|
||||
size_t size = buf.size();
|
||||
return std::fwrite(buf.data(), sizeof(Char), size, f) < size
|
||||
? -1
|
||||
: static_cast<int>(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats `args` according to specifications in `fmt` and writes the output
|
||||
* to `f`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||
*/
|
||||
template <typename S, typename... T, typename Char = detail::char_t<S>>
|
||||
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
|
||||
return vfprintf(f, detail::to_string_view(fmt),
|
||||
make_printf_args<Char>(args...));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_DEPRECATED inline auto vprintf(basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args)
|
||||
-> int {
|
||||
return vfprintf(stdout, fmt, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats `args` according to specifications in `fmt` and writes the output
|
||||
* to `stdout`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto printf(string_view fmt, const T&... args) -> int {
|
||||
return vfprintf(stdout, fmt, make_printf_args(args...));
|
||||
}
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt,
|
||||
const T&... args) -> int {
|
||||
return vfprintf(stdout, fmt, make_printf_args<wchar_t>(args...));
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_PRINTF_H_
|
||||
850
include/fmt/ranges.h
Normal file
850
include/fmt/ranges.h
Normal file
@@ -0,0 +1,850 @@
|
||||
// Formatting library for C++ - range and tuple support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_RANGES_H_
|
||||
#define FMT_RANGES_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <initializer_list>
|
||||
# include <iterator>
|
||||
# include <string>
|
||||
# include <tuple>
|
||||
# include <type_traits>
|
||||
# include <utility>
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
FMT_EXPORT
|
||||
enum class range_format { disabled, map, set, sequence, string, debug_string };
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T> class is_map {
|
||||
template <typename U> static auto check(U*) -> typename U::mapped_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename T> class is_set {
|
||||
template <typename U> static auto check(U*) -> typename U::key_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||
};
|
||||
|
||||
// C array overload
|
||||
template <typename T, std::size_t N>
|
||||
auto range_begin(const T (&arr)[N]) -> const T* {
|
||||
return arr;
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
auto range_end(const T (&arr)[N]) -> const T* {
|
||||
return arr + N;
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_member_fn_begin_end_t : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
|
||||
decltype(std::declval<T>().end())>>
|
||||
: std::true_type {};
|
||||
|
||||
// Member function overloads.
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) {
|
||||
return static_cast<T&&>(rng).begin();
|
||||
}
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
|
||||
return static_cast<T&&>(rng).end();
|
||||
}
|
||||
|
||||
// ADL overloads. Only participate in overload resolution if member functions
|
||||
// are not found.
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng)
|
||||
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(begin(static_cast<T&&>(rng)))> {
|
||||
return begin(static_cast<T&&>(rng));
|
||||
}
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(end(static_cast<T&&>(rng)))> {
|
||||
return end(static_cast<T&&>(rng));
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_const_begin_end : std::false_type {};
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_mutable_begin_end : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_const_begin_end<
|
||||
T, void_t<decltype(*detail::range_begin(
|
||||
std::declval<const remove_cvref_t<T>&>())),
|
||||
decltype(detail::range_end(
|
||||
std::declval<const remove_cvref_t<T>&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_mutable_begin_end<
|
||||
T, void_t<decltype(*detail::range_begin(std::declval<T&>())),
|
||||
decltype(detail::range_end(std::declval<T&>())),
|
||||
// the extra int here is because older versions of MSVC don't
|
||||
// SFINAE properly unless there are distinct types
|
||||
int>> : std::true_type {};
|
||||
|
||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_range_<T, void>
|
||||
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
|
||||
has_mutable_begin_end<T>::value)> {};
|
||||
|
||||
// tuple_size and tuple_element check.
|
||||
template <typename T> class is_tuple_like_ {
|
||||
template <typename U, typename V = typename std::remove_cv<U>::type>
|
||||
static auto check(U* p) -> decltype(std::tuple_size<V>::value, 0);
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
// Check for integer_sequence
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
|
||||
template <typename T, T... N>
|
||||
using integer_sequence = std::integer_sequence<T, N...>;
|
||||
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
|
||||
#else
|
||||
template <typename T, T... N> struct integer_sequence {
|
||||
using value_type = T;
|
||||
|
||||
static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); }
|
||||
};
|
||||
|
||||
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
|
||||
|
||||
template <typename T, size_t N, T... Ns>
|
||||
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
||||
template <typename T, T... Ns>
|
||||
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
||||
|
||||
template <size_t N>
|
||||
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
|
||||
|
||||
template <typename T, typename C, bool = is_tuple_like_<T>::value>
|
||||
class is_tuple_formattable_ {
|
||||
public:
|
||||
static constexpr const bool value = false;
|
||||
};
|
||||
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||
template <size_t... Is>
|
||||
static auto all_true(index_sequence<Is...>,
|
||||
integer_sequence<bool, (Is >= 0)...>) -> std::true_type;
|
||||
static auto all_true(...) -> std::false_type;
|
||||
|
||||
template <size_t... Is>
|
||||
static auto check(index_sequence<Is...>) -> decltype(all_true(
|
||||
index_sequence<Is...>{},
|
||||
integer_sequence<bool,
|
||||
(is_formattable<typename std::tuple_element<Is, T>::type,
|
||||
C>::value)...>{}));
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
decltype(check(tuple_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename F, size_t... Is>
|
||||
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
|
||||
using std::get;
|
||||
// Using a free function get<Is>(Tuple) now.
|
||||
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
|
||||
template <typename Tuple, typename F>
|
||||
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
|
||||
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
|
||||
std::forward<Tuple>(t), std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
|
||||
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||
using std::get;
|
||||
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
|
||||
template <typename Tuple1, typename Tuple2, typename F>
|
||||
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
|
||||
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
namespace tuple {
|
||||
// Workaround a bug in MSVC 2019 (v140).
|
||||
template <typename Char, typename... T>
|
||||
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
|
||||
|
||||
using std::get;
|
||||
template <typename Tuple, typename Char, std::size_t... Is>
|
||||
auto get_formatters(index_sequence<Is...>)
|
||||
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
|
||||
} // namespace tuple
|
||||
|
||||
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
|
||||
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||
template <typename R> struct range_reference_type_impl {
|
||||
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
|
||||
using type = T&;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using range_reference_type = typename range_reference_type_impl<T>::type;
|
||||
#else
|
||||
template <typename Range>
|
||||
using range_reference_type =
|
||||
decltype(*detail::range_begin(std::declval<Range&>()));
|
||||
#endif
|
||||
|
||||
// We don't use the Range's value_type for anything, but we do need the Range's
|
||||
// reference type, with cv-ref stripped.
|
||||
template <typename Range>
|
||||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
|
||||
-> decltype(f.set_debug_format(set)) {
|
||||
f.set_debug_format(set);
|
||||
}
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
|
||||
|
||||
template <typename T>
|
||||
struct range_format_kind_
|
||||
: std::integral_constant<range_format,
|
||||
std::is_same<uncvref_type<T>, T>::value
|
||||
? range_format::disabled
|
||||
: is_map<T>::value ? range_format::map
|
||||
: is_set<T>::value ? range_format::set
|
||||
: range_format::sequence> {};
|
||||
|
||||
template <range_format K>
|
||||
using range_format_constant = std::integral_constant<range_format, K>;
|
||||
|
||||
// These are not generic lambdas for compatibility with C++11.
|
||||
template <typename Char> struct parse_empty_specs {
|
||||
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
|
||||
f.parse(ctx);
|
||||
detail::maybe_set_debug_format(f, true);
|
||||
}
|
||||
parse_context<Char>& ctx;
|
||||
};
|
||||
template <typename FormatContext> struct format_tuple_element {
|
||||
using char_type = typename FormatContext::char_type;
|
||||
|
||||
template <typename T>
|
||||
void operator()(const formatter<T, char_type>& f, const T& v) {
|
||||
if (i > 0) ctx.advance_to(detail::copy<char_type>(separator, ctx.out()));
|
||||
ctx.advance_to(f.format(v, ctx));
|
||||
++i;
|
||||
}
|
||||
|
||||
int i;
|
||||
FormatContext& ctx;
|
||||
basic_string_view<char_type> separator;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_tuple_like {
|
||||
static constexpr const bool value =
|
||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename C> struct is_tuple_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_tuple_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename Char>
|
||||
struct formatter<Tuple, Char,
|
||||
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
|
||||
fmt::is_tuple_formattable<Tuple, Char>::value>> {
|
||||
private:
|
||||
decltype(detail::tuple::get_formatters<Tuple, Char>(
|
||||
detail::tuple_index_sequence<Tuple>())) formatters_;
|
||||
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '('>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ')'>{};
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR formatter() {}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it != end && detail::to_ascii(*it) == 'n') {
|
||||
++it;
|
||||
set_brackets({}, {});
|
||||
set_separator({});
|
||||
}
|
||||
if (it != end && *it != '}') report_error("invalid format specifier");
|
||||
ctx.advance_to(it);
|
||||
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Tuple& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
ctx.advance_to(detail::copy<Char>(opening_bracket_, ctx.out()));
|
||||
detail::for_each2(
|
||||
formatters_, value,
|
||||
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
|
||||
return detail::copy<Char>(closing_bracket_, ctx.out());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static constexpr const bool value =
|
||||
detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename Element>
|
||||
using range_formatter_type = formatter<remove_cvref_t<Element>, Char>;
|
||||
|
||||
template <typename R>
|
||||
using maybe_const_range =
|
||||
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct is_formattable_delayed
|
||||
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename...> struct conjunction : std::true_type {};
|
||||
template <typename P> struct conjunction<P> : P {};
|
||||
template <typename P1, typename... Pn>
|
||||
struct conjunction<P1, Pn...>
|
||||
: conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
|
||||
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_formatter;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct range_formatter<
|
||||
T, Char,
|
||||
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
|
||||
is_formattable<T, Char>>::value>> {
|
||||
private:
|
||||
detail::range_formatter_type<Char, T> underlying_;
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '['>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ']'>{};
|
||||
bool is_debug = false;
|
||||
|
||||
template <typename Output, typename It, typename Sentinel, typename U = T,
|
||||
FMT_ENABLE_IF(std::is_same<U, Char>::value)>
|
||||
auto write_debug_string(Output& out, It it, Sentinel end) const -> Output {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
for (; it != end; ++it) buf.push_back(*it);
|
||||
auto specs = format_specs();
|
||||
specs.set_type(presentation_type::debug);
|
||||
return detail::write<Char>(
|
||||
out, basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
}
|
||||
|
||||
template <typename Output, typename It, typename Sentinel, typename U = T,
|
||||
FMT_ENABLE_IF(!std::is_same<U, Char>::value)>
|
||||
auto write_debug_string(Output& out, It, Sentinel) const -> Output {
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR range_formatter() {}
|
||||
|
||||
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
|
||||
return underlying_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
detail::maybe_set_debug_format(underlying_, true);
|
||||
if (it == end) return underlying_.parse(ctx);
|
||||
|
||||
switch (detail::to_ascii(*it)) {
|
||||
case 'n':
|
||||
set_brackets({}, {});
|
||||
++it;
|
||||
break;
|
||||
case '?':
|
||||
is_debug = true;
|
||||
set_brackets({}, {});
|
||||
++it;
|
||||
if (it == end || *it != 's') report_error("invalid format specifier");
|
||||
FMT_FALLTHROUGH;
|
||||
case 's':
|
||||
if (!std::is_same<T, Char>::value)
|
||||
report_error("invalid format specifier");
|
||||
if (!is_debug) {
|
||||
set_brackets(detail::string_literal<Char, '"'>{},
|
||||
detail::string_literal<Char, '"'>{});
|
||||
set_separator({});
|
||||
detail::maybe_set_debug_format(underlying_, false);
|
||||
}
|
||||
++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
if (it != end && *it != '}') {
|
||||
if (*it != ':') report_error("invalid format specifier");
|
||||
detail::maybe_set_debug_format(underlying_, false);
|
||||
++it;
|
||||
}
|
||||
|
||||
ctx.advance_to(it);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename R, typename FormatContext>
|
||||
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
auto it = detail::range_begin(range);
|
||||
auto end = detail::range_end(range);
|
||||
if (is_debug) return write_debug_string(out, std::move(it), end);
|
||||
|
||||
out = detail::copy<Char>(opening_bracket_, out);
|
||||
int i = 0;
|
||||
for (; it != end; ++it) {
|
||||
if (i > 0) out = detail::copy<Char>(separator_, out);
|
||||
ctx.advance_to(out);
|
||||
auto&& item = *it; // Need an lvalue
|
||||
out = underlying_.format(item, ctx);
|
||||
++i;
|
||||
}
|
||||
out = detail::copy<Char>(closing_bracket_, out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_format_kind
|
||||
: conditional_t<
|
||||
is_range<T, Char>::value, detail::range_format_kind_<T>,
|
||||
std::integral_constant<range_format, range_format::disabled>> {};
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<conjunction<
|
||||
bool_constant<
|
||||
range_format_kind<R, Char>::value != range_format::disabled &&
|
||||
range_format_kind<R, Char>::value != range_format::map &&
|
||||
range_format_kind<R, Char>::value != range_format::string &&
|
||||
range_format_kind<R, Char>::value != range_format::debug_string>,
|
||||
detail::is_formattable_delayed<R, Char>>::value>> {
|
||||
private:
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
range_formatter<detail::uncvref_type<range_type>, Char> range_formatter_;
|
||||
|
||||
public:
|
||||
using nonlocking = void;
|
||||
|
||||
FMT_CONSTEXPR formatter() {
|
||||
if (detail::const_check(range_format_kind<R, Char>::value !=
|
||||
range_format::set))
|
||||
return;
|
||||
range_formatter_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||
detail::string_literal<Char, '}'>{});
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return range_formatter_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return range_formatter_.format(range, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// A map formatter.
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<conjunction<
|
||||
bool_constant<range_format_kind<R, Char>::value == range_format::map>,
|
||||
detail::is_formattable_delayed<R, Char>>::value>> {
|
||||
private:
|
||||
using map_type = detail::maybe_const_range<R>;
|
||||
using element_type = detail::uncvref_type<map_type>;
|
||||
|
||||
decltype(detail::tuple::get_formatters<element_type, Char>(
|
||||
detail::tuple_index_sequence<element_type>())) formatters_;
|
||||
bool no_delimiters_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR formatter() {}
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it != end) {
|
||||
if (detail::to_ascii(*it) == 'n') {
|
||||
no_delimiters_ = true;
|
||||
++it;
|
||||
}
|
||||
if (it != end && *it != '}') {
|
||||
if (*it != ':') report_error("invalid format specifier");
|
||||
++it;
|
||||
}
|
||||
ctx.advance_to(it);
|
||||
}
|
||||
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
basic_string_view<Char> open = detail::string_literal<Char, '{'>{};
|
||||
if (!no_delimiters_) out = detail::copy<Char>(open, out);
|
||||
int i = 0;
|
||||
basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{};
|
||||
for (auto&& value : map) {
|
||||
if (i > 0) out = detail::copy<Char>(sep, out);
|
||||
ctx.advance_to(out);
|
||||
detail::for_each2(formatters_, value,
|
||||
detail::format_tuple_element<FormatContext>{
|
||||
0, ctx, detail::string_literal<Char, ':', ' '>{}});
|
||||
++i;
|
||||
}
|
||||
basic_string_view<Char> close = detail::string_literal<Char, '}'>{};
|
||||
if (!no_delimiters_) out = detail::copy<Char>(close, out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// A (debug_)string formatter.
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<range_format_kind<R, Char>::value == range_format::string ||
|
||||
range_format_kind<R, Char>::value ==
|
||||
range_format::debug_string>> {
|
||||
private:
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
using string_type =
|
||||
conditional_t<std::is_constructible<
|
||||
detail::std_string_view<Char>,
|
||||
decltype(detail::range_begin(std::declval<R>())),
|
||||
decltype(detail::range_end(std::declval<R>()))>::value,
|
||||
detail::std_string_view<Char>, std::basic_string<Char>>;
|
||||
|
||||
formatter<string_type, Char> underlying_;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
if (detail::const_check(range_format_kind<R, Char>::value ==
|
||||
range_format::debug_string))
|
||||
*out++ = '"';
|
||||
out = underlying_.format(
|
||||
string_type{detail::range_begin(range), detail::range_end(range)}, ctx);
|
||||
if (detail::const_check(range_format_kind<R, Char>::value ==
|
||||
range_format::debug_string))
|
||||
*out++ = '"';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename It, typename Sentinel, typename Char = char>
|
||||
struct join_view : detail::view {
|
||||
It begin;
|
||||
Sentinel end;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
join_view(It b, Sentinel e, basic_string_view<Char> s)
|
||||
: begin(std::move(b)), end(e), sep(s) {}
|
||||
};
|
||||
|
||||
template <typename It, typename Sentinel, typename Char>
|
||||
struct formatter<join_view<It, Sentinel, Char>, Char> {
|
||||
private:
|
||||
using value_type =
|
||||
#ifdef __cpp_lib_ranges
|
||||
std::iter_value_t<It>;
|
||||
#else
|
||||
typename std::iterator_traits<It>::value_type;
|
||||
#endif
|
||||
formatter<remove_cvref_t<value_type>, Char> value_formatter_;
|
||||
|
||||
using view = conditional_t<std::is_copy_constructible<It>::value,
|
||||
const join_view<It, Sentinel, Char>,
|
||||
join_view<It, Sentinel, Char>>;
|
||||
|
||||
public:
|
||||
using nonlocking = void;
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return value_formatter_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
using iter =
|
||||
conditional_t<std::is_copy_constructible<view>::value, It, It&>;
|
||||
iter it = value.begin;
|
||||
auto out = ctx.out();
|
||||
if (it == value.end) return out;
|
||||
out = value_formatter_.format(*it, ctx);
|
||||
++it;
|
||||
while (it != value.end) {
|
||||
out = detail::copy<Char>(value.sep.begin(), value.sep.end(), out);
|
||||
ctx.advance_to(out);
|
||||
out = value_formatter_.format(*it, ctx);
|
||||
++it;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Tuple> struct tuple_join_view : detail::view {
|
||||
const Tuple& tuple;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
tuple_join_view(const Tuple& t, basic_string_view<Char> s)
|
||||
: tuple(t), sep{s} {}
|
||||
};
|
||||
|
||||
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
||||
// support in tuple_join. It is disabled by default because of issues with
|
||||
// the dynamic width and precision.
|
||||
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
|
||||
# define FMT_TUPLE_JOIN_SPECIFIERS 0
|
||||
#endif
|
||||
|
||||
template <typename Char, typename Tuple>
|
||||
struct formatter<tuple_join_view<Char, Tuple>, Char,
|
||||
enable_if_t<is_tuple_like<Tuple>::value>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return do_parse(ctx, std::tuple_size<Tuple>());
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const tuple_join_view<Char, Tuple>& value,
|
||||
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||
return do_format(value, ctx, std::tuple_size<Tuple>());
|
||||
}
|
||||
|
||||
private:
|
||||
decltype(detail::tuple::get_formatters<Tuple, Char>(
|
||||
detail::tuple_index_sequence<Tuple>())) formatters_;
|
||||
|
||||
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
|
||||
std::integral_constant<size_t, 0>)
|
||||
-> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
|
||||
std::integral_constant<size_t, N>)
|
||||
-> const Char* {
|
||||
auto end = ctx.begin();
|
||||
#if FMT_TUPLE_JOIN_SPECIFIERS
|
||||
end = std::get<std::tuple_size<Tuple>::value - N>(formatters_).parse(ctx);
|
||||
if (N > 1) {
|
||||
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
||||
if (end != end1)
|
||||
report_error("incompatible format specs for tuple elements");
|
||||
}
|
||||
#endif
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto do_format(const tuple_join_view<Char, Tuple>&, FormatContext& ctx,
|
||||
std::integral_constant<size_t, 0>) const ->
|
||||
typename FormatContext::iterator {
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
template <typename FormatContext, size_t N>
|
||||
auto do_format(const tuple_join_view<Char, Tuple>& value, FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
typename FormatContext::iterator {
|
||||
using std::get;
|
||||
auto out =
|
||||
std::get<std::tuple_size<Tuple>::value - N>(formatters_)
|
||||
.format(get<std::tuple_size<Tuple>::value - N>(value.tuple), ctx);
|
||||
if (N <= 1) return out;
|
||||
out = detail::copy<Char>(value.sep, out);
|
||||
ctx.advance_to(out);
|
||||
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// Check if T has an interface like a container adaptor (e.g. std::stack,
|
||||
// std::queue, std::priority_queue).
|
||||
template <typename T> class is_container_adaptor_like {
|
||||
template <typename U> static auto check(U* p) -> typename U::container_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename Container> struct all {
|
||||
const Container& c;
|
||||
auto begin() const -> typename Container::const_iterator { return c.begin(); }
|
||||
auto end() const -> typename Container::const_iterator { return c.end(); }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char,
|
||||
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
|
||||
bool_constant<range_format_kind<T, Char>::value ==
|
||||
range_format::disabled>>::value>>
|
||||
: formatter<detail::all<typename T::container_type>, Char> {
|
||||
using all = detail::all<typename T::container_type>;
|
||||
template <typename FormatContext>
|
||||
auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
struct getter : T {
|
||||
static auto get(const T& t) -> all {
|
||||
return {t.*(&getter::c)}; // Access c through the derived class.
|
||||
}
|
||||
};
|
||||
return formatter<all>::format(getter::get(t), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
/// Returns a view that formats the iterator range `[begin, end)` with elements
|
||||
/// separated by `sep`.
|
||||
template <typename It, typename Sentinel>
|
||||
auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
|
||||
return {std::move(begin), end, sep};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view that formats `range` with elements separated by `sep`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* auto v = std::vector<int>{1, 2, 3};
|
||||
* fmt::print("{}", fmt::join(v, ", "));
|
||||
* // Output: 1, 2, 3
|
||||
*
|
||||
* `fmt::join` applies passed format specifiers to the range elements:
|
||||
*
|
||||
* fmt::print("{:02}", fmt::join(v, ", "));
|
||||
* // Output: 01, 02, 03
|
||||
*/
|
||||
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
|
||||
auto join(Range&& r, string_view sep)
|
||||
-> join_view<decltype(detail::range_begin(r)),
|
||||
decltype(detail::range_end(r))> {
|
||||
return {detail::range_begin(r), detail::range_end(r), sep};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object that formats `std::tuple` with elements separated by `sep`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* auto t = std::tuple<int, char>{1, 'a'};
|
||||
* fmt::print("{}", fmt::join(t, ", "));
|
||||
* // Output: 1, a
|
||||
*/
|
||||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
|
||||
FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep)
|
||||
-> tuple_join_view<char, Tuple> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object that formats `std::initializer_list` with elements
|
||||
* separated by `sep`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::print("{}", fmt::join({1, 2, 3}, ", "));
|
||||
* // Output: "1, 2, 3"
|
||||
*/
|
||||
template <typename T>
|
||||
auto join(std::initializer_list<T> list, string_view sep)
|
||||
-> join_view<const T*, const T*> {
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_RANGES_H_
|
||||
726
include/fmt/std.h
Normal file
726
include/fmt/std.h
Normal file
@@ -0,0 +1,726 @@
|
||||
// Formatting library for C++ - formatters for standard library types
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_STD_H_
|
||||
#define FMT_STD_H_
|
||||
|
||||
#include "format.h"
|
||||
#include "ostream.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <atomic>
|
||||
# include <bitset>
|
||||
# include <complex>
|
||||
# include <cstdlib>
|
||||
# include <exception>
|
||||
# include <functional>
|
||||
# include <memory>
|
||||
# include <thread>
|
||||
# include <type_traits>
|
||||
# include <typeinfo>
|
||||
# include <utility>
|
||||
# include <vector>
|
||||
|
||||
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
|
||||
# if FMT_CPLUSPLUS >= 201703L
|
||||
# if FMT_HAS_INCLUDE(<filesystem>) && \
|
||||
(!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0)
|
||||
# include <filesystem>
|
||||
# endif
|
||||
# if FMT_HAS_INCLUDE(<variant>)
|
||||
# include <variant>
|
||||
# endif
|
||||
# if FMT_HAS_INCLUDE(<optional>)
|
||||
# include <optional>
|
||||
# endif
|
||||
# endif
|
||||
// Use > instead of >= in the version check because <source_location> may be
|
||||
// available after C++17 but before C++20 is marked as implemented.
|
||||
# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
|
||||
# include <source_location>
|
||||
# endif
|
||||
# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>)
|
||||
# include <expected>
|
||||
# endif
|
||||
#endif // FMT_MODULE
|
||||
|
||||
#if FMT_HAS_INCLUDE(<version>)
|
||||
# include <version>
|
||||
#endif
|
||||
|
||||
// GCC 4 does not support FMT_HAS_INCLUDE.
|
||||
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
|
||||
# include <cxxabi.h>
|
||||
// Android NDK with gabi++ library on some architectures does not implement
|
||||
// abi::__cxa_demangle().
|
||||
# ifndef __GABIXX_CXXABI_H__
|
||||
# define FMT_HAS_ABI_CXA_DEMANGLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined.
|
||||
#ifndef FMT_CPP_LIB_FILESYSTEM
|
||||
# ifdef __cpp_lib_filesystem
|
||||
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
|
||||
# else
|
||||
# define FMT_CPP_LIB_FILESYSTEM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FMT_CPP_LIB_VARIANT
|
||||
# ifdef __cpp_lib_variant
|
||||
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
|
||||
# else
|
||||
# define FMT_CPP_LIB_VARIANT 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_FILESYSTEM
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
auto get_path_string(const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
|
||||
return to_utf8<wchar_t>(native, to_utf8_error_policy::replace);
|
||||
else
|
||||
return p.string<Char>();
|
||||
}
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> &&
|
||||
std::is_same_v<PathChar, wchar_t>) {
|
||||
auto buf = basic_memory_buffer<wchar_t>();
|
||||
write_escaped_string<wchar_t>(std::back_inserter(buf), native);
|
||||
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
|
||||
FMT_ASSERT(valid, "invalid utf16");
|
||||
} else if constexpr (std::is_same_v<Char, PathChar>) {
|
||||
write_escaped_string<std::filesystem::path::value_type>(
|
||||
std::back_inserter(quoted), native);
|
||||
} else {
|
||||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||
private:
|
||||
format_specs specs_;
|
||||
detail::arg_ref<Char> width_ref_;
|
||||
bool debug_ = false;
|
||||
char path_type_ = 0;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it == end) return it;
|
||||
|
||||
it = detail::parse_align(it, end, specs_);
|
||||
if (it == end) return it;
|
||||
|
||||
Char c = *it;
|
||||
if ((c >= '0' && c <= '9') || c == '{')
|
||||
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||
if (it != end && *it == '?') {
|
||||
debug_ = true;
|
||||
++it;
|
||||
}
|
||||
if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
|
||||
auto specs = specs_;
|
||||
auto path_string =
|
||||
!path_type_ ? p.native()
|
||||
: p.generic_string<std::filesystem::path::value_type>();
|
||||
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||
ctx);
|
||||
if (!debug_) {
|
||||
auto s = detail::get_path_string<Char>(p, path_string);
|
||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||
}
|
||||
auto quoted = basic_memory_buffer<Char>();
|
||||
detail::write_escaped_path(quoted, p, path_string);
|
||||
return detail::write(ctx.out(),
|
||||
basic_string_view<Char>(quoted.data(), quoted.size()),
|
||||
specs);
|
||||
}
|
||||
};
|
||||
|
||||
class path : public std::filesystem::path {
|
||||
public:
|
||||
auto display_string() const -> std::string {
|
||||
const std::filesystem::path& base = *this;
|
||||
return fmt::format(FMT_STRING("{}"), base);
|
||||
}
|
||||
auto system_string() const -> std::string { return string(); }
|
||||
|
||||
auto generic_display_string() const -> std::string {
|
||||
const std::filesystem::path& base = *this;
|
||||
return fmt::format(FMT_STRING("{:g}"), base);
|
||||
}
|
||||
auto generic_system_string() const -> std::string { return generic_string(); }
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <std::size_t N, typename Char>
|
||||
struct formatter<std::bitset<N>, Char>
|
||||
: nested_formatter<basic_string_view<Char>, Char> {
|
||||
private:
|
||||
// Functor because C++11 doesn't support generic lambdas.
|
||||
struct writer {
|
||||
const std::bitset<N>& bs;
|
||||
|
||||
template <typename OutputIt>
|
||||
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
|
||||
for (auto pos = N; pos > 0; --pos) {
|
||||
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename FormatContext>
|
||||
auto format(const std::bitset<N>& bs, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return this->write_padded(ctx, writer{bs});
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Char>
|
||||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::optional<T>, Char,
|
||||
std::enable_if_t<is_formattable<T, Char>::value>> {
|
||||
private:
|
||||
formatter<T, Char> underlying_;
|
||||
static constexpr basic_string_view<Char> optional =
|
||||
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
|
||||
'('>{};
|
||||
static constexpr basic_string_view<Char> none =
|
||||
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
|
||||
-> decltype(u.set_debug_format(set)) {
|
||||
u.set_debug_format(set);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
||||
maybe_set_debug_format(underlying_, true);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::optional<T>& opt, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
if (!opt) return detail::write<Char>(ctx.out(), none);
|
||||
|
||||
auto out = ctx.out();
|
||||
out = detail::write<Char>(out, optional);
|
||||
ctx.advance_to(out);
|
||||
out = underlying_.format(*opt, ctx);
|
||||
return detail::write(out, ')');
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // __cpp_lib_optional
|
||||
|
||||
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename OutputIt, typename T>
|
||||
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||
if constexpr (has_to_string_view<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
|
||||
return write<Char>(out, v);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_expected
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename E, typename Char>
|
||||
struct formatter<std::expected<T, E>, Char,
|
||||
std::enable_if_t<(std::is_void<T>::value ||
|
||||
is_formattable<T, Char>::value) &&
|
||||
is_formattable<E, Char>::value>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::expected<T, E>& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
|
||||
if (value.has_value()) {
|
||||
out = detail::write<Char>(out, "expected(");
|
||||
if constexpr (!std::is_void<T>::value)
|
||||
out = detail::write_escaped_alternative<Char>(out, *value);
|
||||
} else {
|
||||
out = detail::write<Char>(out, "unexpected(");
|
||||
out = detail::write_escaped_alternative<Char>(out, value.error());
|
||||
}
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // __cpp_lib_expected
|
||||
|
||||
#ifdef __cpp_lib_source_location
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <> struct formatter<std::source_location> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::source_location& loc, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = detail::write(out, loc.file_name());
|
||||
out = detail::write(out, ':');
|
||||
out = detail::write<char>(out, loc.line());
|
||||
out = detail::write(out, ':');
|
||||
out = detail::write<char>(out, loc.column());
|
||||
out = detail::write(out, ": ");
|
||||
out = detail::write(out, loc.function_name());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_VARIANT
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using variant_index_sequence =
|
||||
std::make_index_sequence<std::variant_size<T>::value>;
|
||||
|
||||
template <typename> struct is_variant_like_ : std::false_type {};
|
||||
template <typename... Types>
|
||||
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
|
||||
|
||||
// formattable element check.
|
||||
template <typename T, typename C> class is_variant_formattable_ {
|
||||
template <std::size_t... Is>
|
||||
static std::conjunction<
|
||||
is_formattable<std::variant_alternative_t<Is, T>, C>...>
|
||||
check(std::index_sequence<Is...>);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
decltype(check(variant_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_variant_like {
|
||||
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename C> struct is_variant_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_variant_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Char> struct formatter<std::monostate, Char> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::monostate&, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return detail::write<Char>(ctx.out(), "monostate");
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Variant, typename Char>
|
||||
struct formatter<
|
||||
Variant, Char,
|
||||
std::enable_if_t<std::conjunction_v<
|
||||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Variant& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
|
||||
out = detail::write<Char>(out, "variant(");
|
||||
FMT_TRY {
|
||||
std::visit(
|
||||
[&](const auto& v) {
|
||||
out = detail::write_escaped_alternative<Char>(out, v);
|
||||
},
|
||||
value);
|
||||
}
|
||||
FMT_CATCH(const std::bad_variant_access&) {
|
||||
detail::write<Char>(out, "valueless by exception");
|
||||
}
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // FMT_CPP_LIB_VARIANT
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <> struct formatter<std::error_code> {
|
||||
private:
|
||||
format_specs specs_;
|
||||
detail::arg_ref<char> width_ref_;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it == end) return it;
|
||||
|
||||
it = detail::parse_align(it, end, specs_);
|
||||
if (it == end) return it;
|
||||
|
||||
char c = *it;
|
||||
if ((c >= '0' && c <= '9') || c == '{')
|
||||
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR20 auto format(const std::error_code& ec,
|
||||
FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto specs = specs_;
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||
ctx);
|
||||
memory_buffer buf;
|
||||
buf.append(string_view(ec.category().name()));
|
||||
buf.push_back(':');
|
||||
detail::write<char>(appender(buf), ec.value());
|
||||
return detail::write<char>(ctx.out(), string_view(buf.data(), buf.size()),
|
||||
specs);
|
||||
}
|
||||
};
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
|
||||
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
|
||||
int status = 0;
|
||||
std::size_t size = 0;
|
||||
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
|
||||
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
|
||||
|
||||
string_view demangled_name_view;
|
||||
if (demangled_name_ptr) {
|
||||
demangled_name_view = demangled_name_ptr.get();
|
||||
|
||||
// Normalization of stdlib inline namespace names.
|
||||
// libc++ inline namespaces.
|
||||
// std::__1::* -> std::*
|
||||
// std::__1::__fs::* -> std::*
|
||||
// libstdc++ inline namespaces.
|
||||
// std::__cxx11::* -> std::*
|
||||
// std::filesystem::__cxx11::* -> std::filesystem::*
|
||||
if (demangled_name_view.starts_with("std::")) {
|
||||
char* begin = demangled_name_ptr.get();
|
||||
char* to = begin + 5; // std::
|
||||
for (char *from = to, *end = begin + demangled_name_view.size();
|
||||
from < end;) {
|
||||
// This is safe, because demangled_name is NUL-terminated.
|
||||
if (from[0] == '_' && from[1] == '_') {
|
||||
char* next = from + 1;
|
||||
while (next < end && *next != ':') next++;
|
||||
if (next[0] == ':' && next[1] == ':') {
|
||||
from = next + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*to++ = *from++;
|
||||
}
|
||||
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
|
||||
}
|
||||
} else {
|
||||
demangled_name_view = string_view(ti.name());
|
||||
}
|
||||
return detail::write_bytes<Char>(out, demangled_name_view);
|
||||
# elif FMT_MSC_VERSION
|
||||
const string_view demangled_name(ti.name());
|
||||
for (std::size_t i = 0; i < demangled_name.size(); ++i) {
|
||||
auto sub = demangled_name;
|
||||
sub.remove_prefix(i);
|
||||
if (sub.starts_with("enum ")) {
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("class ") || sub.starts_with("union ")) {
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("struct ")) {
|
||||
i += 6;
|
||||
continue;
|
||||
}
|
||||
if (*sub.begin() != ' ') *out++ = *sub.begin();
|
||||
}
|
||||
return out;
|
||||
# else
|
||||
return detail::write_bytes<Char>(out, string_view(ti.name()));
|
||||
# endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Char>
|
||||
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
|
||||
> {
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
auto format(const std::type_info& ti, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return detail::write_demangled_name<Char>(ctx.out(), ti);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char, // DEPRECATED! Mixing code unit types.
|
||||
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
|
||||
private:
|
||||
bool with_typename_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it == end || *it == '}') return it;
|
||||
if (*it == 't') {
|
||||
++it;
|
||||
with_typename_ = FMT_USE_RTTI != 0;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
auto format(const std::exception& ex, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
#if FMT_USE_RTTI
|
||||
if (with_typename_) {
|
||||
out = detail::write_demangled_name<Char>(out, typeid(ex));
|
||||
*out++ = ':';
|
||||
*out++ = ' ';
|
||||
}
|
||||
#endif
|
||||
return detail::write_bytes<Char>(out, string_view(ex.what()));
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_flip : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T> struct is_bit_reference_like {
|
||||
static constexpr const bool value =
|
||||
std::is_convertible<T, bool>::value &&
|
||||
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
|
||||
};
|
||||
|
||||
#ifdef _LIBCPP_VERSION
|
||||
|
||||
// Workaround for libc++ incompatibility with C++ standard.
|
||||
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||
template <typename C>
|
||||
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||
static constexpr const bool value = true;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// We can't use std::vector<bool, Allocator>::reference and
|
||||
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
||||
// in partial specialization.
|
||||
FMT_EXPORT
|
||||
template <typename BitRef, typename Char>
|
||||
struct formatter<BitRef, Char,
|
||||
enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
|
||||
: formatter<bool, Char> {
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<bool, Char>::format(v, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::atomic<T>, Char,
|
||||
enable_if_t<is_formattable<T, Char>::value>>
|
||||
: formatter<T, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::atomic<T>& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<T, Char>::format(v.load(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cpp_lib_atomic_flag_test
|
||||
FMT_EXPORT
|
||||
template <typename Char>
|
||||
struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::atomic_flag& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<bool, Char>::format(v.test(), ctx);
|
||||
}
|
||||
};
|
||||
#endif // __cpp_lib_atomic_flag_test
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
||||
private:
|
||||
detail::dynamic_format_specs<Char> specs_;
|
||||
|
||||
template <typename FormatContext, typename OutputIt>
|
||||
FMT_CONSTEXPR auto do_format(const std::complex<T>& c,
|
||||
detail::dynamic_format_specs<Char>& specs,
|
||||
FormatContext& ctx, OutputIt out) const
|
||||
-> OutputIt {
|
||||
if (c.real() != 0) {
|
||||
*out++ = Char('(');
|
||||
out = detail::write<Char>(out, c.real(), specs, ctx.locale());
|
||||
specs.set_sign(sign::plus);
|
||||
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
|
||||
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
|
||||
*out++ = Char('i');
|
||||
*out++ = Char(')');
|
||||
return out;
|
||||
}
|
||||
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
|
||||
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
|
||||
*out++ = Char('i');
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
|
||||
return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
|
||||
detail::type_constant<T, Char>::value);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::complex<T>& c, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto specs = specs_;
|
||||
if (specs.dynamic()) {
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
|
||||
specs.width_ref, ctx);
|
||||
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||
specs.precision_ref, ctx);
|
||||
}
|
||||
|
||||
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
|
||||
auto outer_specs = format_specs();
|
||||
outer_specs.width = specs.width;
|
||||
outer_specs.copy_fill_from(specs);
|
||||
outer_specs.set_align(specs.align());
|
||||
|
||||
specs.width = 0;
|
||||
specs.set_fill({});
|
||||
specs.set_align(align::none);
|
||||
|
||||
do_format(c, specs, ctx, basic_appender<Char>(buf));
|
||||
return detail::write<Char>(ctx.out(),
|
||||
basic_string_view<Char>(buf.data(), buf.size()),
|
||||
outer_specs);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::reference_wrapper<T>, Char,
|
||||
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
|
||||
: formatter<remove_cvref_t<T>, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
#endif // FMT_STD_H_
|
||||
373
include/fmt/xchar.h
Normal file
373
include/fmt/xchar.h
Normal file
@@ -0,0 +1,373 @@
|
||||
// Formatting library for C++ - optional wchar_t and exotic character support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_XCHAR_H_
|
||||
#define FMT_XCHAR_H_
|
||||
|
||||
#include "color.h"
|
||||
#include "format.h"
|
||||
#include "ostream.h"
|
||||
#include "ranges.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <cwchar>
|
||||
# if FMT_USE_LOCALE
|
||||
# include <locale>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
|
||||
|
||||
template <typename S, typename = void> struct format_string_char {};
|
||||
|
||||
template <typename S>
|
||||
struct format_string_char<
|
||||
S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> {
|
||||
using type = char_t<S>;
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
struct format_string_char<
|
||||
S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> {
|
||||
using type = typename S::char_type;
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
using format_string_char_t = typename format_string_char<S>::type;
|
||||
|
||||
inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
|
||||
const format_specs& specs, locale_ref loc) -> bool {
|
||||
#if FMT_USE_LOCALE
|
||||
auto& numpunct =
|
||||
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
|
||||
auto separator = std::wstring();
|
||||
auto grouping = numpunct.grouping();
|
||||
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
|
||||
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
using wstring_view = basic_string_view<wchar_t>;
|
||||
using wformat_parse_context = parse_context<wchar_t>;
|
||||
using wformat_context = buffered_context<wchar_t>;
|
||||
using wformat_args = basic_format_args<wformat_context>;
|
||||
using wmemory_buffer = basic_memory_buffer<wchar_t>;
|
||||
|
||||
template <typename Char, typename... T> struct basic_fstring {
|
||||
private:
|
||||
basic_string_view<Char> str_;
|
||||
|
||||
static constexpr int num_static_named_args =
|
||||
detail::count_static_named_args<T...>();
|
||||
|
||||
using checker = detail::format_string_checker<
|
||||
Char, static_cast<int>(sizeof...(T)), num_static_named_args,
|
||||
num_static_named_args != detail::count_named_args<T...>()>;
|
||||
|
||||
using arg_pack = detail::arg_pack<T...>;
|
||||
|
||||
public:
|
||||
using t = basic_fstring;
|
||||
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(
|
||||
std::is_convertible<const S&, basic_string_view<Char>>::value)>
|
||||
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) {
|
||||
if (FMT_USE_CONSTEVAL)
|
||||
detail::parse_format_string<Char>(s, checker(s, arg_pack()));
|
||||
}
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
|
||||
std::is_same<typename S::char_type, Char>::value)>
|
||||
FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) {
|
||||
FMT_CONSTEXPR auto sv = basic_string_view<Char>(S());
|
||||
FMT_CONSTEXPR int ignore =
|
||||
(parse_format_string(sv, checker(sv, arg_pack())), 0);
|
||||
detail::ignore_unused(ignore);
|
||||
}
|
||||
basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {}
|
||||
|
||||
operator basic_string_view<Char>() const { return str_; }
|
||||
auto get() const -> basic_string_view<Char> { return str_; }
|
||||
};
|
||||
|
||||
template <typename Char, typename... T>
|
||||
using basic_format_string = basic_fstring<Char, T...>;
|
||||
|
||||
template <typename... T>
|
||||
using wformat_string = typename basic_format_string<wchar_t, T...>::t;
|
||||
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
|
||||
return {{s}};
|
||||
}
|
||||
|
||||
template <> struct is_char<wchar_t> : std::true_type {};
|
||||
template <> struct is_char<char16_t> : std::true_type {};
|
||||
template <> struct is_char<char32_t> : std::true_type {};
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {};
|
||||
#endif
|
||||
|
||||
template <typename... T>
|
||||
constexpr auto make_wformat_args(T&... args)
|
||||
-> decltype(fmt::make_format_args<wformat_context>(args...)) {
|
||||
return fmt::make_format_args<wformat_context>(args...);
|
||||
}
|
||||
|
||||
#if !FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
inline namespace literals {
|
||||
inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> {
|
||||
return {s};
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
template <typename It, typename Sentinel>
|
||||
auto join(It begin, Sentinel end, wstring_view sep)
|
||||
-> join_view<It, Sentinel, wchar_t> {
|
||||
return {begin, end, sep};
|
||||
}
|
||||
|
||||
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
|
||||
auto join(Range&& range, wstring_view sep)
|
||||
-> join_view<decltype(std::begin(range)), decltype(std::end(range)),
|
||||
wchar_t> {
|
||||
return join(std::begin(range), std::end(range), sep);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto join(std::initializer_list<T> list, wstring_view sep)
|
||||
-> join_view<const T*, const T*, wchar_t> {
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
|
||||
auto join(const Tuple& tuple, basic_string_view<wchar_t> sep)
|
||||
-> tuple_join_view<wchar_t, Tuple> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
auto vformat(basic_string_view<Char> fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buf, fmt, args);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
|
||||
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename... T>
|
||||
auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args)
|
||||
-> OutputIt {
|
||||
return vformat_to(out, fmt::wstring_view(fmt),
|
||||
fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
// Pass char_t as a default template parameter instead of using
|
||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||
template <typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
|
||||
!std::is_same<Char, wchar_t>::value)>
|
||||
auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
|
||||
return vformat(detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename Locale, typename S,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat(const Locale& loc, const S& fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt), args,
|
||||
detail::locale_ref(loc));
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
template <typename Locale, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto format(const Locale& loc, const S& fmt, T&&... args)
|
||||
-> std::basic_string<Char> {
|
||||
return vformat(loc, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
auto vformat_to(OutputIt out, const S& fmt,
|
||||
typename detail::vformat_args<Char>::type args) -> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt), args);
|
||||
return detail::get_iterator(buf, out);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
|
||||
!std::is_same<Char, char>::value &&
|
||||
!std::is_same<Char, wchar_t>::value)>
|
||||
inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
|
||||
return vformat_to(out, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_locale<Locale>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
-> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc));
|
||||
return detail::get_iterator(buf, out);
|
||||
}
|
||||
|
||||
template <typename Locale, typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
bool enable = detail::is_output_iterator<OutputIt, Char>::value &&
|
||||
detail::is_locale<Locale>::value &&
|
||||
detail::is_exotic_char<Char>::value>
|
||||
inline auto format_to(OutputIt out, const Locale& loc, const S& fmt,
|
||||
T&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
return vformat_to(out, loc, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
using traits = detail::fixed_buffer_traits;
|
||||
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
|
||||
detail::vformat_to(buf, fmt, args);
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
|
||||
auto buf = detail::counting_buffer<Char>();
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
return buf.count();
|
||||
}
|
||||
|
||||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
||||
auto buf = wmemory_buffer();
|
||||
detail::vformat_to(buf, fmt, args);
|
||||
buf.push_back(L'\0');
|
||||
if (std::fputws(buf.data(), f) == -1)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
inline void vprint(wstring_view fmt, wformat_args args) {
|
||||
vprint(stdout, fmt, args);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
||||
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
|
||||
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args)
|
||||
-> std::wstring {
|
||||
auto buf = wmemory_buffer();
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
inline auto format(const text_style& ts, wformat_string<T...> fmt, T&&... args)
|
||||
-> std::wstring {
|
||||
return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED void print(std::FILE* f, const text_style& ts,
|
||||
wformat_string<T...> fmt, const T&... args) {
|
||||
vprint(f, ts, fmt, fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt,
|
||||
const T&... args) {
|
||||
return print(stdout, ts, fmt, args...);
|
||||
}
|
||||
|
||||
inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) {
|
||||
auto buffer = basic_memory_buffer<wchar_t>();
|
||||
detail::vformat_to(buffer, fmt, args);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
|
||||
vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
|
||||
print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
/// Converts `value` to `std::wstring` using the default format for type `T`.
|
||||
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
|
||||
return format(FMT_STRING(L"{}"), value);
|
||||
}
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_XCHAR_H_
|
||||
237
posix.cc
237
posix.cc
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
A C++ interface to POSIX functions.
|
||||
|
||||
Copyright (c) 2014, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#include "posix.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
|
||||
# define O_CREAT _O_CREAT
|
||||
# define O_TRUNC _O_TRUNC
|
||||
|
||||
#ifndef S_IRUSR
|
||||
# define S_IRUSR _S_IREAD
|
||||
#endif
|
||||
|
||||
#ifndef S_IWUSR
|
||||
# define S_IWUSR _S_IWRITE
|
||||
#endif
|
||||
|
||||
# ifdef __MINGW32__
|
||||
# define _SH_DENYNO 0x40
|
||||
# endif
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
namespace {
|
||||
#ifdef _WIN32
|
||||
// Return type of read and write functions.
|
||||
typedef int RWResult;
|
||||
|
||||
// On Windows the count argument to read and write is unsigned, so convert
|
||||
// it from size_t preventing integer overflow.
|
||||
inline unsigned convert_rwcount(std::size_t count) {
|
||||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
||||
}
|
||||
#else
|
||||
// Return type of read and write functions.
|
||||
typedef ssize_t RWResult;
|
||||
|
||||
inline std::size_t convert_rwcount(std::size_t count) { return count; }
|
||||
#endif
|
||||
}
|
||||
|
||||
fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT(true) {
|
||||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
||||
fmt::report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
fmt::BufferedFile::BufferedFile(fmt::StringRef filename, fmt::StringRef mode) {
|
||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
|
||||
if (!file_)
|
||||
throw SystemError(errno, "cannot open file {}", filename);
|
||||
}
|
||||
|
||||
void fmt::BufferedFile::close() {
|
||||
if (!file_)
|
||||
return;
|
||||
int result = FMT_SYSTEM(fclose(file_));
|
||||
file_ = 0;
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot close file");
|
||||
}
|
||||
|
||||
int fmt::BufferedFile::fileno() const {
|
||||
int fd = FMT_POSIX_CALL(fileno(file_));
|
||||
if (fd == -1)
|
||||
throw SystemError(errno, "cannot get file descriptor");
|
||||
return fd;
|
||||
}
|
||||
|
||||
fmt::File::File(fmt::StringRef path, int oflag) {
|
||||
int mode = S_IRUSR | S_IWUSR;
|
||||
#ifdef _WIN32
|
||||
fd_ = -1;
|
||||
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
||||
#else
|
||||
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
|
||||
#endif
|
||||
if (fd_ == -1)
|
||||
throw SystemError(errno, "cannot open file {}", path);
|
||||
}
|
||||
|
||||
fmt::File::~File() FMT_NOEXCEPT(true) {
|
||||
// Don't retry close in case of EINTR!
|
||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
||||
fmt::report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
void fmt::File::close() {
|
||||
if (fd_ == -1)
|
||||
return;
|
||||
// Don't retry close in case of EINTR!
|
||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
int result = FMT_POSIX_CALL(close(fd_));
|
||||
fd_ = -1;
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot close file");
|
||||
}
|
||||
|
||||
fmt::LongLong fmt::File::size() const {
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER size = {};
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
|
||||
if (!FMT_SYSTEM(GetFileSizeEx(handle, &size)))
|
||||
throw WindowsError(GetLastError(), "cannot get file size");
|
||||
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(size.QuadPart),
|
||||
"return type of File::size is not large enough");
|
||||
return size.QuadPart;
|
||||
#else
|
||||
typedef struct stat Stat;
|
||||
Stat file_stat = Stat();
|
||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||
throw SystemError(errno, "cannot get file attributes");
|
||||
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
|
||||
"return type of File::size is not large enough");
|
||||
return file_stat.st_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::size_t fmt::File::read(void *buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
throw SystemError(errno, "cannot read from file");
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
throw SystemError(errno, "cannot write to file");
|
||||
return result;
|
||||
}
|
||||
|
||||
fmt::File fmt::File::dup(int fd) {
|
||||
// Don't retry as dup doesn't return EINTR.
|
||||
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
||||
int new_fd = FMT_POSIX_CALL(dup(fd));
|
||||
if (new_fd == -1)
|
||||
throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
|
||||
return File(new_fd);
|
||||
}
|
||||
|
||||
void fmt::File::dup2(int fd) {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) {
|
||||
throw SystemError(errno,
|
||||
"cannot duplicate file descriptor {} to {}", fd_, fd);
|
||||
}
|
||||
}
|
||||
|
||||
void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true) {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1)
|
||||
ec = ErrorCode(errno);
|
||||
}
|
||||
|
||||
void fmt::File::pipe(File &read_end, File &write_end) {
|
||||
// Close the descriptors first to make sure that assignments don't throw
|
||||
// and there are no leaks.
|
||||
read_end.close();
|
||||
write_end.close();
|
||||
int fds[2] = {};
|
||||
#ifdef _WIN32
|
||||
// Make the default pipe capacity same as on Linux 2.6.11+.
|
||||
enum { DEFAULT_CAPACITY = 65536 };
|
||||
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
|
||||
#else
|
||||
// Don't retry as the pipe function doesn't return EINTR.
|
||||
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
||||
int result = FMT_POSIX_CALL(pipe(fds));
|
||||
#endif
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot create pipe");
|
||||
// The following assignments don't throw because read_fd and write_fd
|
||||
// are closed.
|
||||
read_end = File(fds[0]);
|
||||
write_end = File(fds[1]);
|
||||
}
|
||||
|
||||
fmt::BufferedFile fmt::File::fdopen(const char *mode) {
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||
if (!f)
|
||||
throw SystemError(errno, "cannot associate stream with file descriptor");
|
||||
BufferedFile file(f);
|
||||
fd_ = -1;
|
||||
return file;
|
||||
}
|
||||
|
||||
long fmt::getpagesize() {
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO si = {};
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
#else
|
||||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
||||
if (size < 0)
|
||||
throw SystemError(errno, "cannot get memory page size");
|
||||
return size;
|
||||
#endif
|
||||
}
|
||||
336
posix.h
336
posix.h
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
A C++ interface to POSIX functions.
|
||||
|
||||
Copyright (c) 2014, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 FMT_POSIX_H_
|
||||
#define FMT_POSIX_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> // for O_RDONLY
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifdef FMT_INCLUDE_POSIX_TEST
|
||||
# include "test/posix-test.h"
|
||||
#endif
|
||||
|
||||
#ifndef FMT_POSIX
|
||||
# ifdef _WIN32
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX(call) _##call
|
||||
# else
|
||||
# define FMT_POSIX(call) call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
||||
#ifdef FMT_SYSTEM
|
||||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
||||
#else
|
||||
# define FMT_SYSTEM(call) call
|
||||
# ifdef _WIN32
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX_CALL(call) ::_##call
|
||||
# else
|
||||
# define FMT_POSIX_CALL(call) ::call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_GCC_VERSION >= 407
|
||||
# define FMT_UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define FMT_UNUSED
|
||||
#endif
|
||||
|
||||
#if FMT_USE_STATIC_ASSERT
|
||||
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
|
||||
#else
|
||||
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
|
||||
# define FMT_STATIC_ASSERT(cond, message) \
|
||||
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
|
||||
#endif
|
||||
|
||||
// Retries the expression while it evaluates to error_result and errno
|
||||
// equals to EINTR.
|
||||
#ifndef _WIN32
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||
do { \
|
||||
result = (expression); \
|
||||
} while (result == error_result && errno == EINTR)
|
||||
#else
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||
#endif
|
||||
|
||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||
|
||||
namespace fmt {
|
||||
|
||||
// An error code.
|
||||
class ErrorCode {
|
||||
private:
|
||||
int value_;
|
||||
|
||||
public:
|
||||
explicit ErrorCode(int value = 0) FMT_NOEXCEPT(true) : value_(value) {}
|
||||
|
||||
int get() const FMT_NOEXCEPT(true) { return value_; }
|
||||
};
|
||||
|
||||
// A buffered file.
|
||||
class BufferedFile {
|
||||
private:
|
||||
FILE *file_;
|
||||
|
||||
friend class File;
|
||||
|
||||
explicit BufferedFile(FILE *f) : file_(f) {}
|
||||
|
||||
public:
|
||||
// Constructs a BufferedFile object which doesn't represent any file.
|
||||
BufferedFile() FMT_NOEXCEPT(true) : file_(0) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~BufferedFile() FMT_NOEXCEPT(true);
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
// Emulate a move constructor and a move assignment operator if rvalue
|
||||
// references are not supported.
|
||||
|
||||
private:
|
||||
// A proxy object to emulate a move constructor.
|
||||
// It is private to make it impossible call operator Proxy directly.
|
||||
struct Proxy {
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
public:
|
||||
// A "move constructor" for moving from a temporary.
|
||||
BufferedFile(Proxy p) FMT_NOEXCEPT(true) : file_(p.file) {}
|
||||
|
||||
// A "move constructor" for for moving from an lvalue.
|
||||
BufferedFile(BufferedFile &f) FMT_NOEXCEPT(true) : file_(f.file_) {
|
||||
f.file_ = 0;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from a temporary.
|
||||
BufferedFile &operator=(Proxy p) {
|
||||
close();
|
||||
file_ = p.file;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from an lvalue.
|
||||
BufferedFile &operator=(BufferedFile &other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns a proxy object for moving from a temporary:
|
||||
// BufferedFile file = BufferedFile(...);
|
||||
operator Proxy() FMT_NOEXCEPT(true) {
|
||||
Proxy p = {file_};
|
||||
file_ = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
#else
|
||||
private:
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
|
||||
|
||||
public:
|
||||
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT(true) : file_(other.file_) {
|
||||
other.file_ = 0;
|
||||
}
|
||||
|
||||
BufferedFile& operator=(BufferedFile &&other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = 0;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Opens a file.
|
||||
BufferedFile(fmt::StringRef filename, fmt::StringRef mode);
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
|
||||
// Returns the pointer to a FILE object representing this file.
|
||||
FILE *get() const { return file_; }
|
||||
|
||||
int fileno() const;
|
||||
|
||||
void print(fmt::StringRef format_str, const ArgList &args) {
|
||||
fmt::print(file_, format_str, args);
|
||||
}
|
||||
FMT_VARIADIC(void, print, fmt::StringRef)
|
||||
};
|
||||
|
||||
// A file. Closed file is represented by a File object with descriptor -1.
|
||||
// Methods that are not declared with FMT_NOEXCEPT(true) may throw
|
||||
// fmt::SystemError in case of failure. Note that some errors such as
|
||||
// closing the file multiple times will cause a crash on Windows rather
|
||||
// than an exception. You can get standard behavior by overriding the
|
||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||
class File {
|
||||
private:
|
||||
int fd_; // File descriptor.
|
||||
|
||||
// Constructs a File object with a given descriptor.
|
||||
explicit File(int fd) : fd_(fd) {}
|
||||
|
||||
public:
|
||||
// Possible values for the oflag argument to the constructor.
|
||||
enum {
|
||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
||||
};
|
||||
|
||||
// Constructs a File object which doesn't represent any file.
|
||||
File() FMT_NOEXCEPT(true) : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a File object representing this file.
|
||||
File(fmt::StringRef path, int oflag);
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
// Emulate a move constructor and a move assignment operator if rvalue
|
||||
// references are not supported.
|
||||
|
||||
private:
|
||||
// A proxy object to emulate a move constructor.
|
||||
// It is private to make it impossible call operator Proxy directly.
|
||||
struct Proxy {
|
||||
int fd;
|
||||
};
|
||||
|
||||
public:
|
||||
// A "move constructor" for moving from a temporary.
|
||||
File(Proxy p) FMT_NOEXCEPT(true) : fd_(p.fd) {}
|
||||
|
||||
// A "move constructor" for for moving from an lvalue.
|
||||
File(File &other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
|
||||
other.fd_ = -1;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from a temporary.
|
||||
File &operator=(Proxy p) {
|
||||
close();
|
||||
fd_ = p.fd;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from an lvalue.
|
||||
File &operator=(File &other) {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns a proxy object for moving from a temporary:
|
||||
// File file = File(...);
|
||||
operator Proxy() FMT_NOEXCEPT(true) {
|
||||
Proxy p = {fd_};
|
||||
fd_ = -1;
|
||||
return p;
|
||||
}
|
||||
|
||||
#else
|
||||
private:
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(File);
|
||||
|
||||
public:
|
||||
File(File &&other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
|
||||
other.fd_ = -1;
|
||||
}
|
||||
|
||||
File& operator=(File &&other) {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~File() FMT_NOEXCEPT(true);
|
||||
|
||||
// Returns the file descriptor.
|
||||
int descriptor() const FMT_NOEXCEPT(true) { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
|
||||
// Returns the file size.
|
||||
fmt::LongLong size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
std::size_t read(void *buffer, std::size_t count);
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
std::size_t write(const void *buffer, std::size_t count);
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
static File dup(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true);
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
static void pipe(File &read_end, File &write_end);
|
||||
|
||||
// Creates a BufferedFile object associated with this file and detaches
|
||||
// this File object from the file.
|
||||
BufferedFile fdopen(const char *mode);
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
long getpagesize();
|
||||
} // namespace fmt
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
namespace std {
|
||||
// For compatibility with C++98.
|
||||
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
|
||||
inline fmt::File &move(fmt::File &f) { return f; }
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // FMT_POSIX_H_
|
||||
153
src/fmt.cc
Normal file
153
src/fmt.cc
Normal file
@@ -0,0 +1,153 @@
|
||||
module;
|
||||
|
||||
#define FMT_MODULE
|
||||
|
||||
#ifdef _MSVC_LANG
|
||||
# define FMT_CPLUSPLUS _MSVC_LANG
|
||||
#else
|
||||
# define FMT_CPLUSPLUS __cplusplus
|
||||
#endif
|
||||
|
||||
// Put all implementation-provided headers into the global module fragment
|
||||
// to prevent attachment to this module.
|
||||
#ifndef FMT_IMPORT_STD
|
||||
# include <algorithm>
|
||||
# include <bitset>
|
||||
# include <chrono>
|
||||
# include <cmath>
|
||||
# include <complex>
|
||||
# include <cstddef>
|
||||
# include <cstdint>
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
# include <ctime>
|
||||
# include <exception>
|
||||
# if FMT_CPLUSPLUS > 202002L
|
||||
# include <expected>
|
||||
# endif
|
||||
# include <filesystem>
|
||||
# include <fstream>
|
||||
# include <functional>
|
||||
# include <iterator>
|
||||
# include <limits>
|
||||
# include <locale>
|
||||
# include <memory>
|
||||
# include <optional>
|
||||
# include <ostream>
|
||||
# include <source_location>
|
||||
# include <stdexcept>
|
||||
# include <string>
|
||||
# include <string_view>
|
||||
# include <system_error>
|
||||
# include <thread>
|
||||
# include <type_traits>
|
||||
# include <typeinfo>
|
||||
# include <utility>
|
||||
# include <variant>
|
||||
# include <vector>
|
||||
#else
|
||||
# include <limits.h>
|
||||
# include <stdint.h>
|
||||
# include <stdio.h>
|
||||
# include <time.h>
|
||||
#endif
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <version>
|
||||
|
||||
#if __has_include(<cxxabi.h>)
|
||||
# include <cxxabi.h>
|
||||
#endif
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||
# include <xlocale.h>
|
||||
#endif
|
||||
#if __has_include(<winapifamily.h>)
|
||||
# include <winapifamily.h>
|
||||
#endif
|
||||
#if (__has_include(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||
# include <fcntl.h>
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# else
|
||||
# include <io.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
# if defined(__GLIBCXX__)
|
||||
# include <ext/stdio_filebuf.h>
|
||||
# include <ext/stdio_sync_filebuf.h>
|
||||
# endif
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
export module fmt;
|
||||
|
||||
#ifdef FMT_IMPORT_STD
|
||||
import std;
|
||||
#endif
|
||||
|
||||
#define FMT_EXPORT export
|
||||
#define FMT_BEGIN_EXPORT export {
|
||||
#define FMT_END_EXPORT }
|
||||
|
||||
// If you define FMT_ATTACH_TO_GLOBAL_MODULE
|
||||
// - all declarations are detached from module 'fmt'
|
||||
// - the module behaves like a traditional static library, too
|
||||
// - all library symbols are mangled traditionally
|
||||
// - you can mix TUs with either importing or #including the {fmt} API
|
||||
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
|
||||
extern "C++" {
|
||||
#endif
|
||||
|
||||
#ifndef FMT_OS
|
||||
# define FMT_OS 1
|
||||
#endif
|
||||
|
||||
// All library-provided declarations and definitions must be in the module
|
||||
// purview to be exported.
|
||||
#include "fmt/args.h"
|
||||
#include "fmt/chrono.h"
|
||||
#include "fmt/color.h"
|
||||
#include "fmt/compile.h"
|
||||
#include "fmt/format.h"
|
||||
#if FMT_OS
|
||||
# include "fmt/os.h"
|
||||
#endif
|
||||
#include "fmt/ostream.h"
|
||||
#include "fmt/printf.h"
|
||||
#include "fmt/ranges.h"
|
||||
#include "fmt/std.h"
|
||||
#include "fmt/xchar.h"
|
||||
|
||||
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
|
||||
}
|
||||
#endif
|
||||
|
||||
// gcc doesn't yet implement private module fragments
|
||||
#if !FMT_GCC_VERSION
|
||||
module :private;
|
||||
#endif
|
||||
|
||||
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
|
||||
extern "C++" {
|
||||
#endif
|
||||
|
||||
#if FMT_HAS_INCLUDE("format.cc")
|
||||
# include "format.cc"
|
||||
#endif
|
||||
#if FMT_OS && FMT_HAS_INCLUDE("os.cc")
|
||||
# include "os.cc"
|
||||
#endif
|
||||
|
||||
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
|
||||
}
|
||||
#endif
|
||||
46
src/format.cc
Normal file
46
src/format.cc
Normal file
@@ -0,0 +1,46 @@
|
||||
// Formatting library for C++
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/format-inl.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template FMT_API auto dragonbox::to_decimal(float x) noexcept
|
||||
-> dragonbox::decimal_fp<float>;
|
||||
template FMT_API auto dragonbox::to_decimal(double x) noexcept
|
||||
-> dragonbox::decimal_fp<double>;
|
||||
|
||||
#if FMT_USE_LOCALE
|
||||
// DEPRECATED! locale_ref in the detail namespace
|
||||
template FMT_API locale_ref::locale_ref(const std::locale& loc);
|
||||
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
|
||||
#endif
|
||||
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<char>;
|
||||
template FMT_API auto decimal_point_impl(locale_ref) -> char;
|
||||
|
||||
// DEPRECATED!
|
||||
template FMT_API void buffer<char>::append(const char*, const char*);
|
||||
|
||||
// DEPRECATED!
|
||||
template FMT_API void vformat_to(buffer<char>&, string_view,
|
||||
typename vformat_args<>::type, locale_ref);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<wchar_t>;
|
||||
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
||||
|
||||
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
|
||||
|
||||
} // namespace detail
|
||||
FMT_END_NAMESPACE
|
||||
398
src/os.cc
Normal file
398
src/os.cc
Normal file
@@ -0,0 +1,398 @@
|
||||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
// Disable bogus MSVC warnings.
|
||||
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "fmt/os.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <climits>
|
||||
|
||||
# if FMT_USE_FCNTL
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
|
||||
# ifdef _WRS_KERNEL // VxWorks7 kernel
|
||||
# include <ioLib.h> // getpagesize
|
||||
# endif
|
||||
|
||||
# ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# else
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <io.h>
|
||||
# endif // _WIN32
|
||||
# endif // FMT_USE_FCNTL
|
||||
|
||||
# ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef S_IRUSR
|
||||
# define S_IRUSR _S_IREAD
|
||||
# endif
|
||||
# ifndef S_IWUSR
|
||||
# define S_IWUSR _S_IWRITE
|
||||
# endif
|
||||
# ifndef S_IRGRP
|
||||
# define S_IRGRP 0
|
||||
# endif
|
||||
# ifndef S_IWGRP
|
||||
# define S_IWGRP 0
|
||||
# endif
|
||||
# ifndef S_IROTH
|
||||
# define S_IROTH 0
|
||||
# endif
|
||||
# ifndef S_IWOTH
|
||||
# define S_IWOTH 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
#ifdef _WIN32
|
||||
// Return type of read and write functions.
|
||||
using rwresult = int;
|
||||
|
||||
// On Windows the count argument to read and write is unsigned, so convert
|
||||
// it from size_t preventing integer overflow.
|
||||
inline unsigned convert_rwcount(std::size_t count) {
|
||||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
||||
}
|
||||
#elif FMT_USE_FCNTL
|
||||
// Return type of read and write functions.
|
||||
using rwresult = ssize_t;
|
||||
|
||||
inline std::size_t convert_rwcount(std::size_t count) { return count; }
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace detail {
|
||||
|
||||
class system_message {
|
||||
system_message(const system_message&) = delete;
|
||||
void operator=(const system_message&) = delete;
|
||||
|
||||
unsigned long result_;
|
||||
wchar_t* message_;
|
||||
|
||||
static bool is_whitespace(wchar_t c) noexcept {
|
||||
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
||||
}
|
||||
|
||||
public:
|
||||
explicit system_message(unsigned long error_code)
|
||||
: result_(0), message_(nullptr) {
|
||||
result_ = FormatMessageW(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<wchar_t*>(&message_), 0, nullptr);
|
||||
if (result_ != 0) {
|
||||
while (result_ != 0 && is_whitespace(message_[result_ - 1])) {
|
||||
--result_;
|
||||
}
|
||||
}
|
||||
}
|
||||
~system_message() { LocalFree(message_); }
|
||||
explicit operator bool() const noexcept { return result_ != 0; }
|
||||
operator basic_string_view<wchar_t>() const noexcept {
|
||||
return basic_string_view<wchar_t>(message_, result_);
|
||||
}
|
||||
};
|
||||
|
||||
class utf8_system_category final : public std::error_category {
|
||||
public:
|
||||
const char* name() const noexcept override { return "system"; }
|
||||
std::string message(int error_code) const override {
|
||||
auto&& msg = system_message(error_code);
|
||||
if (msg) {
|
||||
auto utf8_message = to_utf8<wchar_t>();
|
||||
if (utf8_message.convert(msg)) {
|
||||
return utf8_message.str();
|
||||
}
|
||||
}
|
||||
return "unknown error";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_API const std::error_category& system_category() noexcept {
|
||||
static const detail::utf8_system_category category;
|
||||
return category;
|
||||
}
|
||||
|
||||
std::system_error vwindows_error(int err_code, string_view format_str,
|
||||
format_args args) {
|
||||
auto ec = std::error_code(err_code, system_category());
|
||||
return std::system_error(ec, vformat(format_str, args));
|
||||
}
|
||||
|
||||
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
||||
const char* message) noexcept {
|
||||
FMT_TRY {
|
||||
auto&& msg = system_message(error_code);
|
||||
if (msg) {
|
||||
auto utf8_message = to_utf8<wchar_t>();
|
||||
if (utf8_message.convert(msg)) {
|
||||
fmt::format_to(appender(out), FMT_STRING("{}: {}"), message,
|
||||
string_view(utf8_message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
void report_windows_error(int error_code, const char* message) noexcept {
|
||||
do_report_error(detail::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
buffered_file::~buffered_file() noexcept {
|
||||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
||||
report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
|
||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
|
||||
nullptr);
|
||||
if (!file_)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"),
|
||||
filename.c_str()));
|
||||
}
|
||||
|
||||
void buffered_file::close() {
|
||||
if (!file_) return;
|
||||
int result = FMT_SYSTEM(fclose(file_));
|
||||
file_ = nullptr;
|
||||
if (result != 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
|
||||
}
|
||||
|
||||
int buffered_file::descriptor() const {
|
||||
#ifdef FMT_HAS_SYSTEM
|
||||
// fileno is a macro on OpenBSD.
|
||||
# ifdef fileno
|
||||
# undef fileno
|
||||
# endif
|
||||
int fd = FMT_POSIX_CALL(fileno(file_));
|
||||
#elif defined(_WIN32)
|
||||
int fd = _fileno(file_);
|
||||
#else
|
||||
int fd = fileno(file_);
|
||||
#endif
|
||||
if (fd == -1)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor")));
|
||||
return fd;
|
||||
}
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
# ifdef _WIN32
|
||||
using mode_t = int;
|
||||
# endif
|
||||
|
||||
constexpr mode_t default_open_mode =
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
|
||||
file::file(cstring_view path, int oflag) {
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
fd_ = -1;
|
||||
auto converted = detail::utf8_to_utf16(string_view(path.c_str()));
|
||||
*this = file::open_windows_file(converted.c_str(), oflag);
|
||||
# else
|
||||
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode)));
|
||||
if (fd_ == -1)
|
||||
FMT_THROW(
|
||||
system_error(errno, FMT_STRING("cannot open file {}"), path.c_str()));
|
||||
# endif
|
||||
}
|
||||
|
||||
file::~file() noexcept {
|
||||
// Don't retry close in case of EINTR!
|
||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
||||
report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
void file::close() {
|
||||
if (fd_ == -1) return;
|
||||
// Don't retry close in case of EINTR!
|
||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
int result = FMT_POSIX_CALL(close(fd_));
|
||||
fd_ = -1;
|
||||
if (result != 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
|
||||
}
|
||||
|
||||
long long file::size() const {
|
||||
# ifdef _WIN32
|
||||
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
|
||||
// is less than 0x0500 as is the case with some default MinGW builds.
|
||||
// Both functions support large file sizes.
|
||||
DWORD size_upper = 0;
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
|
||||
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
|
||||
if (size_lower == INVALID_FILE_SIZE) {
|
||||
DWORD error = GetLastError();
|
||||
if (error != NO_ERROR)
|
||||
FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
|
||||
}
|
||||
unsigned long long long_size = size_upper;
|
||||
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
||||
# else
|
||||
using Stat = struct stat;
|
||||
Stat file_stat = Stat();
|
||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes")));
|
||||
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
||||
"return type of file::size is not large enough");
|
||||
return file_stat.st_size;
|
||||
# endif
|
||||
}
|
||||
|
||||
std::size_t file::read(void* buffer, std::size_t count) {
|
||||
rwresult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot read from file")));
|
||||
return detail::to_unsigned(result);
|
||||
}
|
||||
|
||||
std::size_t file::write(const void* buffer, std::size_t count) {
|
||||
rwresult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
return detail::to_unsigned(result);
|
||||
}
|
||||
|
||||
file file::dup(int fd) {
|
||||
// Don't retry as dup doesn't return EINTR.
|
||||
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
||||
int new_fd = FMT_POSIX_CALL(dup(fd));
|
||||
if (new_fd == -1)
|
||||
FMT_THROW(system_error(
|
||||
errno, FMT_STRING("cannot duplicate file descriptor {}"), fd));
|
||||
return file(new_fd);
|
||||
}
|
||||
|
||||
void file::dup2(int fd) {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) {
|
||||
FMT_THROW(system_error(
|
||||
errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_,
|
||||
fd));
|
||||
}
|
||||
}
|
||||
|
||||
void file::dup2(int fd, std::error_code& ec) noexcept {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
||||
}
|
||||
|
||||
buffered_file file::fdopen(const char* mode) {
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
# if defined(__MINGW32__) && defined(_POSIX_)
|
||||
FILE* f = ::fdopen(fd_, mode);
|
||||
# else
|
||||
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||
# endif
|
||||
if (!f) {
|
||||
FMT_THROW(system_error(
|
||||
errno, FMT_STRING("cannot associate stream with file descriptor")));
|
||||
}
|
||||
buffered_file bf(f);
|
||||
fd_ = -1;
|
||||
return bf;
|
||||
}
|
||||
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
file file::open_windows_file(wcstring_view path, int oflag) {
|
||||
int fd = -1;
|
||||
auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode);
|
||||
if (fd == -1) {
|
||||
FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"),
|
||||
detail::to_utf8<wchar_t>(path.c_str()).c_str()));
|
||||
}
|
||||
return file(fd);
|
||||
}
|
||||
# endif
|
||||
|
||||
pipe::pipe() {
|
||||
int fds[2] = {};
|
||||
# ifdef _WIN32
|
||||
// Make the default pipe capacity same as on Linux 2.6.11+.
|
||||
enum { DEFAULT_CAPACITY = 65536 };
|
||||
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
|
||||
# else
|
||||
// Don't retry as the pipe function doesn't return EINTR.
|
||||
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
||||
int result = FMT_POSIX_CALL(pipe(fds));
|
||||
# endif
|
||||
if (result != 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe")));
|
||||
// The following assignments don't throw.
|
||||
read_end = file(fds[0]);
|
||||
write_end = file(fds[1]);
|
||||
}
|
||||
|
||||
# if !defined(__MSDOS__)
|
||||
long getpagesize() {
|
||||
# ifdef _WIN32
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
# else
|
||||
# ifdef _WRS_KERNEL
|
||||
long size = FMT_POSIX_CALL(getpagesize());
|
||||
# else
|
||||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
||||
# endif
|
||||
|
||||
if (size < 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size")));
|
||||
return size;
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
|
||||
void ostream::grow(buffer<char>& buf, size_t) {
|
||||
if (buf.size() == buf.capacity()) static_cast<ostream&>(buf).flush();
|
||||
}
|
||||
|
||||
ostream::ostream(cstring_view path, const detail::ostream_params& params)
|
||||
: buffer<char>(grow), file_(path, params.oflag) {
|
||||
set(new char[params.buffer_size], params.buffer_size);
|
||||
}
|
||||
|
||||
ostream::ostream(ostream&& other) noexcept
|
||||
: buffer<char>(grow, other.data(), other.size(), other.capacity()),
|
||||
file_(std::move(other.file_)) {
|
||||
other.clear();
|
||||
other.set(nullptr, 0);
|
||||
}
|
||||
|
||||
ostream::~ostream() {
|
||||
flush();
|
||||
delete[] data();
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
FMT_END_NAMESPACE
|
||||
15
support/Android.mk
Normal file
15
support/Android.mk
Normal file
@@ -0,0 +1,15 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := fmt_static
|
||||
LOCAL_MODULE_FILENAME := libfmt
|
||||
|
||||
LOCAL_SRC_FILES := ../src/format.cc
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
|
||||
|
||||
LOCAL_CFLAGS += -std=c++11 -fexceptions
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
1
support/AndroidManifest.xml
Normal file
1
support/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest package="dev.fmt" />
|
||||
2061
support/C++.sublime-syntax
Normal file
2061
support/C++.sublime-syntax
Normal file
File diff suppressed because it is too large
Load Diff
4
support/README
Normal file
4
support/README
Normal file
@@ -0,0 +1,4 @@
|
||||
This directory contains build support files such as
|
||||
|
||||
* CMake modules
|
||||
* Build scripts
|
||||
19
support/Vagrantfile
vendored
Normal file
19
support/Vagrantfile
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# A vagrant config for testing against gcc-4.8.
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "bento/ubuntu-22.04-arm64"
|
||||
|
||||
config.vm.provider "vmware_desktop" do |vb|
|
||||
vb.memory = "4096"
|
||||
end
|
||||
|
||||
config.vm.provision "shell", inline: <<-SHELL
|
||||
apt-get update
|
||||
apt-get install -y g++ make wget git
|
||||
wget -q https://github.com/Kitware/CMake/releases/download/v3.26.0/cmake-3.26.0-Linux-x86_64.tar.gz
|
||||
tar xzf cmake-3.26.0-Linux-x86_64.tar.gz
|
||||
ln -s `pwd`/cmake-3.26.0-Linux-x86_64/bin/cmake /usr/local/bin
|
||||
SHELL
|
||||
end
|
||||
1
support/bazel/.bazelversion
Normal file
1
support/bazel/.bazelversion
Normal file
@@ -0,0 +1 @@
|
||||
7.1.2
|
||||
20
support/bazel/BUILD.bazel
Normal file
20
support/bazel/BUILD.bazel
Normal file
@@ -0,0 +1,20 @@
|
||||
cc_library(
|
||||
name = "fmt",
|
||||
srcs = [
|
||||
#"src/fmt.cc", # No C++ module support, yet in Bazel (https://github.com/bazelbuild/bazel/pull/19940)
|
||||
"src/format.cc",
|
||||
"src/os.cc",
|
||||
],
|
||||
hdrs = glob([
|
||||
"include/fmt/*.h",
|
||||
]),
|
||||
copts = select({
|
||||
"@platforms//os:windows": ["-utf-8"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
includes = [
|
||||
"include",
|
||||
],
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
6
support/bazel/MODULE.bazel
Normal file
6
support/bazel/MODULE.bazel
Normal file
@@ -0,0 +1,6 @@
|
||||
module(
|
||||
name = "fmt",
|
||||
compatibility_level = 10,
|
||||
)
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.10")
|
||||
28
support/bazel/README.md
Normal file
28
support/bazel/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Bazel support
|
||||
|
||||
To get [Bazel](https://bazel.build/) working with {fmt} you can copy the files `BUILD.bazel`,
|
||||
`MODULE.bazel`, `WORKSPACE.bazel`, and `.bazelversion` from this folder (`support/bazel`) to the root folder of this project.
|
||||
This way {fmt} gets bazelized and can be used with Bazel (e.g. doing a `bazel build //...` on {fmt}).
|
||||
|
||||
## Using {fmt} as a dependency
|
||||
|
||||
### Using Bzlmod
|
||||
|
||||
The [Bazel Central Registry](https://github.com/bazelbuild/bazel-central-registry/tree/main/modules/fmt) provides support for {fmt}.
|
||||
|
||||
For instance, to use {fmt} add to your `MODULE.bazel` file:
|
||||
|
||||
```
|
||||
bazel_dep(name = "fmt", version = "10.2.1")
|
||||
```
|
||||
|
||||
### Live at head
|
||||
|
||||
For a live-at-head approach, you can copy the contents of this repository and move the Bazel-related build files to the root folder of this project as described above and make use of `local_path_override`, e.g.:
|
||||
|
||||
```
|
||||
local_path_override(
|
||||
module_name = "fmt",
|
||||
path = "../third_party/fmt",
|
||||
)
|
||||
```
|
||||
2
support/bazel/WORKSPACE.bazel
Normal file
2
support/bazel/WORKSPACE.bazel
Normal file
@@ -0,0 +1,2 @@
|
||||
# WORKSPACE marker file needed by Bazel
|
||||
|
||||
132
support/build.gradle
Normal file
132
support/build.gradle
Normal file
@@ -0,0 +1,132 @@
|
||||
import java.nio.file.Paths
|
||||
|
||||
// General gradle arguments for root project
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
//
|
||||
// https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
|
||||
//
|
||||
// Notice that 4.0.0 here is the version of [Android Gradle Plugin]
|
||||
// According to URL above you will need Gradle 6.1 or higher
|
||||
//
|
||||
classpath "com.android.tools.build:gradle:4.1.1"
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// Project's root where CMakeLists.txt exists: rootDir/support/.cxx -> rootDir
|
||||
def rootDir = Paths.get(project.buildDir.getParent()).getParent()
|
||||
println("rootDir: ${rootDir}")
|
||||
|
||||
// Output: Shared library (.so) for Android
|
||||
apply plugin: "com.android.library"
|
||||
android {
|
||||
compileSdkVersion 25 // Android 7.0
|
||||
|
||||
// Target ABI
|
||||
// - This option controls target platform of module
|
||||
// - The platform might be limited by compiler's support
|
||||
// some can work with Clang(default), but some can work only with GCC...
|
||||
// if bad, both toolchains might not support it
|
||||
splits {
|
||||
abi {
|
||||
enable true
|
||||
// Specify platforms for Application
|
||||
reset()
|
||||
include "arm64-v8a", "armeabi-v7a", "x86_64"
|
||||
}
|
||||
}
|
||||
ndkVersion "21.3.6528147" // ANDROID_NDK_HOME is deprecated. Be explicit
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21 // Android 5.0+
|
||||
targetSdkVersion 25 // Follow Compile SDK
|
||||
versionCode 34 // Follow release count
|
||||
versionName "7.1.2" // Follow Official version
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DANDROID_STL=c++_shared" // Specify Android STL
|
||||
arguments "-DBUILD_SHARED_LIBS=true" // Build shared object
|
||||
arguments "-DFMT_TEST=false" // Skip test
|
||||
arguments "-DFMT_DOC=false" // Skip document
|
||||
cppFlags "-std=c++17"
|
||||
targets "fmt"
|
||||
}
|
||||
}
|
||||
println(externalNativeBuild.cmake.cppFlags)
|
||||
println(externalNativeBuild.cmake.arguments)
|
||||
}
|
||||
|
||||
// External Native build
|
||||
// - Use existing CMakeList.txt
|
||||
// - Give path to CMake. This gradle file should be
|
||||
// neighbor of the top level cmake
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version "3.10.0+"
|
||||
path "${rootDir}/CMakeLists.txt"
|
||||
// buildStagingDirectory "./build" // Custom path for cmake output
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets{
|
||||
// Android Manifest for Gradle
|
||||
main {
|
||||
manifest.srcFile "AndroidManifest.xml"
|
||||
}
|
||||
}
|
||||
|
||||
// https://developer.android.com/studio/build/native-dependencies#build_system_configuration
|
||||
buildFeatures {
|
||||
prefab true
|
||||
prefabPublishing true
|
||||
}
|
||||
prefab {
|
||||
fmt {
|
||||
headers "${rootDir}/include"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assemble.doLast
|
||||
{
|
||||
// Instead of `ninja install`, Gradle will deploy the files.
|
||||
// We are doing this since FMT is dependent to the ANDROID_STL after build
|
||||
copy {
|
||||
from "build/intermediates/cmake"
|
||||
into "${rootDir}/libs"
|
||||
}
|
||||
// Copy debug binaries
|
||||
copy {
|
||||
from "${rootDir}/libs/debug/obj"
|
||||
into "${rootDir}/libs/debug"
|
||||
}
|
||||
// Copy Release binaries
|
||||
copy {
|
||||
from "${rootDir}/libs/release/obj"
|
||||
into "${rootDir}/libs/release"
|
||||
}
|
||||
// Remove empty directory
|
||||
delete "${rootDir}/libs/debug/obj"
|
||||
delete "${rootDir}/libs/release/obj"
|
||||
|
||||
// Copy AAR files. Notice that the aar is named after the folder of this script.
|
||||
copy {
|
||||
from "build/outputs/aar/support-release.aar"
|
||||
into "${rootDir}/libs"
|
||||
rename "support-release.aar", "fmt-release.aar"
|
||||
}
|
||||
copy {
|
||||
from "build/outputs/aar/support-debug.aar"
|
||||
into "${rootDir}/libs"
|
||||
rename "support-debug.aar", "fmt-debug.aar"
|
||||
}
|
||||
}
|
||||
43
support/check-commits
Executable file
43
support/check-commits
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Compile source on a range of commits
|
||||
|
||||
Usage:
|
||||
check-commits <start> <source>
|
||||
"""
|
||||
|
||||
import docopt, os, sys, tempfile
|
||||
from subprocess import check_call, check_output, run
|
||||
|
||||
args = docopt.docopt(__doc__)
|
||||
start = args.get('<start>')
|
||||
source = args.get('<source>')
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
with tempfile.TemporaryDirectory() as work_dir:
|
||||
check_call(['git', 'clone', 'https://github.com/fmtlib/fmt.git'],
|
||||
cwd=work_dir)
|
||||
repo_dir = os.path.join(work_dir, 'fmt')
|
||||
commits = check_output(
|
||||
['git', 'rev-list', f'{start}..HEAD', '--abbrev-commit',
|
||||
'--', 'include', 'src'],
|
||||
text=True, cwd=repo_dir).rstrip().split('\n')
|
||||
commits.reverse()
|
||||
print('Time\tCommit')
|
||||
for commit in commits:
|
||||
check_call(['git', '-c', 'advice.detachedHead=false', 'checkout', commit],
|
||||
cwd=repo_dir)
|
||||
returncode = run(
|
||||
['c++', '-std=c++11', '-O3', '-DNDEBUG', '-I', 'include',
|
||||
'src/format.cc', os.path.join(cwd, source)], cwd=repo_dir).returncode
|
||||
if returncode != 0:
|
||||
continue
|
||||
times = []
|
||||
for i in range(5):
|
||||
output = check_output([os.path.join(repo_dir, 'a.out')], text=True)
|
||||
times.append(float(output))
|
||||
message = check_output(['git', 'log', '-1', '--pretty=format:%s', commit],
|
||||
cwd=repo_dir, text=True)
|
||||
print(f'{min(times)}\t{commit} {message[:40]}')
|
||||
sys.stdout.flush()
|
||||
26
support/cmake/JoinPaths.cmake
Normal file
26
support/cmake/JoinPaths.cmake
Normal file
@@ -0,0 +1,26 @@
|
||||
# This module provides function for joining paths
|
||||
# known from from most languages
|
||||
#
|
||||
# Original license:
|
||||
# SPDX-License-Identifier: (MIT OR CC0-1.0)
|
||||
# Explicit permission given to distribute this module under
|
||||
# the terms of the project as described in /LICENSE.rst.
|
||||
# Copyright 2020 Jan Tojnar
|
||||
# https://github.com/jtojnar/cmake-snips
|
||||
#
|
||||
# Modelled after Python’s os.path.join
|
||||
# https://docs.python.org/3.7/library/os.path.html#os.path.join
|
||||
# Windows not supported
|
||||
function(join_paths joined_path first_path_segment)
|
||||
set(temp_path "${first_path_segment}")
|
||||
foreach(current_segment IN LISTS ARGN)
|
||||
if(NOT ("${current_segment}" STREQUAL ""))
|
||||
if(IS_ABSOLUTE "${current_segment}")
|
||||
set(temp_path "${current_segment}")
|
||||
else()
|
||||
set(temp_path "${temp_path}/${current_segment}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
set(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
7
support/cmake/fmt-config.cmake.in
Normal file
7
support/cmake/fmt-config.cmake.in
Normal file
@@ -0,0 +1,7 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
if (NOT TARGET fmt::fmt)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
|
||||
endif ()
|
||||
|
||||
check_required_components(fmt)
|
||||
11
support/cmake/fmt.pc.in
Normal file
11
support/cmake/fmt.pc.in
Normal file
@@ -0,0 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@libdir_for_pc_file@
|
||||
includedir=@includedir_for_pc_file@
|
||||
|
||||
Name: fmt
|
||||
Description: A modern formatting library
|
||||
Version: @FMT_VERSION@
|
||||
Libs: -L${libdir} -l@FMT_LIB_NAME@
|
||||
Cflags: -I${includedir}
|
||||
|
||||
581
support/docopt.py
Normal file
581
support/docopt.py
Normal file
@@ -0,0 +1,581 @@
|
||||
"""Pythonic command-line interface parser that will make you smile.
|
||||
|
||||
* http://docopt.org
|
||||
* Repository and issue-tracker: https://github.com/docopt/docopt
|
||||
* Licensed under terms of MIT license (see LICENSE-MIT)
|
||||
* Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com
|
||||
|
||||
"""
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
__all__ = ['docopt']
|
||||
__version__ = '0.6.1'
|
||||
|
||||
|
||||
class DocoptLanguageError(Exception):
|
||||
|
||||
"""Error in construction of usage-message by developer."""
|
||||
|
||||
|
||||
class DocoptExit(SystemExit):
|
||||
|
||||
"""Exit in case user invoked program with incorrect arguments."""
|
||||
|
||||
usage = ''
|
||||
|
||||
def __init__(self, message=''):
|
||||
SystemExit.__init__(self, (message + '\n' + self.usage).strip())
|
||||
|
||||
|
||||
class Pattern(object):
|
||||
|
||||
def __eq__(self, other):
|
||||
return repr(self) == repr(other)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def fix(self):
|
||||
self.fix_identities()
|
||||
self.fix_repeating_arguments()
|
||||
return self
|
||||
|
||||
def fix_identities(self, uniq=None):
|
||||
"""Make pattern-tree tips point to same object if they are equal."""
|
||||
if not hasattr(self, 'children'):
|
||||
return self
|
||||
uniq = list(set(self.flat())) if uniq is None else uniq
|
||||
for i, child in enumerate(self.children):
|
||||
if not hasattr(child, 'children'):
|
||||
assert child in uniq
|
||||
self.children[i] = uniq[uniq.index(child)]
|
||||
else:
|
||||
child.fix_identities(uniq)
|
||||
|
||||
def fix_repeating_arguments(self):
|
||||
"""Fix elements that should accumulate/increment values."""
|
||||
either = [list(child.children) for child in transform(self).children]
|
||||
for case in either:
|
||||
for e in [child for child in case if case.count(child) > 1]:
|
||||
if type(e) is Argument or type(e) is Option and e.argcount:
|
||||
if e.value is None:
|
||||
e.value = []
|
||||
elif type(e.value) is not list:
|
||||
e.value = e.value.split()
|
||||
if type(e) is Command or type(e) is Option and e.argcount == 0:
|
||||
e.value = 0
|
||||
return self
|
||||
|
||||
|
||||
def transform(pattern):
|
||||
"""Expand pattern into an (almost) equivalent one, but with single Either.
|
||||
|
||||
Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
|
||||
Quirks: [-a] => (-a), (-a...) => (-a -a)
|
||||
|
||||
"""
|
||||
result = []
|
||||
groups = [[pattern]]
|
||||
while groups:
|
||||
children = groups.pop(0)
|
||||
parents = [Required, Optional, OptionsShortcut, Either, OneOrMore]
|
||||
if any(t in map(type, children) for t in parents):
|
||||
child = [c for c in children if type(c) in parents][0]
|
||||
children.remove(child)
|
||||
if type(child) is Either:
|
||||
for c in child.children:
|
||||
groups.append([c] + children)
|
||||
elif type(child) is OneOrMore:
|
||||
groups.append(child.children * 2 + children)
|
||||
else:
|
||||
groups.append(child.children + children)
|
||||
else:
|
||||
result.append(children)
|
||||
return Either(*[Required(*e) for e in result])
|
||||
|
||||
|
||||
class LeafPattern(Pattern):
|
||||
|
||||
"""Leaf/terminal node of a pattern tree."""
|
||||
|
||||
def __init__(self, name, value=None):
|
||||
self.name, self.value = name, value
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
|
||||
|
||||
def flat(self, *types):
|
||||
return [self] if not types or type(self) in types else []
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
pos, match = self.single_match(left)
|
||||
if match is None:
|
||||
return False, left, collected
|
||||
left_ = left[:pos] + left[pos + 1:]
|
||||
same_name = [a for a in collected if a.name == self.name]
|
||||
if type(self.value) in (int, list):
|
||||
if type(self.value) is int:
|
||||
increment = 1
|
||||
else:
|
||||
increment = ([match.value] if type(match.value) is str
|
||||
else match.value)
|
||||
if not same_name:
|
||||
match.value = increment
|
||||
return True, left_, collected + [match]
|
||||
same_name[0].value += increment
|
||||
return True, left_, collected
|
||||
return True, left_, collected + [match]
|
||||
|
||||
|
||||
class BranchPattern(Pattern):
|
||||
|
||||
"""Branch/inner node of a pattern tree."""
|
||||
|
||||
def __init__(self, *children):
|
||||
self.children = list(children)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (self.__class__.__name__,
|
||||
', '.join(repr(a) for a in self.children))
|
||||
|
||||
def flat(self, *types):
|
||||
if type(self) in types:
|
||||
return [self]
|
||||
return sum([child.flat(*types) for child in self.children], [])
|
||||
|
||||
|
||||
class Argument(LeafPattern):
|
||||
|
||||
def single_match(self, left):
|
||||
for n, pattern in enumerate(left):
|
||||
if type(pattern) is Argument:
|
||||
return n, Argument(self.name, pattern.value)
|
||||
return None, None
|
||||
|
||||
@classmethod
|
||||
def parse(class_, source):
|
||||
name = re.findall('(<\S*?>)', source)[0]
|
||||
value = re.findall('\[default: (.*)\]', source, flags=re.I)
|
||||
return class_(name, value[0] if value else None)
|
||||
|
||||
|
||||
class Command(Argument):
|
||||
|
||||
def __init__(self, name, value=False):
|
||||
self.name, self.value = name, value
|
||||
|
||||
def single_match(self, left):
|
||||
for n, pattern in enumerate(left):
|
||||
if type(pattern) is Argument:
|
||||
if pattern.value == self.name:
|
||||
return n, Command(self.name, True)
|
||||
else:
|
||||
break
|
||||
return None, None
|
||||
|
||||
|
||||
class Option(LeafPattern):
|
||||
|
||||
def __init__(self, short=None, long=None, argcount=0, value=False):
|
||||
assert argcount in (0, 1)
|
||||
self.short, self.long, self.argcount = short, long, argcount
|
||||
self.value = None if value is False and argcount else value
|
||||
|
||||
@classmethod
|
||||
def parse(class_, option_description):
|
||||
short, long, argcount, value = None, None, 0, False
|
||||
options, _, description = option_description.strip().partition(' ')
|
||||
options = options.replace(',', ' ').replace('=', ' ')
|
||||
for s in options.split():
|
||||
if s.startswith('--'):
|
||||
long = s
|
||||
elif s.startswith('-'):
|
||||
short = s
|
||||
else:
|
||||
argcount = 1
|
||||
if argcount:
|
||||
matched = re.findall('\[default: (.*)\]', description, flags=re.I)
|
||||
value = matched[0] if matched else None
|
||||
return class_(short, long, argcount, value)
|
||||
|
||||
def single_match(self, left):
|
||||
for n, pattern in enumerate(left):
|
||||
if self.name == pattern.name:
|
||||
return n, pattern
|
||||
return None, None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.long or self.short
|
||||
|
||||
def __repr__(self):
|
||||
return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
|
||||
self.argcount, self.value)
|
||||
|
||||
|
||||
class Required(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
l = left
|
||||
c = collected
|
||||
for pattern in self.children:
|
||||
matched, l, c = pattern.match(l, c)
|
||||
if not matched:
|
||||
return False, left, collected
|
||||
return True, l, c
|
||||
|
||||
|
||||
class Optional(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
for pattern in self.children:
|
||||
m, left, collected = pattern.match(left, collected)
|
||||
return True, left, collected
|
||||
|
||||
|
||||
class OptionsShortcut(Optional):
|
||||
|
||||
"""Marker/placeholder for [options] shortcut."""
|
||||
|
||||
|
||||
class OneOrMore(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
assert len(self.children) == 1
|
||||
collected = [] if collected is None else collected
|
||||
l = left
|
||||
c = collected
|
||||
l_ = None
|
||||
matched = True
|
||||
times = 0
|
||||
while matched:
|
||||
# could it be that something didn't match but changed l or c?
|
||||
matched, l, c = self.children[0].match(l, c)
|
||||
times += 1 if matched else 0
|
||||
if l_ == l:
|
||||
break
|
||||
l_ = l
|
||||
if times >= 1:
|
||||
return True, l, c
|
||||
return False, left, collected
|
||||
|
||||
|
||||
class Either(BranchPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
outcomes = []
|
||||
for pattern in self.children:
|
||||
matched, _, _ = outcome = pattern.match(left, collected)
|
||||
if matched:
|
||||
outcomes.append(outcome)
|
||||
if outcomes:
|
||||
return min(outcomes, key=lambda outcome: len(outcome[1]))
|
||||
return False, left, collected
|
||||
|
||||
|
||||
class Tokens(list):
|
||||
|
||||
def __init__(self, source, error=DocoptExit):
|
||||
self += source.split() if hasattr(source, 'split') else source
|
||||
self.error = error
|
||||
|
||||
@staticmethod
|
||||
def from_pattern(source):
|
||||
source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source)
|
||||
source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s]
|
||||
return Tokens(source, error=DocoptLanguageError)
|
||||
|
||||
def move(self):
|
||||
return self.pop(0) if len(self) else None
|
||||
|
||||
def current(self):
|
||||
return self[0] if len(self) else None
|
||||
|
||||
|
||||
def parse_long(tokens, options):
|
||||
"""long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
|
||||
long, eq, value = tokens.move().partition('=')
|
||||
assert long.startswith('--')
|
||||
value = None if eq == value == '' else value
|
||||
similar = [o for o in options if o.long == long]
|
||||
if tokens.error is DocoptExit and similar == []: # if no exact match
|
||||
similar = [o for o in options if o.long and o.long.startswith(long)]
|
||||
if len(similar) > 1: # might be simply specified ambiguously 2+ times?
|
||||
raise tokens.error('%s is not a unique prefix: %s?' %
|
||||
(long, ', '.join(o.long for o in similar)))
|
||||
elif len(similar) < 1:
|
||||
argcount = 1 if eq == '=' else 0
|
||||
o = Option(None, long, argcount)
|
||||
options.append(o)
|
||||
if tokens.error is DocoptExit:
|
||||
o = Option(None, long, argcount, value if argcount else True)
|
||||
else:
|
||||
o = Option(similar[0].short, similar[0].long,
|
||||
similar[0].argcount, similar[0].value)
|
||||
if o.argcount == 0:
|
||||
if value is not None:
|
||||
raise tokens.error('%s must not have an argument' % o.long)
|
||||
else:
|
||||
if value is None:
|
||||
if tokens.current() in [None, '--']:
|
||||
raise tokens.error('%s requires argument' % o.long)
|
||||
value = tokens.move()
|
||||
if tokens.error is DocoptExit:
|
||||
o.value = value if value is not None else True
|
||||
return [o]
|
||||
|
||||
|
||||
def parse_shorts(tokens, options):
|
||||
"""shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
|
||||
token = tokens.move()
|
||||
assert token.startswith('-') and not token.startswith('--')
|
||||
left = token.lstrip('-')
|
||||
parsed = []
|
||||
while left != '':
|
||||
short, left = '-' + left[0], left[1:]
|
||||
similar = [o for o in options if o.short == short]
|
||||
if len(similar) > 1:
|
||||
raise tokens.error('%s is specified ambiguously %d times' %
|
||||
(short, len(similar)))
|
||||
elif len(similar) < 1:
|
||||
o = Option(short, None, 0)
|
||||
options.append(o)
|
||||
if tokens.error is DocoptExit:
|
||||
o = Option(short, None, 0, True)
|
||||
else: # why copying is necessary here?
|
||||
o = Option(short, similar[0].long,
|
||||
similar[0].argcount, similar[0].value)
|
||||
value = None
|
||||
if o.argcount != 0:
|
||||
if left == '':
|
||||
if tokens.current() in [None, '--']:
|
||||
raise tokens.error('%s requires argument' % short)
|
||||
value = tokens.move()
|
||||
else:
|
||||
value = left
|
||||
left = ''
|
||||
if tokens.error is DocoptExit:
|
||||
o.value = value if value is not None else True
|
||||
parsed.append(o)
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_pattern(source, options):
|
||||
tokens = Tokens.from_pattern(source)
|
||||
result = parse_expr(tokens, options)
|
||||
if tokens.current() is not None:
|
||||
raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
|
||||
return Required(*result)
|
||||
|
||||
|
||||
def parse_expr(tokens, options):
|
||||
"""expr ::= seq ( '|' seq )* ;"""
|
||||
seq = parse_seq(tokens, options)
|
||||
if tokens.current() != '|':
|
||||
return seq
|
||||
result = [Required(*seq)] if len(seq) > 1 else seq
|
||||
while tokens.current() == '|':
|
||||
tokens.move()
|
||||
seq = parse_seq(tokens, options)
|
||||
result += [Required(*seq)] if len(seq) > 1 else seq
|
||||
return [Either(*result)] if len(result) > 1 else result
|
||||
|
||||
|
||||
def parse_seq(tokens, options):
|
||||
"""seq ::= ( atom [ '...' ] )* ;"""
|
||||
result = []
|
||||
while tokens.current() not in [None, ']', ')', '|']:
|
||||
atom = parse_atom(tokens, options)
|
||||
if tokens.current() == '...':
|
||||
atom = [OneOrMore(*atom)]
|
||||
tokens.move()
|
||||
result += atom
|
||||
return result
|
||||
|
||||
|
||||
def parse_atom(tokens, options):
|
||||
"""atom ::= '(' expr ')' | '[' expr ']' | 'options'
|
||||
| long | shorts | argument | command ;
|
||||
"""
|
||||
token = tokens.current()
|
||||
result = []
|
||||
if token in '([':
|
||||
tokens.move()
|
||||
matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
|
||||
result = pattern(*parse_expr(tokens, options))
|
||||
if tokens.move() != matching:
|
||||
raise tokens.error("unmatched '%s'" % token)
|
||||
return [result]
|
||||
elif token == 'options':
|
||||
tokens.move()
|
||||
return [OptionsShortcut()]
|
||||
elif token.startswith('--') and token != '--':
|
||||
return parse_long(tokens, options)
|
||||
elif token.startswith('-') and token not in ('-', '--'):
|
||||
return parse_shorts(tokens, options)
|
||||
elif token.startswith('<') and token.endswith('>') or token.isupper():
|
||||
return [Argument(tokens.move())]
|
||||
else:
|
||||
return [Command(tokens.move())]
|
||||
|
||||
|
||||
def parse_argv(tokens, options, options_first=False):
|
||||
"""Parse command-line argument vector.
|
||||
|
||||
If options_first:
|
||||
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
|
||||
else:
|
||||
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
|
||||
|
||||
"""
|
||||
parsed = []
|
||||
while tokens.current() is not None:
|
||||
if tokens.current() == '--':
|
||||
return parsed + [Argument(None, v) for v in tokens]
|
||||
elif tokens.current().startswith('--'):
|
||||
parsed += parse_long(tokens, options)
|
||||
elif tokens.current().startswith('-') and tokens.current() != '-':
|
||||
parsed += parse_shorts(tokens, options)
|
||||
elif options_first:
|
||||
return parsed + [Argument(None, v) for v in tokens]
|
||||
else:
|
||||
parsed.append(Argument(None, tokens.move()))
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_defaults(doc):
|
||||
defaults = []
|
||||
for s in parse_section('options:', doc):
|
||||
# FIXME corner case "bla: options: --foo"
|
||||
_, _, s = s.partition(':') # get rid of "options:"
|
||||
split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:]
|
||||
split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
|
||||
options = [Option.parse(s) for s in split if s.startswith('-')]
|
||||
defaults += options
|
||||
return defaults
|
||||
|
||||
|
||||
def parse_section(name, source):
|
||||
pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
|
||||
re.IGNORECASE | re.MULTILINE)
|
||||
return [s.strip() for s in pattern.findall(source)]
|
||||
|
||||
|
||||
def formal_usage(section):
|
||||
_, _, section = section.partition(':') # drop "usage:"
|
||||
pu = section.split()
|
||||
return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
|
||||
|
||||
|
||||
def extras(help, version, options, doc):
|
||||
if help and any((o.name in ('-h', '--help')) and o.value for o in options):
|
||||
print(doc.strip("\n"))
|
||||
sys.exit()
|
||||
if version and any(o.name == '--version' and o.value for o in options):
|
||||
print(version)
|
||||
sys.exit()
|
||||
|
||||
|
||||
class Dict(dict):
|
||||
def __repr__(self):
|
||||
return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
|
||||
|
||||
|
||||
def docopt(doc, argv=None, help=True, version=None, options_first=False):
|
||||
"""Parse `argv` based on command-line interface described in `doc`.
|
||||
|
||||
`docopt` creates your command-line interface based on its
|
||||
description that you pass as `doc`. Such description can contain
|
||||
--options, <positional-argument>, commands, which could be
|
||||
[optional], (required), (mutually | exclusive) or repeated...
|
||||
|
||||
Parameters
|
||||
----------
|
||||
doc : str
|
||||
Description of your command-line interface.
|
||||
argv : list of str, optional
|
||||
Argument vector to be parsed. sys.argv[1:] is used if not
|
||||
provided.
|
||||
help : bool (default: True)
|
||||
Set to False to disable automatic help on -h or --help
|
||||
options.
|
||||
version : any object
|
||||
If passed, the object will be printed if --version is in
|
||||
`argv`.
|
||||
options_first : bool (default: False)
|
||||
Set to True to require options precede positional arguments,
|
||||
i.e. to forbid options and positional arguments intermix.
|
||||
|
||||
Returns
|
||||
-------
|
||||
args : dict
|
||||
A dictionary, where keys are names of command-line elements
|
||||
such as e.g. "--verbose" and "<path>", and values are the
|
||||
parsed values of those elements.
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> from docopt import docopt
|
||||
>>> doc = '''
|
||||
... Usage:
|
||||
... my_program tcp <host> <port> [--timeout=<seconds>]
|
||||
... my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
|
||||
... my_program (-h | --help | --version)
|
||||
...
|
||||
... Options:
|
||||
... -h, --help Show this screen and exit.
|
||||
... --baud=<n> Baudrate [default: 9600]
|
||||
... '''
|
||||
>>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
|
||||
>>> docopt(doc, argv)
|
||||
{'--baud': '9600',
|
||||
'--help': False,
|
||||
'--timeout': '30',
|
||||
'--version': False,
|
||||
'<host>': '127.0.0.1',
|
||||
'<port>': '80',
|
||||
'serial': False,
|
||||
'tcp': True}
|
||||
|
||||
See also
|
||||
--------
|
||||
* For video introduction see http://docopt.org
|
||||
* Full documentation is available in README.rst as well as online
|
||||
at https://github.com/docopt/docopt#readme
|
||||
|
||||
"""
|
||||
argv = sys.argv[1:] if argv is None else argv
|
||||
|
||||
usage_sections = parse_section('usage:', doc)
|
||||
if len(usage_sections) == 0:
|
||||
raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
|
||||
if len(usage_sections) > 1:
|
||||
raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
|
||||
DocoptExit.usage = usage_sections[0]
|
||||
|
||||
options = parse_defaults(doc)
|
||||
pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
|
||||
# [default] syntax for argument is disabled
|
||||
#for a in pattern.flat(Argument):
|
||||
# same_name = [d for d in arguments if d.name == a.name]
|
||||
# if same_name:
|
||||
# a.value = same_name[0].value
|
||||
argv = parse_argv(Tokens(argv), list(options), options_first)
|
||||
pattern_options = set(pattern.flat(Option))
|
||||
for options_shortcut in pattern.flat(OptionsShortcut):
|
||||
doc_options = parse_defaults(doc)
|
||||
options_shortcut.children = list(set(doc_options) - pattern_options)
|
||||
#if any_options:
|
||||
# options_shortcut.children += [Option(o.short, o.long, o.argcount)
|
||||
# for o in argv if type(o) is Option]
|
||||
extras(help, version, argv, doc)
|
||||
matched, left, collected = pattern.fix().match(argv)
|
||||
if matched and left == []: # better error message if left?
|
||||
return Dict((a.name, a.value) for a in (pattern.flat() + collected))
|
||||
raise DocoptExit()
|
||||
76
support/mkdocs
Executable file
76
support/mkdocs
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
# A script to invoke mkdocs with the correct environment.
|
||||
# Additionally supports deploying via mike:
|
||||
# ./mkdocs deploy [mike-deploy-options]
|
||||
|
||||
import errno, os, shutil, sys
|
||||
from subprocess import call
|
||||
|
||||
support_dir = os.path.dirname(os.path.normpath(__file__))
|
||||
build_dir = os.path.join(os.path.dirname(support_dir), 'build')
|
||||
|
||||
# Set PYTHONPATH for the mkdocstrings handler.
|
||||
env = os.environ.copy()
|
||||
path = env.get('PYTHONPATH')
|
||||
env['PYTHONPATH'] = \
|
||||
(path + ':' if path else '') + os.path.join(support_dir, 'python')
|
||||
|
||||
redirect_page = \
|
||||
'''<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Redirecting</title>
|
||||
<noscript>
|
||||
<meta http-equiv="refresh" content="1; url=11.0/" />
|
||||
</noscript>
|
||||
<script>
|
||||
window.location.replace(
|
||||
"api/" + window.location.search + window.location.hash
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Redirecting to <a href="api/">api</a>...
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
||||
config_path = os.path.join(support_dir, 'mkdocs.yml')
|
||||
args = sys.argv[1:]
|
||||
if len(args) > 0:
|
||||
command = args[0]
|
||||
if command == 'deploy':
|
||||
git_url = 'https://github.com/' if 'CI' in os.environ else 'git@github.com:'
|
||||
site_repo = git_url + 'fmtlib/fmt.dev.git'
|
||||
|
||||
site_dir = os.path.join(build_dir, 'fmt.dev')
|
||||
try:
|
||||
shutil.rmtree(site_dir)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
pass
|
||||
ret = call(['git', 'clone', '--depth=1', site_repo, site_dir])
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
|
||||
# Copy the config to the build dir because the site is built relative to it.
|
||||
config_build_path = os.path.join(build_dir, 'mkdocs.yml')
|
||||
shutil.copyfile(config_path, config_build_path)
|
||||
|
||||
version = args[1]
|
||||
ret = call(['mike'] + args + ['--config-file', config_build_path,
|
||||
'--branch', 'master'], cwd=site_dir, env=env)
|
||||
if ret != 0 or version == 'dev':
|
||||
sys.exit(ret)
|
||||
redirect_page_path = os.path.join(site_dir, version, 'api.html')
|
||||
with open(redirect_page_path, "w") as file:
|
||||
file.write(redirect_page)
|
||||
ret = call(['git', 'add', redirect_page_path], cwd=site_dir)
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir)
|
||||
sys.exit(ret)
|
||||
elif not command.startswith('-'):
|
||||
args += ['-f', config_path]
|
||||
sys.exit(call(['mkdocs'] + args, env=env))
|
||||
48
support/mkdocs.yml
Normal file
48
support/mkdocs.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
site_name: '{fmt}'
|
||||
|
||||
docs_dir: ../doc
|
||||
|
||||
repo_url: https://github.com/fmtlib/fmt
|
||||
|
||||
theme:
|
||||
name: material
|
||||
features:
|
||||
- navigation.tabs
|
||||
- navigation.top
|
||||
- toc.integrate
|
||||
|
||||
extra_javascript:
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js
|
||||
- fmt.js
|
||||
|
||||
extra_css:
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css
|
||||
- fmt.css
|
||||
|
||||
markdown_extensions:
|
||||
- pymdownx.highlight:
|
||||
# Use JavaScript syntax highlighter instead of Pygments because it
|
||||
# automatically applies to code blocks extracted through Doxygen.
|
||||
use_pygments: false
|
||||
anchor_linenums: true
|
||||
line_spans: __span
|
||||
pygments_lang_class: true
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.snippets
|
||||
|
||||
plugins:
|
||||
- search
|
||||
- mkdocstrings:
|
||||
default_handler: cxx
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Get Started: get-started.md
|
||||
- API: api.md
|
||||
- Syntax: syntax.md
|
||||
|
||||
exclude_docs: ChangeLog-old.md
|
||||
|
||||
extra:
|
||||
version:
|
||||
provider: mike
|
||||
generator: false
|
||||
201
support/printable.py
Executable file
201
support/printable.py
Executable file
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This script is based on
|
||||
# https://github.com/rust-lang/rust/blob/master/library/core/src/unicode/printable.py
|
||||
# distributed under https://github.com/rust-lang/rust/blob/master/LICENSE-MIT.
|
||||
|
||||
# This script uses the following Unicode tables:
|
||||
# - UnicodeData.txt
|
||||
|
||||
|
||||
from collections import namedtuple
|
||||
import csv
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
NUM_CODEPOINTS=0x110000
|
||||
|
||||
def to_ranges(iter):
|
||||
current = None
|
||||
for i in iter:
|
||||
if current is None or i != current[1] or i in (0x10000, 0x20000):
|
||||
if current is not None:
|
||||
yield tuple(current)
|
||||
current = [i, i + 1]
|
||||
else:
|
||||
current[1] += 1
|
||||
if current is not None:
|
||||
yield tuple(current)
|
||||
|
||||
def get_escaped(codepoints):
|
||||
for c in codepoints:
|
||||
if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '):
|
||||
yield c.value
|
||||
|
||||
def get_file(f):
|
||||
try:
|
||||
return open(os.path.basename(f))
|
||||
except FileNotFoundError:
|
||||
subprocess.run(["curl", "-O", f], check=True)
|
||||
return open(os.path.basename(f))
|
||||
|
||||
Codepoint = namedtuple('Codepoint', 'value class_')
|
||||
|
||||
def get_codepoints(f):
|
||||
r = csv.reader(f, delimiter=";")
|
||||
prev_codepoint = 0
|
||||
class_first = None
|
||||
for row in r:
|
||||
codepoint = int(row[0], 16)
|
||||
name = row[1]
|
||||
class_ = row[2]
|
||||
|
||||
if class_first is not None:
|
||||
if not name.endswith("Last>"):
|
||||
raise ValueError("Missing Last after First")
|
||||
|
||||
for c in range(prev_codepoint + 1, codepoint):
|
||||
yield Codepoint(c, class_first)
|
||||
|
||||
class_first = None
|
||||
if name.endswith("First>"):
|
||||
class_first = class_
|
||||
|
||||
yield Codepoint(codepoint, class_)
|
||||
prev_codepoint = codepoint
|
||||
|
||||
if class_first is not None:
|
||||
raise ValueError("Missing Last after First")
|
||||
|
||||
for c in range(prev_codepoint + 1, NUM_CODEPOINTS):
|
||||
yield Codepoint(c, None)
|
||||
|
||||
def compress_singletons(singletons):
|
||||
uppers = [] # (upper, # items in lowers)
|
||||
lowers = []
|
||||
|
||||
for i in singletons:
|
||||
upper = i >> 8
|
||||
lower = i & 0xff
|
||||
if len(uppers) == 0 or uppers[-1][0] != upper:
|
||||
uppers.append((upper, 1))
|
||||
else:
|
||||
upper, count = uppers[-1]
|
||||
uppers[-1] = upper, count + 1
|
||||
lowers.append(lower)
|
||||
|
||||
return uppers, lowers
|
||||
|
||||
def compress_normal(normal):
|
||||
# lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f
|
||||
# lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff
|
||||
compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)]
|
||||
|
||||
prev_start = 0
|
||||
for start, count in normal:
|
||||
truelen = start - prev_start
|
||||
falselen = count
|
||||
prev_start = start + count
|
||||
|
||||
assert truelen < 0x8000 and falselen < 0x8000
|
||||
entry = []
|
||||
if truelen > 0x7f:
|
||||
entry.append(0x80 | (truelen >> 8))
|
||||
entry.append(truelen & 0xff)
|
||||
else:
|
||||
entry.append(truelen & 0x7f)
|
||||
if falselen > 0x7f:
|
||||
entry.append(0x80 | (falselen >> 8))
|
||||
entry.append(falselen & 0xff)
|
||||
else:
|
||||
entry.append(falselen & 0x7f)
|
||||
|
||||
compressed.append(entry)
|
||||
|
||||
return compressed
|
||||
|
||||
def print_singletons(uppers, lowers, uppersname, lowersname):
|
||||
print(" static constexpr singleton {}[] = {{".format(uppersname))
|
||||
for u, c in uppers:
|
||||
print(" {{{:#04x}, {}}},".format(u, c))
|
||||
print(" };")
|
||||
print(" static constexpr unsigned char {}[] = {{".format(lowersname))
|
||||
for i in range(0, len(lowers), 8):
|
||||
print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
|
||||
print(" };")
|
||||
|
||||
def print_normal(normal, normalname):
|
||||
print(" static constexpr unsigned char {}[] = {{".format(normalname))
|
||||
for v in normal:
|
||||
print(" {}".format(" ".join("{:#04x},".format(i) for i in v)))
|
||||
print(" };")
|
||||
|
||||
def main():
|
||||
file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
|
||||
|
||||
codepoints = get_codepoints(file)
|
||||
|
||||
CUTOFF=0x10000
|
||||
singletons0 = []
|
||||
singletons1 = []
|
||||
normal0 = []
|
||||
normal1 = []
|
||||
extra = []
|
||||
|
||||
for a, b in to_ranges(get_escaped(codepoints)):
|
||||
if a > 2 * CUTOFF:
|
||||
extra.append((a, b - a))
|
||||
elif a == b - 1:
|
||||
if a & CUTOFF:
|
||||
singletons1.append(a & ~CUTOFF)
|
||||
else:
|
||||
singletons0.append(a)
|
||||
elif a == b - 2:
|
||||
if a & CUTOFF:
|
||||
singletons1.append(a & ~CUTOFF)
|
||||
singletons1.append((a + 1) & ~CUTOFF)
|
||||
else:
|
||||
singletons0.append(a)
|
||||
singletons0.append(a + 1)
|
||||
else:
|
||||
if a >= 2 * CUTOFF:
|
||||
extra.append((a, b - a))
|
||||
elif a & CUTOFF:
|
||||
normal1.append((a & ~CUTOFF, b - a))
|
||||
else:
|
||||
normal0.append((a, b - a))
|
||||
|
||||
singletons0u, singletons0l = compress_singletons(singletons0)
|
||||
singletons1u, singletons1l = compress_singletons(singletons1)
|
||||
normal0 = compress_normal(normal0)
|
||||
normal1 = compress_normal(normal1)
|
||||
|
||||
print("""\
|
||||
FMT_FUNC auto is_printable(uint32_t cp) -> bool {\
|
||||
""")
|
||||
print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
|
||||
print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
|
||||
print_normal(normal0, 'normal0')
|
||||
print_normal(normal1, 'normal1')
|
||||
print("""\
|
||||
auto lower = static_cast<uint16_t>(cp);
|
||||
if (cp < 0x10000) {
|
||||
return is_printable(lower, singletons0,
|
||||
sizeof(singletons0) / sizeof(*singletons0),
|
||||
singletons0_lower, normal0, sizeof(normal0));
|
||||
}
|
||||
if (cp < 0x20000) {
|
||||
return is_printable(lower, singletons1,
|
||||
sizeof(singletons1) / sizeof(*singletons1),
|
||||
singletons1_lower, normal1, sizeof(normal1));
|
||||
}\
|
||||
""")
|
||||
for a, b in extra:
|
||||
print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b))
|
||||
print("""\
|
||||
return cp < 0x{:x};
|
||||
}}\
|
||||
""".format(NUM_CODEPOINTS))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
338
support/python/mkdocstrings_handlers/cxx/__init__.py
Normal file
338
support/python/mkdocstrings_handlers/cxx/__init__.py
Normal file
@@ -0,0 +1,338 @@
|
||||
# A basic mkdocstrings handler for {fmt}.
|
||||
# Copyright (c) 2012 - present, Victor Zverovich
|
||||
# https://github.com/fmtlib/fmt/blob/master/LICENSE
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
from pathlib import Path
|
||||
from subprocess import PIPE, STDOUT, CalledProcessError, Popen
|
||||
from typing import Any, List, Mapping, Optional
|
||||
|
||||
from mkdocstrings.handlers.base import BaseHandler
|
||||
|
||||
|
||||
class Definition:
|
||||
"""A definition extracted by Doxygen."""
|
||||
|
||||
def __init__(self, name: str, kind: Optional[str] = None,
|
||||
node: Optional[ElementTree.Element] = None,
|
||||
is_member: bool = False):
|
||||
self.name = name
|
||||
self.kind = kind if kind is not None else node.get('kind')
|
||||
self.desc = None
|
||||
self.id = name if not is_member else None
|
||||
self.members = None
|
||||
self.params = None
|
||||
self.template_params = None
|
||||
self.trailing_return_type = None
|
||||
self.type = None
|
||||
|
||||
|
||||
# A map from Doxygen to HTML tags.
|
||||
tag_map = {
|
||||
'bold': 'b',
|
||||
'emphasis': 'em',
|
||||
'computeroutput': 'code',
|
||||
'para': 'p',
|
||||
'programlisting': 'pre',
|
||||
'verbatim': 'pre'
|
||||
}
|
||||
|
||||
# A map from Doxygen tags to text.
|
||||
tag_text_map = {
|
||||
'codeline': '',
|
||||
'highlight': '',
|
||||
'sp': ' '
|
||||
}
|
||||
|
||||
|
||||
def escape_html(s: str) -> str:
|
||||
return s.replace("<", "<")
|
||||
|
||||
|
||||
def doxyxml2html(nodes: List[ElementTree.Element]):
|
||||
out = ''
|
||||
for n in nodes:
|
||||
tag = tag_map.get(n.tag)
|
||||
if not tag:
|
||||
out += tag_text_map[n.tag]
|
||||
out += '<' + tag + '>' if tag else ''
|
||||
out += '<code class="language-cpp">' if tag == 'pre' else ''
|
||||
if n.text:
|
||||
out += escape_html(n.text)
|
||||
out += doxyxml2html(list(n))
|
||||
out += '</code>' if tag == 'pre' else ''
|
||||
out += '</' + tag + '>' if tag else ''
|
||||
if n.tail:
|
||||
out += n.tail
|
||||
return out
|
||||
|
||||
|
||||
def convert_template_params(node: ElementTree.Element) -> Optional[List[Definition]]:
|
||||
template_param_list = node.find('templateparamlist')
|
||||
if template_param_list is None:
|
||||
return None
|
||||
params = []
|
||||
for param_node in template_param_list.findall('param'):
|
||||
name = param_node.find('declname')
|
||||
param = Definition(name.text if name is not None else '', 'param')
|
||||
param.type = param_node.find('type').text
|
||||
params.append(param)
|
||||
return params
|
||||
|
||||
|
||||
def get_description(node: ElementTree.Element) -> List[ElementTree.Element]:
|
||||
return node.findall('briefdescription/para') + \
|
||||
node.findall('detaileddescription/para')
|
||||
|
||||
|
||||
def normalize_type(type_: str) -> str:
|
||||
type_ = type_.replace('< ', '<').replace(' >', '>')
|
||||
return type_.replace(' &', '&').replace(' *', '*')
|
||||
|
||||
|
||||
def convert_type(type_: ElementTree.Element) -> Optional[str]:
|
||||
if type_ is None:
|
||||
return None
|
||||
result = type_.text if type_.text else ''
|
||||
for ref in type_:
|
||||
result += ref.text
|
||||
if ref.tail:
|
||||
result += ref.tail
|
||||
result += type_.tail.strip()
|
||||
return normalize_type(result)
|
||||
|
||||
|
||||
def convert_params(func: ElementTree.Element) -> List[Definition]:
|
||||
params = []
|
||||
for p in func.findall('param'):
|
||||
d = Definition(p.find('declname').text, 'param')
|
||||
d.type = convert_type(p.find('type'))
|
||||
params.append(d)
|
||||
return params
|
||||
|
||||
|
||||
def convert_return_type(d: Definition, node: ElementTree.Element) -> None:
|
||||
d.trailing_return_type = None
|
||||
if d.type == 'auto' or d.type == 'constexpr auto':
|
||||
parts = node.find('argsstring').text.split(' -> ')
|
||||
if len(parts) > 1:
|
||||
d.trailing_return_type = normalize_type(parts[1])
|
||||
|
||||
|
||||
def render_param(param: Definition) -> str:
|
||||
return param.type + (f' {param.name}' if len(param.name) > 0 else '')
|
||||
|
||||
|
||||
def render_decl(d: Definition) -> str:
|
||||
text = ''
|
||||
if d.id is not None:
|
||||
text += f'<a id="{d.id}">\n'
|
||||
text += '<pre><code class="language-cpp decl">'
|
||||
|
||||
text += '<div>'
|
||||
if d.template_params is not None:
|
||||
text += 'template <'
|
||||
text += ', '.join([render_param(p) for p in d.template_params])
|
||||
text += '>\n'
|
||||
text += '</div>'
|
||||
|
||||
text += '<div>'
|
||||
end = ';'
|
||||
if d.kind == 'function' or d.kind == 'variable':
|
||||
text += d.type + ' ' if len(d.type) > 0 else ''
|
||||
elif d.kind == 'typedef':
|
||||
text += 'using '
|
||||
elif d.kind == 'define':
|
||||
end = ''
|
||||
else:
|
||||
text += d.kind + ' '
|
||||
text += d.name
|
||||
|
||||
if d.params is not None:
|
||||
params = ', '.join([
|
||||
(p.type + ' ' if p.type else '') + p.name for p in d.params])
|
||||
text += '(' + escape_html(params) + ')'
|
||||
if d.trailing_return_type:
|
||||
text += ' -⁠> ' + escape_html(d.trailing_return_type)
|
||||
elif d.kind == 'typedef':
|
||||
text += ' = ' + escape_html(d.type)
|
||||
|
||||
text += end
|
||||
text += '</div>'
|
||||
text += '</code></pre>\n'
|
||||
if d.id is not None:
|
||||
text += f'</a>\n'
|
||||
return text
|
||||
|
||||
|
||||
class CxxHandler(BaseHandler):
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
super().__init__(handler='cxx', **kwargs)
|
||||
|
||||
headers = [
|
||||
'args.h', 'base.h', 'chrono.h', 'color.h', 'compile.h', 'format.h',
|
||||
'os.h', 'ostream.h', 'printf.h', 'ranges.h', 'std.h', 'xchar.h'
|
||||
]
|
||||
|
||||
# Run doxygen.
|
||||
cmd = ['doxygen', '-']
|
||||
support_dir = Path(__file__).parents[3]
|
||||
top_dir = os.path.dirname(support_dir)
|
||||
include_dir = os.path.join(top_dir, 'include', 'fmt')
|
||||
self._ns2doxyxml = {}
|
||||
build_dir = os.path.join(top_dir, 'build')
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
self._doxyxml_dir = os.path.join(build_dir, 'doxyxml')
|
||||
p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
|
||||
_, _ = p.communicate(input=r'''
|
||||
PROJECT_NAME = fmt
|
||||
GENERATE_XML = YES
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_HTML = NO
|
||||
INPUT = {0}
|
||||
XML_OUTPUT = {1}
|
||||
QUIET = YES
|
||||
AUTOLINK_SUPPORT = NO
|
||||
MACRO_EXPANSION = YES
|
||||
PREDEFINED = _WIN32=1 \
|
||||
__linux__=1 \
|
||||
FMT_ENABLE_IF(...)= \
|
||||
FMT_USE_USER_LITERALS=1 \
|
||||
FMT_USE_ALIAS_TEMPLATES=1 \
|
||||
FMT_USE_NONTYPE_TEMPLATE_ARGS=1 \
|
||||
FMT_API= \
|
||||
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
||||
"FMT_END_NAMESPACE=}}" \
|
||||
"FMT_DOC=1"
|
||||
'''.format(
|
||||
' '.join([os.path.join(include_dir, h) for h in headers]),
|
||||
self._doxyxml_dir).encode('utf-8'))
|
||||
if p.returncode != 0:
|
||||
raise CalledProcessError(p.returncode, cmd)
|
||||
|
||||
# Merge all file-level XMLs into one to simplify search.
|
||||
self._file_doxyxml = None
|
||||
for h in headers:
|
||||
filename = h.replace(".h", "_8h.xml")
|
||||
with open(os.path.join(self._doxyxml_dir, filename)) as f:
|
||||
doxyxml = ElementTree.parse(f)
|
||||
if self._file_doxyxml is None:
|
||||
self._file_doxyxml = doxyxml
|
||||
continue
|
||||
root = self._file_doxyxml.getroot()
|
||||
for node in doxyxml.getroot():
|
||||
root.append(node)
|
||||
|
||||
def collect_compound(self, identifier: str,
|
||||
cls: List[ElementTree.Element]) -> Definition:
|
||||
"""Collect a compound definition such as a struct."""
|
||||
path = os.path.join(self._doxyxml_dir, cls[0].get('refid') + '.xml')
|
||||
with open(path) as f:
|
||||
xml = ElementTree.parse(f)
|
||||
node = xml.find('compounddef')
|
||||
d = Definition(identifier, node=node)
|
||||
d.template_params = convert_template_params(node)
|
||||
d.desc = get_description(node)
|
||||
d.members = []
|
||||
for m in \
|
||||
node.findall('sectiondef[@kind="public-attrib"]/memberdef') + \
|
||||
node.findall('sectiondef[@kind="public-func"]/memberdef'):
|
||||
name = m.find('name').text
|
||||
# Doxygen incorrectly classifies members of private unnamed unions as
|
||||
# public members of the containing class.
|
||||
if name.endswith('_'):
|
||||
continue
|
||||
desc = get_description(m)
|
||||
if len(desc) == 0:
|
||||
continue
|
||||
kind = m.get('kind')
|
||||
member = Definition(name if name else '', kind=kind, is_member=True)
|
||||
type_text = m.find('type').text
|
||||
member.type = type_text if type_text else ''
|
||||
if kind == 'function':
|
||||
member.params = convert_params(m)
|
||||
convert_return_type(member, m)
|
||||
member.template_params = None
|
||||
member.desc = desc
|
||||
d.members.append(member)
|
||||
return d
|
||||
|
||||
def collect(self, identifier: str, _config: Mapping[str, Any]) -> Definition:
|
||||
qual_name = 'fmt::' + identifier
|
||||
|
||||
param_str = None
|
||||
paren = qual_name.find('(')
|
||||
if paren > 0:
|
||||
qual_name, param_str = qual_name[:paren], qual_name[paren + 1:-1]
|
||||
|
||||
colons = qual_name.rfind('::')
|
||||
namespace, name = qual_name[:colons], qual_name[colons + 2:]
|
||||
|
||||
# Load XML.
|
||||
doxyxml = self._ns2doxyxml.get(namespace)
|
||||
if doxyxml is None:
|
||||
path = f'namespace{namespace.replace("::", "_1_1")}.xml'
|
||||
with open(os.path.join(self._doxyxml_dir, path)) as f:
|
||||
doxyxml = ElementTree.parse(f)
|
||||
self._ns2doxyxml[namespace] = doxyxml
|
||||
|
||||
nodes = doxyxml.findall(
|
||||
f"compounddef/sectiondef/memberdef/name[.='{name}']/..")
|
||||
if len(nodes) == 0:
|
||||
nodes = self._file_doxyxml.findall(
|
||||
f"compounddef/sectiondef/memberdef/name[.='{name}']/..")
|
||||
candidates = []
|
||||
for node in nodes:
|
||||
# Process a function or a typedef.
|
||||
params = None
|
||||
d = Definition(name, node=node)
|
||||
if d.kind == 'function':
|
||||
params = convert_params(node)
|
||||
node_param_str = ', '.join([p.type for p in params])
|
||||
if param_str and param_str != node_param_str:
|
||||
candidates.append(f'{name}({node_param_str})')
|
||||
continue
|
||||
elif d.kind == 'define':
|
||||
params = []
|
||||
for p in node.findall('param'):
|
||||
param = Definition(p.find('defname').text, kind='param')
|
||||
param.type = None
|
||||
params.append(param)
|
||||
d.type = convert_type(node.find('type'))
|
||||
d.template_params = convert_template_params(node)
|
||||
d.params = params
|
||||
convert_return_type(d, node)
|
||||
d.desc = get_description(node)
|
||||
return d
|
||||
|
||||
cls = doxyxml.findall(f"compounddef/innerclass[.='{qual_name}']")
|
||||
if not cls:
|
||||
raise Exception(f'Cannot find {identifier}. Candidates: {candidates}')
|
||||
return self.collect_compound(identifier, cls)
|
||||
|
||||
def render(self, d: Definition, config: dict) -> str:
|
||||
if d.id is not None:
|
||||
self.do_heading('', 0, id=d.id)
|
||||
text = '<div class="docblock">\n'
|
||||
text += render_decl(d)
|
||||
text += '<div class="docblock-desc">\n'
|
||||
text += doxyxml2html(d.desc)
|
||||
if d.members is not None:
|
||||
for m in d.members:
|
||||
text += self.render(m, config)
|
||||
text += '</div>\n'
|
||||
text += '</div>\n'
|
||||
return text
|
||||
|
||||
|
||||
def get_handler(theme: str, custom_templates: Optional[str] = None,
|
||||
**_config: Any) -> CxxHandler:
|
||||
"""Return an instance of `CxxHandler`.
|
||||
|
||||
Arguments:
|
||||
theme: The theme to use when rendering contents.
|
||||
custom_templates: Directory containing custom templates.
|
||||
**_config: Configuration passed to the handler.
|
||||
"""
|
||||
return CxxHandler(theme=theme, custom_templates=custom_templates)
|
||||
@@ -0,0 +1 @@
|
||||
mkdocsstrings requires a handler to have a templates directory.
|
||||
188
support/release.py
Executable file
188
support/release.py
Executable file
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Make a release.
|
||||
|
||||
Usage:
|
||||
release.py [<branch>]
|
||||
|
||||
For the release command $FMT_TOKEN should contain a GitHub personal access token
|
||||
obtained from https://github.com/settings/tokens.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import datetime, docopt, errno, fileinput, json, os
|
||||
import re, shutil, sys
|
||||
from subprocess import check_call
|
||||
import urllib.request
|
||||
|
||||
|
||||
class Git:
|
||||
def __init__(self, dir):
|
||||
self.dir = dir
|
||||
|
||||
def call(self, method, args, **kwargs):
|
||||
return check_call(['git', method] + list(args), **kwargs)
|
||||
|
||||
def add(self, *args):
|
||||
return self.call('add', args, cwd=self.dir)
|
||||
|
||||
def checkout(self, *args):
|
||||
return self.call('checkout', args, cwd=self.dir)
|
||||
|
||||
def clean(self, *args):
|
||||
return self.call('clean', args, cwd=self.dir)
|
||||
|
||||
def clone(self, *args):
|
||||
return self.call('clone', list(args) + [self.dir])
|
||||
|
||||
def commit(self, *args):
|
||||
return self.call('commit', args, cwd=self.dir)
|
||||
|
||||
def pull(self, *args):
|
||||
return self.call('pull', args, cwd=self.dir)
|
||||
|
||||
def push(self, *args):
|
||||
return self.call('push', args, cwd=self.dir)
|
||||
|
||||
def reset(self, *args):
|
||||
return self.call('reset', args, cwd=self.dir)
|
||||
|
||||
def update(self, *args):
|
||||
clone = not os.path.exists(self.dir)
|
||||
if clone:
|
||||
self.clone(*args)
|
||||
return clone
|
||||
|
||||
|
||||
def clean_checkout(repo, branch):
|
||||
repo.clean('-f', '-d')
|
||||
repo.reset('--hard')
|
||||
repo.checkout(branch)
|
||||
|
||||
|
||||
class Runner:
|
||||
def __init__(self, cwd):
|
||||
self.cwd = cwd
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
kwargs['cwd'] = kwargs.get('cwd', self.cwd)
|
||||
check_call(args, **kwargs)
|
||||
|
||||
|
||||
def create_build_env():
|
||||
"""Create a build environment."""
|
||||
class Env:
|
||||
pass
|
||||
env = Env()
|
||||
env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
env.build_dir = 'build'
|
||||
env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt'))
|
||||
return env
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = docopt.docopt(__doc__)
|
||||
env = create_build_env()
|
||||
fmt_repo = env.fmt_repo
|
||||
|
||||
branch = args.get('<branch>')
|
||||
if branch is None:
|
||||
branch = 'master'
|
||||
if not fmt_repo.update('-b', branch, 'git@github.com:fmtlib/fmt'):
|
||||
clean_checkout(fmt_repo, branch)
|
||||
|
||||
# Update the date in the changelog and extract the version and the first
|
||||
# section content.
|
||||
changelog = 'ChangeLog.md'
|
||||
changelog_path = os.path.join(fmt_repo.dir, changelog)
|
||||
is_first_section = True
|
||||
first_section = []
|
||||
for i, line in enumerate(fileinput.input(changelog_path, inplace=True)):
|
||||
if i == 0:
|
||||
version = re.match(r'# (.*) - TBD', line).group(1)
|
||||
line = '# {} - {}\n'.format(
|
||||
version, datetime.date.today().isoformat())
|
||||
elif not is_first_section:
|
||||
pass
|
||||
elif line.startswith('#'):
|
||||
is_first_section = False
|
||||
else:
|
||||
first_section.append(line)
|
||||
sys.stdout.write(line)
|
||||
if first_section[0] == '\n':
|
||||
first_section.pop(0)
|
||||
|
||||
ns_version = None
|
||||
base_h_path = os.path.join(fmt_repo.dir, 'include', 'fmt', 'base.h')
|
||||
for line in fileinput.input(base_h_path):
|
||||
m = re.match(r'\s*inline namespace v(.*) .*', line)
|
||||
if m:
|
||||
ns_version = m.group(1)
|
||||
break
|
||||
major_version = version.split('.')[0]
|
||||
if not ns_version or ns_version != major_version:
|
||||
raise Exception(f'Version mismatch {ns_version} != {major_version}')
|
||||
|
||||
# Workaround GitHub-flavored Markdown treating newlines as <br>.
|
||||
changes = ''
|
||||
code_block = False
|
||||
stripped = False
|
||||
for line in first_section:
|
||||
if re.match(r'^\s*```', line):
|
||||
code_block = not code_block
|
||||
changes += line
|
||||
stripped = False
|
||||
continue
|
||||
if code_block:
|
||||
changes += line
|
||||
continue
|
||||
if line == '\n' or re.match(r'^\s*\|.*', line):
|
||||
if stripped:
|
||||
changes += '\n'
|
||||
stripped = False
|
||||
changes += line
|
||||
continue
|
||||
if stripped:
|
||||
line = ' ' + line.lstrip()
|
||||
changes += line.rstrip()
|
||||
stripped = True
|
||||
|
||||
fmt_repo.checkout('-B', 'release')
|
||||
fmt_repo.add(changelog)
|
||||
fmt_repo.commit('-m', 'Update version')
|
||||
|
||||
# Build the docs and package.
|
||||
run = Runner(fmt_repo.dir)
|
||||
run('cmake', '.')
|
||||
run('make', 'doc', 'package_source')
|
||||
|
||||
# Create a release on GitHub.
|
||||
fmt_repo.push('origin', 'release')
|
||||
auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')}
|
||||
req = urllib.request.Request(
|
||||
'https://api.github.com/repos/fmtlib/fmt/releases',
|
||||
data=json.dumps({'tag_name': version,
|
||||
'target_commitish': 'release',
|
||||
'body': changes, 'draft': True}).encode('utf-8'),
|
||||
headers=auth_headers, method='POST')
|
||||
with urllib.request.urlopen(req) as response:
|
||||
if response.status != 201:
|
||||
raise Exception(f'Failed to create a release ' +
|
||||
'{response.status} {response.reason}')
|
||||
response_data = json.loads(response.read().decode('utf-8'))
|
||||
id = response_data['id']
|
||||
|
||||
# Upload the package.
|
||||
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
|
||||
package = 'fmt-{}.zip'.format(version)
|
||||
req = urllib.request.Request(
|
||||
f'{uploads_url}/{id}/assets?name={package}',
|
||||
headers={'Content-Type': 'application/zip'} | auth_headers,
|
||||
data=open('build/fmt/' + package, 'rb').read(), method='POST')
|
||||
with urllib.request.urlopen(req) as response:
|
||||
if response.status != 201:
|
||||
raise Exception(f'Failed to upload an asset '
|
||||
'{response.status} {response.reason}')
|
||||
|
||||
short_version = '.'.join(version.split('.')[:-1])
|
||||
check_call(['./mkdocs', 'deploy', short_version])
|
||||
@@ -1,74 +1,257 @@
|
||||
add_subdirectory(gtest)
|
||||
|
||||
include(CheckSymbolExists)
|
||||
|
||||
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
|
||||
add_library(test-main ${TEST_MAIN_SRC})
|
||||
target_link_libraries(test-main gmock)
|
||||
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
||||
target_include_directories(test-main PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
||||
target_link_libraries(test-main gtest fmt)
|
||||
|
||||
# Adds a test.
|
||||
# Usage: add_fmt_test(name [CUSTOM_LINK] srcs...)
|
||||
# Usage: add_fmt_test(name srcs...)
|
||||
function(add_fmt_test name)
|
||||
cmake_parse_arguments(add_fmt_test CUSTOM_LINK "" "" ${ARGN})
|
||||
add_executable(${name} ${name}.cc ${add_fmt_test_UNPARSED_ARGUMENTS})
|
||||
target_link_libraries(${name} test-main)
|
||||
if (NOT add_fmt_test_CUSTOM_LINK)
|
||||
target_link_libraries(${name} format)
|
||||
cmake_parse_arguments(ADD_FMT_TEST "HEADER_ONLY;MODULE" "" "" ${ARGN})
|
||||
|
||||
set(sources ${name}.cc ${ADD_FMT_TEST_UNPARSED_ARGUMENTS})
|
||||
if (ADD_FMT_TEST_HEADER_ONLY)
|
||||
set(sources ${sources} ${TEST_MAIN_SRC} ../src/os.cc)
|
||||
set(libs gtest fmt-header-only)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-weak-vtables)
|
||||
endif ()
|
||||
elseif (ADD_FMT_TEST_MODULE)
|
||||
set(libs test-main test-module)
|
||||
set_source_files_properties(${name}.cc PROPERTIES OBJECT_DEPENDS test-module)
|
||||
else ()
|
||||
set(libs test-main fmt)
|
||||
endif ()
|
||||
add_test(${name} ${name})
|
||||
add_executable(${name} ${sources})
|
||||
target_link_libraries(${name} ${libs})
|
||||
|
||||
if (ADD_FMT_TEST_HEADER_ONLY AND NOT FMT_UNICODE)
|
||||
target_compile_definitions(${name} PUBLIC FMT_UNICODE=0)
|
||||
endif ()
|
||||
|
||||
# Define if certain C++ features can be used.
|
||||
if (FMT_PEDANTIC)
|
||||
target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
endif ()
|
||||
if (FMT_WERROR)
|
||||
target_compile_options(${name} PRIVATE ${WERROR_FLAG})
|
||||
endif ()
|
||||
add_test(NAME ${name} COMMAND ${name})
|
||||
endfunction()
|
||||
|
||||
if (FMT_MODULE)
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
add_fmt_test(args-test)
|
||||
add_fmt_test(base-test)
|
||||
add_fmt_test(assert-test)
|
||||
add_fmt_test(chrono-test)
|
||||
add_fmt_test(color-test)
|
||||
add_fmt_test(gtest-extra-test)
|
||||
add_fmt_test(format-test)
|
||||
add_fmt_test(format-impl-test CUSTOM_LINK)
|
||||
add_fmt_test(format-test mock-allocator.h)
|
||||
if (MSVC)
|
||||
target_compile_options(format-test PRIVATE /bigobj)
|
||||
endif ()
|
||||
if (NOT (MSVC AND BUILD_SHARED_LIBS))
|
||||
add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc)
|
||||
endif ()
|
||||
add_fmt_test(ostream-test)
|
||||
add_fmt_test(compile-test)
|
||||
add_fmt_test(compile-fp-test)
|
||||
if (MSVC)
|
||||
# Without this option, MSVC returns 199711L for the __cplusplus macro.
|
||||
target_compile_options(compile-fp-test PRIVATE /Zc:__cplusplus)
|
||||
endif()
|
||||
add_fmt_test(printf-test)
|
||||
foreach (target format-test printf-test)
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS
|
||||
"-Wall -Wextra -pedantic -Wno-long-long -Wno-variadic-macros")
|
||||
add_fmt_test(ranges-test ranges-odr-test.cc)
|
||||
add_fmt_test(no-builtin-types-test HEADER_ONLY)
|
||||
|
||||
add_fmt_test(scan-test HEADER_ONLY)
|
||||
check_symbol_exists(strptime "time.h" HAVE_STRPTIME)
|
||||
if (HAVE_STRPTIME)
|
||||
target_compile_definitions(scan-test PRIVATE FMT_HAVE_STRPTIME)
|
||||
endif ()
|
||||
|
||||
add_fmt_test(std-test)
|
||||
try_compile(compile_result_unused
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${CMAKE_CURRENT_LIST_DIR}/detect-stdfs.cc
|
||||
OUTPUT_VARIABLE RAWOUTPUT)
|
||||
string(REGEX REPLACE ".*libfound \"([^\"]*)\".*" "\\1" STDLIBFS "${RAWOUTPUT}")
|
||||
if (STDLIBFS)
|
||||
target_link_libraries(std-test ${STDLIBFS})
|
||||
endif ()
|
||||
add_fmt_test(unicode-test HEADER_ONLY)
|
||||
if (MSVC)
|
||||
target_compile_options(unicode-test PRIVATE /utf-8)
|
||||
endif ()
|
||||
add_fmt_test(xchar-test)
|
||||
add_fmt_test(enforce-checks-test)
|
||||
target_compile_definitions(enforce-checks-test PRIVATE
|
||||
-DFMT_ENFORCE_COMPILE_STRING)
|
||||
|
||||
add_executable(perf-sanity perf-sanity.cc)
|
||||
target_link_libraries(perf-sanity fmt::fmt)
|
||||
|
||||
if (FMT_MODULE)
|
||||
# The tests need {fmt} to be compiled as traditional library
|
||||
# because of visibility of implementation details.
|
||||
# If module support is present the module tests require a
|
||||
# test-only module to be built from {fmt}
|
||||
add_library(test-module OBJECT ${CMAKE_SOURCE_DIR}/src/fmt.cc)
|
||||
target_compile_features(test-module PUBLIC cxx_std_11)
|
||||
target_include_directories(test-module PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
||||
enable_module(test-module)
|
||||
|
||||
add_fmt_test(module-test MODULE test-main.cc)
|
||||
if (MSVC)
|
||||
target_compile_options(test-module PRIVATE /utf-8 /Zc:__cplusplus
|
||||
/Zc:externConstexpr /Zc:inline)
|
||||
target_compile_options(module-test PRIVATE /utf-8 /Zc:__cplusplus
|
||||
/Zc:externConstexpr /Zc:inline)
|
||||
endif ()
|
||||
if (CPP11_FLAG)
|
||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC)
|
||||
foreach (flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if (${flag_var} MATCHES "^(/|-)(MT|MTd)")
|
||||
set(MSVC_STATIC_RUNTIME ON)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (NOT MSVC_STATIC_RUNTIME)
|
||||
add_executable(posix-mock-test
|
||||
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
|
||||
target_include_directories(
|
||||
posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||
target_link_libraries(posix-mock-test gtest)
|
||||
if (FMT_PEDANTIC)
|
||||
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
endif ()
|
||||
endforeach ()
|
||||
add_fmt_test(util-test mock-allocator.h)
|
||||
if (CPP11_FLAG)
|
||||
set_target_properties(util-test PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
|
||||
if (MSVC)
|
||||
target_compile_options(posix-mock-test PRIVATE /utf-8)
|
||||
endif ()
|
||||
add_test(NAME posix-mock-test COMMAND posix-mock-test)
|
||||
add_fmt_test(os-test)
|
||||
endif ()
|
||||
|
||||
foreach (src ${FMT_SOURCES})
|
||||
set(FMT_TEST_SOURCES ${FMT_TEST_SOURCES} ../${src})
|
||||
endforeach ()
|
||||
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
class C { void operator=(const C&); };
|
||||
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
|
||||
HAVE_TYPE_TRAITS)
|
||||
if (HAVE_TYPE_TRAITS)
|
||||
add_definitions(-DFMT_USE_TYPE_TRAITS=1)
|
||||
if (FMT_PEDANTIC)
|
||||
# Test that the library can be compiled with exceptions disabled.
|
||||
# -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822.
|
||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
endif ()
|
||||
if (HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
add_library(noexception-test ../src/format.cc noexception-test.cc)
|
||||
target_include_directories(
|
||||
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||
target_compile_options(noexception-test PRIVATE -fno-exceptions)
|
||||
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
endif ()
|
||||
|
||||
# Test that the library compiles without locale.
|
||||
add_library(nolocale-test ../src/format.cc)
|
||||
target_include_directories(
|
||||
nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||
target_compile_definitions(
|
||||
nolocale-test PRIVATE FMT_STATIC_THOUSANDS_SEPARATOR=1)
|
||||
endif ()
|
||||
|
||||
add_executable(macro-test macro-test.cc ${FMT_TEST_SOURCES} ${TEST_MAIN_SRC})
|
||||
set_target_properties(macro-test
|
||||
PROPERTIES COMPILE_DEFINITIONS "FMT_USE_VARIADIC_TEMPLATES=0")
|
||||
target_link_libraries(macro-test gmock)
|
||||
# These tests are disabled on Windows because they take too long.
|
||||
# They are disabled on GCC < 4.9 because it can not parse UDLs without
|
||||
# a space after `operator""` but that is an incorrect syntax for any more
|
||||
# modern compiler.
|
||||
if (FMT_PEDANTIC AND NOT WIN32 AND NOT (
|
||||
CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND
|
||||
CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9))
|
||||
# Test if incorrect API usages produce compilation error.
|
||||
add_test(compile-error-test ${CMAKE_CTEST_COMMAND}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/compile-error-test"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/compile-error-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
||||
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
|
||||
"-DFMT_DIR=${CMAKE_SOURCE_DIR}")
|
||||
|
||||
if (HAVE_OPEN)
|
||||
add_executable(posix-test posix-test.cc ${FMT_TEST_SOURCES} ${TEST_MAIN_SRC})
|
||||
set_target_properties(posix-test
|
||||
PROPERTIES COMPILE_DEFINITIONS "FMT_INCLUDE_POSIX_TEST=1")
|
||||
target_link_libraries(posix-test gmock)
|
||||
add_test(posix-test posix-test)
|
||||
# Test if the targets are found from the build directory.
|
||||
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
||||
-C ${CMAKE_BUILD_TYPE}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/find-package-test"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/find-package-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
||||
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||
"-DFMT_DIR=${PROJECT_BINARY_DIR}"
|
||||
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
|
||||
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||
|
||||
# Test if the targets are found when add_subdirectory is used.
|
||||
add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
|
||||
-C ${CMAKE_BUILD_TYPE}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/add-subdirectory-test"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
|
||||
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||
endif ()
|
||||
|
||||
# Test that the library can be compiled with exceptions disabled.
|
||||
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
if (HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
add_library(noexception-test ../format.cc)
|
||||
set_target_properties(noexception-test
|
||||
PROPERTIES COMPILE_FLAGS -fno-exceptions)
|
||||
# This test is disabled on Windows because it is POSIX-specific.
|
||||
if (FMT_PEDANTIC AND NOT WIN32)
|
||||
add_test(static-export-test ${CMAKE_CTEST_COMMAND}
|
||||
-C ${CMAKE_BUILD_TYPE}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/static-export-test"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/static-export-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||
endif ()
|
||||
|
||||
add_test(compile-test ${CMAKE_CTEST_COMMAND}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/compile-test"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/compile-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM})
|
||||
# Activate optional CUDA tests if CUDA is found. For version selection see
|
||||
# https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features
|
||||
if (FMT_CUDA_TEST)
|
||||
if (${CMAKE_VERSION} VERSION_LESS 3.15)
|
||||
find_package(CUDA 9.0)
|
||||
else ()
|
||||
include(CheckLanguage)
|
||||
check_language(CUDA)
|
||||
if (CMAKE_CUDA_COMPILER)
|
||||
enable_language(CUDA OPTIONAL)
|
||||
set(CUDA_FOUND TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (CUDA_FOUND)
|
||||
add_subdirectory(cuda-test)
|
||||
add_test(NAME cuda-test COMMAND fmt-in-cuda-test)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
17
test/add-subdirectory-test/CMakeLists.txt
Normal file
17
test/add-subdirectory-test/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.8...3.25)
|
||||
|
||||
project(fmt-test CXX)
|
||||
|
||||
add_subdirectory(../.. fmt)
|
||||
|
||||
add_executable(library-test main.cc)
|
||||
target_include_directories(library-test PUBLIC SYSTEM .)
|
||||
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
target_link_libraries(library-test fmt::fmt)
|
||||
|
||||
if (TARGET fmt::fmt-header-only)
|
||||
add_executable(header-only-test main.cc)
|
||||
target_include_directories(header-only-test PUBLIC SYSTEM .)
|
||||
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
target_link_libraries(header-only-test fmt::fmt-header-only)
|
||||
endif ()
|
||||
5
test/add-subdirectory-test/main.cc
Normal file
5
test/add-subdirectory-test/main.cc
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "fmt/base.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
|
||||
}
|
||||
202
test/args-test.cc
Normal file
202
test/args-test.cc
Normal file
@@ -0,0 +1,202 @@
|
||||
// Formatting library for C++ - dynamic argument store tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/args.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(args_test, basic) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
store.push_back(42);
|
||||
store.push_back("abc1");
|
||||
store.push_back(1.5f);
|
||||
EXPECT_EQ("42 and abc1 and 1.5", fmt::vformat("{} and {} and {}", store));
|
||||
}
|
||||
|
||||
TEST(args_test, strings_and_refs) {
|
||||
// Unfortunately the tests are compiled with old ABI so strings use COW.
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
char str[] = "1234567890";
|
||||
store.push_back(str);
|
||||
store.push_back(std::cref(str));
|
||||
store.push_back(fmt::string_view{str});
|
||||
str[0] = 'X';
|
||||
|
||||
auto result = fmt::vformat("{} and {} and {}", store);
|
||||
EXPECT_EQ("1234567890 and X234567890 and X234567890", result);
|
||||
}
|
||||
|
||||
struct custom_type {
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<custom_type> {
|
||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const custom_type& p, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return fmt::format_to(ctx.out(), "cust={}", p.i);
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(args_test, custom_format) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto c = custom_type();
|
||||
store.push_back(c);
|
||||
++c.i;
|
||||
store.push_back(c);
|
||||
++c.i;
|
||||
store.push_back(std::cref(c));
|
||||
++c.i;
|
||||
auto result = fmt::vformat("{} and {} and {}", store);
|
||||
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
|
||||
}
|
||||
|
||||
struct to_stringable {
|
||||
friend fmt::string_view to_string_view(to_stringable) { return {}; }
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<to_stringable> {
|
||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(to_stringable, format_context& ctx) const -> decltype(ctx.out()) {
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(args_test, to_string_and_formatter) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto s = to_stringable();
|
||||
store.push_back(s);
|
||||
store.push_back(std::cref(s));
|
||||
fmt::vformat("", store);
|
||||
}
|
||||
|
||||
TEST(args_test, named_int) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
store.push_back(fmt::arg("a1", 42));
|
||||
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
||||
}
|
||||
|
||||
TEST(args_test, named_strings) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
char str[] = "1234567890";
|
||||
store.push_back(fmt::arg("a1", str));
|
||||
store.push_back(fmt::arg("a2", std::cref(str)));
|
||||
str[0] = 'X';
|
||||
EXPECT_EQ("1234567890 and X234567890", fmt::vformat("{a1} and {a2}", store));
|
||||
}
|
||||
|
||||
TEST(args_test, named_arg_by_ref) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
char band[] = "Rolling Stones";
|
||||
store.push_back(fmt::arg("band", std::cref(band)));
|
||||
band[9] = 'c'; // Changing band affects the output.
|
||||
EXPECT_EQ(fmt::vformat("{band}", store), "Rolling Scones");
|
||||
}
|
||||
|
||||
TEST(args_test, named_custom_format) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto c = custom_type();
|
||||
store.push_back(fmt::arg("c1", c));
|
||||
++c.i;
|
||||
store.push_back(fmt::arg("c2", c));
|
||||
++c.i;
|
||||
store.push_back(fmt::arg("c_ref", std::cref(c)));
|
||||
++c.i;
|
||||
auto result = fmt::vformat("{c1} and {c2} and {c_ref}", store);
|
||||
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
|
||||
}
|
||||
|
||||
TEST(args_test, clear) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
store.push_back(42);
|
||||
|
||||
auto result = fmt::vformat("{}", store);
|
||||
EXPECT_EQ("42", result);
|
||||
|
||||
store.push_back(43);
|
||||
result = fmt::vformat("{} and {}", store);
|
||||
EXPECT_EQ("42 and 43", result);
|
||||
|
||||
store.clear();
|
||||
store.push_back(44);
|
||||
result = fmt::vformat("{}", store);
|
||||
EXPECT_EQ("44", result);
|
||||
}
|
||||
|
||||
TEST(args_test, reserve) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
store.reserve(2, 1);
|
||||
store.push_back(1.5f);
|
||||
store.push_back(fmt::arg("a", 42));
|
||||
auto result = fmt::vformat("{} and {a}", store);
|
||||
EXPECT_EQ("1.5 and 42", result);
|
||||
}
|
||||
|
||||
struct copy_throwable {
|
||||
copy_throwable() {}
|
||||
copy_throwable(const copy_throwable&) { throw "deal with it"; }
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<copy_throwable> {
|
||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
auto format(copy_throwable, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(args_test, throw_on_copy) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
store.push_back(std::string("foo"));
|
||||
try {
|
||||
store.push_back(copy_throwable());
|
||||
} catch (...) {
|
||||
}
|
||||
EXPECT_EQ(fmt::vformat("{}", store), "foo");
|
||||
}
|
||||
|
||||
TEST(args_test, move_constructor) {
|
||||
using store_type = fmt::dynamic_format_arg_store<fmt::format_context>;
|
||||
auto store = std::unique_ptr<store_type>(new store_type());
|
||||
store->push_back(42);
|
||||
store->push_back(std::string("foo"));
|
||||
store->push_back(fmt::arg("a1", "foo"));
|
||||
auto moved_store = std::move(*store);
|
||||
store.reset();
|
||||
EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo");
|
||||
}
|
||||
|
||||
TEST(args_test, size) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
EXPECT_EQ(store.size(), 0);
|
||||
|
||||
store.push_back(42);
|
||||
EXPECT_EQ(store.size(), 1);
|
||||
|
||||
store.push_back("Molybdenum");
|
||||
EXPECT_EQ(store.size(), 2);
|
||||
|
||||
store.clear();
|
||||
EXPECT_EQ(store.size(), 0);
|
||||
}
|
||||
31
test/assert-test.cc
Normal file
31
test/assert-test.cc
Normal file
@@ -0,0 +1,31 @@
|
||||
// Formatting library for C++ - FMT_ASSERT test
|
||||
//
|
||||
// It is a separate test to minimize the number of EXPECT_DEBUG_DEATH checks
|
||||
// which are slow on some platforms. In other tests FMT_ASSERT is made to throw
|
||||
// an exception which is much faster and easier to check.
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/base.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(assert_test, fail) {
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
EXPECT_DEBUG_DEATH(FMT_ASSERT(false, "don't panic!"), "don't panic!");
|
||||
#else
|
||||
fmt::print("warning: death tests are not supported\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(assert_test, dangling_else) {
|
||||
bool test_condition = false;
|
||||
bool executed_else = false;
|
||||
if (test_condition)
|
||||
FMT_ASSERT(true, "");
|
||||
else
|
||||
executed_else = true;
|
||||
EXPECT_TRUE(executed_else);
|
||||
}
|
||||
886
test/base-test.cc
Normal file
886
test/base-test.cc
Normal file
@@ -0,0 +1,886 @@
|
||||
// Formatting library for C++ - core tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
// clang-format off
|
||||
#include "test-assert.h"
|
||||
// clang-format on
|
||||
|
||||
#include "fmt/base.h"
|
||||
|
||||
#include <climits> // INT_MAX
|
||||
#include <cstring> // std::strlen
|
||||
#include <functional> // std::equal_to
|
||||
#include <iterator> // std::back_insert_iterator, std::distance
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <string> // std::string
|
||||
#include <type_traits> // std::is_same
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
using fmt::string_view;
|
||||
using fmt::detail::buffer;
|
||||
|
||||
using testing::_;
|
||||
using testing::Invoke;
|
||||
using testing::Return;
|
||||
|
||||
#ifdef FMT_FORMAT_H_
|
||||
# error core-test includes format.h
|
||||
#endif
|
||||
|
||||
fmt::appender copy(fmt::string_view s, fmt::appender out) {
|
||||
for (char c : s) *out++ = c;
|
||||
return out;
|
||||
}
|
||||
|
||||
TEST(string_view_test, value_type) {
|
||||
static_assert(std::is_same<string_view::value_type, char>::value, "");
|
||||
}
|
||||
|
||||
TEST(string_view_test, ctor) {
|
||||
EXPECT_STREQ("abc", fmt::string_view("abc").data());
|
||||
EXPECT_EQ(3u, fmt::string_view("abc").size());
|
||||
|
||||
EXPECT_STREQ("defg", fmt::string_view(std::string("defg")).data());
|
||||
EXPECT_EQ(4u, fmt::string_view(std::string("defg")).size());
|
||||
}
|
||||
|
||||
TEST(string_view_test, length) {
|
||||
// Test that string_view::size() returns string length, not buffer size.
|
||||
char str[100] = "some string";
|
||||
EXPECT_EQ(std::strlen(str), string_view(str).size());
|
||||
EXPECT_LT(std::strlen(str), sizeof(str));
|
||||
}
|
||||
|
||||
// Check string_view's comparison operator.
|
||||
template <template <typename> class Op> void check_op() {
|
||||
const char* inputs[] = {"foo", "fop", "fo"};
|
||||
size_t num_inputs = sizeof(inputs) / sizeof(*inputs);
|
||||
for (size_t i = 0; i < num_inputs; ++i) {
|
||||
for (size_t j = 0; j < num_inputs; ++j) {
|
||||
string_view lhs(inputs[i]), rhs(inputs[j]);
|
||||
EXPECT_EQ(Op<int>()(lhs.compare(rhs), 0), Op<string_view>()(lhs, rhs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(string_view_test, compare) {
|
||||
EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0);
|
||||
EXPECT_GT(string_view("fop").compare(string_view("foo")), 0);
|
||||
EXPECT_LT(string_view("foo").compare(string_view("fop")), 0);
|
||||
EXPECT_GT(string_view("foo").compare(string_view("fo")), 0);
|
||||
EXPECT_LT(string_view("fo").compare(string_view("foo")), 0);
|
||||
|
||||
EXPECT_TRUE(string_view("foo").starts_with('f'));
|
||||
EXPECT_FALSE(string_view("foo").starts_with('o'));
|
||||
EXPECT_FALSE(string_view().starts_with('o'));
|
||||
|
||||
EXPECT_TRUE(string_view("foo").starts_with("fo"));
|
||||
EXPECT_TRUE(string_view("foo").starts_with("foo"));
|
||||
EXPECT_FALSE(string_view("foo").starts_with("fooo"));
|
||||
EXPECT_FALSE(string_view().starts_with("fooo"));
|
||||
|
||||
check_op<std::equal_to>();
|
||||
check_op<std::not_equal_to>();
|
||||
check_op<std::less>();
|
||||
check_op<std::less_equal>();
|
||||
check_op<std::greater>();
|
||||
check_op<std::greater_equal>();
|
||||
}
|
||||
|
||||
TEST(base_test, is_locking) {
|
||||
EXPECT_FALSE(fmt::detail::is_locking<const char(&)[3]>());
|
||||
}
|
||||
|
||||
TEST(base_test, is_output_iterator) {
|
||||
EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value));
|
||||
EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value));
|
||||
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string, char>::value));
|
||||
EXPECT_TRUE(
|
||||
(fmt::detail::is_output_iterator<std::back_insert_iterator<std::string>,
|
||||
char>::value));
|
||||
EXPECT_TRUE(
|
||||
(fmt::detail::is_output_iterator<std::string::iterator, char>::value));
|
||||
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string::const_iterator,
|
||||
char>::value));
|
||||
}
|
||||
|
||||
TEST(base_test, is_back_insert_iterator) {
|
||||
EXPECT_TRUE(fmt::detail::is_back_insert_iterator<
|
||||
std::back_insert_iterator<std::string>>::value);
|
||||
EXPECT_FALSE(fmt::detail::is_back_insert_iterator<
|
||||
std::front_insert_iterator<std::string>>::value);
|
||||
}
|
||||
|
||||
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
||||
TEST(buffer_test, noncopyable) {
|
||||
EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value);
|
||||
# if !FMT_MSC_VERSION
|
||||
// std::is_copy_assignable is broken in MSVC2013.
|
||||
EXPECT_FALSE(std::is_copy_assignable<buffer<char>>::value);
|
||||
# endif
|
||||
}
|
||||
|
||||
TEST(buffer_test, nonmoveable) {
|
||||
EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value);
|
||||
# if !FMT_MSC_VERSION
|
||||
// std::is_move_assignable is broken in MSVC2013.
|
||||
EXPECT_FALSE(std::is_move_assignable<buffer<char>>::value);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(buffer_test, indestructible) {
|
||||
static_assert(!std::is_destructible<fmt::detail::buffer<int>>(),
|
||||
"buffer's destructor is protected");
|
||||
}
|
||||
|
||||
template <typename T> struct mock_buffer final : buffer<T> {
|
||||
MOCK_METHOD(size_t, do_grow, (size_t));
|
||||
|
||||
static void grow(buffer<T>& buf, size_t capacity) {
|
||||
auto& self = static_cast<mock_buffer&>(buf);
|
||||
self.set(buf.data(), self.do_grow(capacity));
|
||||
}
|
||||
|
||||
mock_buffer(T* data = nullptr, size_t buf_capacity = 0) : buffer<T>(grow) {
|
||||
this->set(data, buf_capacity);
|
||||
ON_CALL(*this, do_grow(_)).WillByDefault(Invoke([](size_t capacity) {
|
||||
return capacity;
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
TEST(buffer_test, ctor) {
|
||||
{
|
||||
mock_buffer<int> buffer;
|
||||
EXPECT_EQ(nullptr, buffer.data());
|
||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
||||
EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
|
||||
}
|
||||
{
|
||||
int dummy;
|
||||
mock_buffer<int> buffer(&dummy);
|
||||
EXPECT_EQ(&dummy, &buffer[0]);
|
||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
||||
EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
|
||||
}
|
||||
{
|
||||
int dummy;
|
||||
size_t capacity = std::numeric_limits<size_t>::max();
|
||||
mock_buffer<int> buffer(&dummy, capacity);
|
||||
EXPECT_EQ(&dummy, &buffer[0]);
|
||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
||||
EXPECT_EQ(capacity, buffer.capacity());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(buffer_test, access) {
|
||||
char data[10];
|
||||
mock_buffer<char> buffer(data, sizeof(data));
|
||||
buffer[0] = 11;
|
||||
EXPECT_EQ(11, buffer[0]);
|
||||
buffer[3] = 42;
|
||||
EXPECT_EQ(42, *(&buffer[0] + 3));
|
||||
const fmt::detail::buffer<char>& const_buffer = buffer;
|
||||
EXPECT_EQ(42, const_buffer[3]);
|
||||
}
|
||||
|
||||
TEST(buffer_test, try_resize) {
|
||||
char data[123];
|
||||
mock_buffer<char> buffer(data, sizeof(data));
|
||||
buffer[10] = 42;
|
||||
EXPECT_EQ(42, buffer[10]);
|
||||
buffer.try_resize(20);
|
||||
EXPECT_EQ(20u, buffer.size());
|
||||
EXPECT_EQ(123u, buffer.capacity());
|
||||
EXPECT_EQ(42, buffer[10]);
|
||||
buffer.try_resize(5);
|
||||
EXPECT_EQ(5u, buffer.size());
|
||||
EXPECT_EQ(123u, buffer.capacity());
|
||||
EXPECT_EQ(42, buffer[10]);
|
||||
// Check if try_resize calls grow.
|
||||
EXPECT_CALL(buffer, do_grow(124));
|
||||
buffer.try_resize(124);
|
||||
EXPECT_CALL(buffer, do_grow(200));
|
||||
buffer.try_resize(200);
|
||||
}
|
||||
|
||||
TEST(buffer_test, try_resize_partial) {
|
||||
char data[10];
|
||||
mock_buffer<char> buffer(data, sizeof(data));
|
||||
EXPECT_CALL(buffer, do_grow(20)).WillOnce(Return(15));
|
||||
buffer.try_resize(20);
|
||||
EXPECT_EQ(buffer.capacity(), 15);
|
||||
EXPECT_EQ(buffer.size(), 15);
|
||||
}
|
||||
|
||||
TEST(buffer_test, clear) {
|
||||
mock_buffer<char> buffer;
|
||||
EXPECT_CALL(buffer, do_grow(20));
|
||||
buffer.try_resize(20);
|
||||
buffer.try_resize(0);
|
||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
||||
EXPECT_EQ(20u, buffer.capacity());
|
||||
}
|
||||
|
||||
TEST(buffer_test, append) {
|
||||
char data[15];
|
||||
mock_buffer<char> buffer(data, 10);
|
||||
auto test = "test";
|
||||
buffer.append(test, test + 5);
|
||||
EXPECT_STREQ(test, &buffer[0]);
|
||||
EXPECT_EQ(5u, buffer.size());
|
||||
buffer.try_resize(10);
|
||||
EXPECT_CALL(buffer, do_grow(12));
|
||||
buffer.append(test, test + 2);
|
||||
EXPECT_EQ('t', buffer[10]);
|
||||
EXPECT_EQ('e', buffer[11]);
|
||||
EXPECT_EQ(12u, buffer.size());
|
||||
}
|
||||
|
||||
TEST(buffer_test, append_partial) {
|
||||
char data[10];
|
||||
mock_buffer<char> buffer(data, sizeof(data));
|
||||
testing::InSequence seq;
|
||||
EXPECT_CALL(buffer, do_grow(15)).WillOnce(Return(10));
|
||||
EXPECT_CALL(buffer, do_grow(15)).WillOnce(Invoke([&buffer](size_t) {
|
||||
EXPECT_EQ(fmt::string_view(buffer.data(), buffer.size()), "0123456789");
|
||||
buffer.clear();
|
||||
return 10;
|
||||
}));
|
||||
auto test = "0123456789abcde";
|
||||
buffer.append(test, test + 15);
|
||||
}
|
||||
|
||||
TEST(buffer_test, append_allocates_enough_storage) {
|
||||
char data[19];
|
||||
mock_buffer<char> buffer(data, 10);
|
||||
auto test = "abcdefgh";
|
||||
buffer.try_resize(10);
|
||||
EXPECT_CALL(buffer, do_grow(19));
|
||||
buffer.append(test, test + 9);
|
||||
}
|
||||
|
||||
TEST(base_test, get_buffer) {
|
||||
mock_buffer<char> buffer;
|
||||
void* buffer_ptr = &buffer;
|
||||
auto&& appender_result = fmt::detail::get_buffer<char>(fmt::appender(buffer));
|
||||
EXPECT_EQ(&appender_result, buffer_ptr);
|
||||
auto&& back_inserter_result =
|
||||
fmt::detail::get_buffer<char>(std::back_inserter(buffer));
|
||||
EXPECT_EQ(&back_inserter_result, buffer_ptr);
|
||||
}
|
||||
|
||||
struct test_struct {};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <typename Char> struct formatter<test_struct, Char> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(test_struct, format_context& ctx) const -> decltype(ctx.out()) {
|
||||
return copy("test", ctx.out());
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(arg_test, format_args) {
|
||||
auto args = fmt::format_args();
|
||||
EXPECT_FALSE(args.get(1));
|
||||
}
|
||||
|
||||
// Use a unique result type to make sure that there are no undesirable
|
||||
// conversions.
|
||||
struct test_result {};
|
||||
|
||||
template <typename T> struct mock_visitor {
|
||||
template <typename U> struct result {
|
||||
using type = test_result;
|
||||
};
|
||||
|
||||
mock_visitor() {
|
||||
ON_CALL(*this, visit(_)).WillByDefault(Return(test_result()));
|
||||
}
|
||||
|
||||
MOCK_METHOD(test_result, visit, (T));
|
||||
MOCK_METHOD(void, unexpected, ());
|
||||
|
||||
auto operator()(T value) -> test_result { return visit(value); }
|
||||
|
||||
template <typename U> auto operator()(U) -> test_result {
|
||||
unexpected();
|
||||
return test_result();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct visit_type {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
#define VISIT_TYPE(type_, visit_type_) \
|
||||
template <> struct visit_type<type_> { \
|
||||
using type = visit_type_; \
|
||||
}
|
||||
|
||||
VISIT_TYPE(signed char, int);
|
||||
VISIT_TYPE(unsigned char, unsigned);
|
||||
VISIT_TYPE(short, int);
|
||||
VISIT_TYPE(unsigned short, unsigned);
|
||||
|
||||
#if LONG_MAX == INT_MAX
|
||||
VISIT_TYPE(long, int);
|
||||
VISIT_TYPE(unsigned long, unsigned);
|
||||
#else
|
||||
VISIT_TYPE(long, long long);
|
||||
VISIT_TYPE(unsigned long, unsigned long long);
|
||||
#endif
|
||||
|
||||
#if FMT_BUILTIN_TYPES
|
||||
# define CHECK_ARG(expected, value) \
|
||||
{ \
|
||||
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||
EXPECT_CALL(visitor, visit(expected)); \
|
||||
auto var = value; \
|
||||
fmt::basic_format_arg<fmt::format_context>(var).visit(visitor); \
|
||||
}
|
||||
#else
|
||||
# define CHECK_ARG(expected, value)
|
||||
#endif
|
||||
|
||||
#define CHECK_ARG_SIMPLE(value) \
|
||||
{ \
|
||||
using value_type = decltype(value); \
|
||||
typename visit_type<value_type>::type expected = value; \
|
||||
CHECK_ARG(expected, value) \
|
||||
}
|
||||
|
||||
template <typename T> class numeric_arg_test : public testing::Test {};
|
||||
|
||||
#if FMT_BUILTIN_TYPES
|
||||
using test_types =
|
||||
testing::Types<bool, signed char, unsigned char, short, unsigned short, int,
|
||||
unsigned, long, unsigned long, long long, unsigned long long,
|
||||
float, double, long double>;
|
||||
#else
|
||||
using test_types = testing::Types<int>;
|
||||
#endif
|
||||
TYPED_TEST_SUITE(numeric_arg_test, test_types);
|
||||
|
||||
template <typename T, fmt::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||
auto test_value() -> T {
|
||||
return static_cast<T>(42);
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
fmt::enable_if_t<std::is_floating_point<T>::value, int> = 0>
|
||||
auto test_value() -> T {
|
||||
return static_cast<T>(4.2);
|
||||
}
|
||||
|
||||
TYPED_TEST(numeric_arg_test, make_and_visit) {
|
||||
CHECK_ARG_SIMPLE(test_value<TypeParam>());
|
||||
CHECK_ARG_SIMPLE(std::numeric_limits<TypeParam>::min());
|
||||
CHECK_ARG_SIMPLE(std::numeric_limits<TypeParam>::max());
|
||||
}
|
||||
|
||||
TEST(arg_test, char_arg) { CHECK_ARG('a', 'a'); }
|
||||
|
||||
TEST(arg_test, string_arg) {
|
||||
char str_data[] = "test";
|
||||
char* str = str_data;
|
||||
const char* cstr = str;
|
||||
CHECK_ARG(cstr, str);
|
||||
|
||||
auto sv = fmt::string_view(str);
|
||||
CHECK_ARG(sv, std::string(str));
|
||||
}
|
||||
|
||||
TEST(arg_test, pointer_arg) {
|
||||
void* p = nullptr;
|
||||
const void* cp = nullptr;
|
||||
CHECK_ARG(cp, p);
|
||||
CHECK_ARG_SIMPLE(cp);
|
||||
}
|
||||
|
||||
TEST(arg_test, volatile_pointer_arg) {
|
||||
const void* p = nullptr;
|
||||
volatile int* vip = nullptr;
|
||||
const volatile int* cvip = nullptr;
|
||||
CHECK_ARG(p, static_cast<volatile void*>(vip));
|
||||
CHECK_ARG(p, static_cast<const volatile void*>(cvip));
|
||||
}
|
||||
|
||||
struct check_custom {
|
||||
auto operator()(fmt::basic_format_arg<fmt::format_context>::handle h) const
|
||||
-> test_result {
|
||||
struct test_buffer final : fmt::detail::buffer<char> {
|
||||
char data[10];
|
||||
test_buffer()
|
||||
: fmt::detail::buffer<char>([](buffer<char>&, size_t) {}, data, 0,
|
||||
10) {}
|
||||
} buffer;
|
||||
auto parse_ctx = fmt::format_parse_context("");
|
||||
auto ctx = fmt::format_context(fmt::appender(buffer), fmt::format_args());
|
||||
h.format(parse_ctx, ctx);
|
||||
EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
|
||||
return test_result();
|
||||
}
|
||||
};
|
||||
|
||||
TEST(arg_test, custom_arg) {
|
||||
auto test = test_struct();
|
||||
using visitor =
|
||||
mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>;
|
||||
auto&& v = testing::StrictMock<visitor>();
|
||||
EXPECT_CALL(v, visit(_)).WillOnce(Invoke(check_custom()));
|
||||
fmt::basic_format_arg<fmt::format_context>(test).visit(v);
|
||||
}
|
||||
|
||||
TEST(arg_test, visit_invalid_arg) {
|
||||
auto&& visitor = testing::StrictMock<mock_visitor<fmt::monostate>>();
|
||||
EXPECT_CALL(visitor, visit(_));
|
||||
fmt::basic_format_arg<fmt::format_context>().visit(visitor);
|
||||
}
|
||||
|
||||
#if FMT_USE_CONSTEXPR
|
||||
|
||||
enum class arg_id_result { none, index, name };
|
||||
struct test_arg_id_handler {
|
||||
arg_id_result res = arg_id_result::none;
|
||||
int index = 0;
|
||||
string_view name;
|
||||
|
||||
constexpr void on_index(int i) {
|
||||
res = arg_id_result::index;
|
||||
index = i;
|
||||
}
|
||||
|
||||
constexpr void on_name(string_view n) {
|
||||
res = arg_id_result::name;
|
||||
name = n;
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
constexpr test_arg_id_handler parse_arg_id(const char (&s)[N]) {
|
||||
auto h = test_arg_id_handler();
|
||||
fmt::detail::parse_arg_id(s, s + N, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
TEST(base_test, constexpr_parse_arg_id) {
|
||||
static_assert(parse_arg_id("42:").res == arg_id_result::index, "");
|
||||
static_assert(parse_arg_id("42:").index == 42, "");
|
||||
static_assert(parse_arg_id("foo:").res == arg_id_result::name, "");
|
||||
static_assert(parse_arg_id("foo:").name.size() == 3, "");
|
||||
}
|
||||
|
||||
template <size_t N> constexpr auto parse_test_specs(const char (&s)[N]) {
|
||||
auto ctx = fmt::detail::compile_parse_context<char>(fmt::string_view(s, N),
|
||||
43, nullptr);
|
||||
auto specs = fmt::detail::dynamic_format_specs<>();
|
||||
fmt::detail::parse_format_specs(s, s + N - 1, specs, ctx,
|
||||
fmt::detail::type::float_type);
|
||||
return specs;
|
||||
}
|
||||
|
||||
TEST(base_test, constexpr_parse_format_specs) {
|
||||
static_assert(parse_test_specs("<").align() == fmt::align::left, "");
|
||||
static_assert(parse_test_specs("*^").fill_unit<char>() == '*', "");
|
||||
static_assert(parse_test_specs("+").sign() == fmt::sign::plus, "");
|
||||
static_assert(parse_test_specs("-").sign() == fmt::sign::none, "");
|
||||
static_assert(parse_test_specs(" ").sign() == fmt::sign::space, "");
|
||||
static_assert(parse_test_specs("#").alt(), "");
|
||||
static_assert(parse_test_specs("0").align() == fmt::align::numeric, "");
|
||||
static_assert(parse_test_specs("L").localized(), "");
|
||||
static_assert(parse_test_specs("42").width == 42, "");
|
||||
static_assert(parse_test_specs("{42}").width_ref.index == 42, "");
|
||||
static_assert(parse_test_specs(".42").precision == 42, "");
|
||||
static_assert(parse_test_specs(".{42}").precision_ref.index == 42, "");
|
||||
static_assert(parse_test_specs("f").type() == fmt::presentation_type::fixed,
|
||||
"");
|
||||
}
|
||||
|
||||
struct test_format_string_handler {
|
||||
constexpr void on_text(const char*, const char*) {}
|
||||
|
||||
constexpr auto on_arg_id() -> int { return 0; }
|
||||
|
||||
template <typename T> constexpr auto on_arg_id(T) -> int { return 0; }
|
||||
|
||||
constexpr void on_replacement_field(int, const char*) {}
|
||||
|
||||
constexpr auto on_format_specs(int, const char* begin, const char*) -> const
|
||||
char* {
|
||||
return begin;
|
||||
}
|
||||
|
||||
constexpr void on_error(const char*) { error = true; }
|
||||
|
||||
bool error = false;
|
||||
};
|
||||
|
||||
template <size_t N> constexpr bool parse_string(const char (&s)[N]) {
|
||||
auto h = test_format_string_handler();
|
||||
fmt::detail::parse_format_string(fmt::string_view(s, N - 1), h);
|
||||
return !h.error;
|
||||
}
|
||||
|
||||
TEST(base_test, constexpr_parse_format_string) {
|
||||
static_assert(parse_string("foo"), "");
|
||||
static_assert(!parse_string("}"), "");
|
||||
static_assert(parse_string("{}"), "");
|
||||
static_assert(parse_string("{42}"), "");
|
||||
static_assert(parse_string("{foo}"), "");
|
||||
static_assert(parse_string("{:}"), "");
|
||||
}
|
||||
#endif // FMT_USE_CONSTEXPR
|
||||
|
||||
struct enabled_formatter {};
|
||||
struct enabled_ptr_formatter {};
|
||||
struct disabled_formatter {};
|
||||
struct disabled_formatter_convertible {
|
||||
operator int() const { return 42; }
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<enabled_formatter> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
auto format(enabled_formatter, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct formatter<enabled_ptr_formatter*> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
auto format(enabled_ptr_formatter*, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
struct const_formattable {};
|
||||
struct nonconst_formattable {};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<const_formattable> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(const const_formattable&, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return copy("test", ctx.out());
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct formatter<nonconst_formattable> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(nonconst_formattable&, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return copy("test", ctx.out());
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
struct convertible_to_pointer {
|
||||
operator const int*() const { return nullptr; }
|
||||
};
|
||||
|
||||
struct convertible_to_pointer_formattable {
|
||||
operator const int*() const { return nullptr; }
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<convertible_to_pointer_formattable> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(convertible_to_pointer_formattable, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return copy("test", ctx.out());
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
enum class unformattable_scoped_enum {};
|
||||
|
||||
TEST(base_test, is_formattable) {
|
||||
EXPECT_FALSE(fmt::is_formattable<void>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<wchar_t>::value);
|
||||
#ifdef __cpp_char8_t
|
||||
EXPECT_FALSE(fmt::is_formattable<char8_t>::value);
|
||||
#endif
|
||||
EXPECT_FALSE(fmt::is_formattable<char16_t>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<char32_t>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<signed char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<unsigned char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const signed char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const unsigned char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const wchar_t*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const wchar_t[3]>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<enabled_ptr_formatter*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<disabled_formatter>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<disabled_formatter_convertible>::value);
|
||||
|
||||
EXPECT_TRUE(fmt::is_formattable<enabled_formatter>::value);
|
||||
EXPECT_TRUE(fmt::is_formattable<const_formattable&>::value);
|
||||
EXPECT_TRUE(fmt::is_formattable<const const_formattable&>::value);
|
||||
|
||||
EXPECT_TRUE(fmt::is_formattable<nonconst_formattable&>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const nonconst_formattable&>::value);
|
||||
|
||||
EXPECT_FALSE(fmt::is_formattable<convertible_to_pointer>::value);
|
||||
const auto f = convertible_to_pointer_formattable();
|
||||
auto str = std::string();
|
||||
fmt::format_to(std::back_inserter(str), "{}", f);
|
||||
EXPECT_EQ(str, "test");
|
||||
|
||||
EXPECT_FALSE(fmt::is_formattable<void (*)()>::value);
|
||||
|
||||
struct s;
|
||||
EXPECT_FALSE(fmt::is_formattable<int(s::*)>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<int (s::*)()>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<unformattable_scoped_enum>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<unformattable_scoped_enum>::value);
|
||||
}
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
TEST(base_test, formattable_concept) {
|
||||
static_assert(fmt::formattable<char>);
|
||||
static_assert(fmt::formattable<char&>);
|
||||
static_assert(fmt::formattable<char&&>);
|
||||
static_assert(fmt::formattable<const char>);
|
||||
static_assert(fmt::formattable<const char&>);
|
||||
static_assert(fmt::formattable<const char&&>);
|
||||
static_assert(fmt::formattable<int>);
|
||||
static_assert(!fmt::formattable<wchar_t>);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(base_test, format_to) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", 42);
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
|
||||
TEST(base_test, format_to_array) {
|
||||
char buffer[4];
|
||||
auto result = fmt::format_to(buffer, "{}", 12345);
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ(buffer + 4, result.out);
|
||||
EXPECT_EQ("1234", fmt::string_view(buffer, 4));
|
||||
|
||||
char* out = nullptr;
|
||||
EXPECT_THROW(out = result, std::runtime_error);
|
||||
(void)out;
|
||||
|
||||
result = fmt::format_to(buffer, "{:s}", "foobar");
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ(buffer + 4, result.out);
|
||||
EXPECT_EQ("foob", fmt::string_view(buffer, 4));
|
||||
|
||||
buffer[0] = 'x';
|
||||
buffer[1] = 'x';
|
||||
buffer[2] = 'x';
|
||||
buffer[3] = 'x';
|
||||
result = fmt::format_to(buffer, "{}", 'A');
|
||||
EXPECT_EQ(1, std::distance(&buffer[0], result.out));
|
||||
EXPECT_FALSE(result.truncated);
|
||||
EXPECT_EQ(buffer + 1, result.out);
|
||||
EXPECT_EQ("Axxx", fmt::string_view(buffer, 4));
|
||||
|
||||
result = fmt::format_to(buffer, "{}{} ", 'B', 'C');
|
||||
EXPECT_EQ(3, std::distance(&buffer[0], result.out));
|
||||
EXPECT_FALSE(result.truncated);
|
||||
EXPECT_EQ(buffer + 3, result.out);
|
||||
EXPECT_EQ("BC x", fmt::string_view(buffer, 4));
|
||||
|
||||
result = fmt::format_to(buffer, "{}", "ABCDE");
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ("ABCD", fmt::string_view(buffer, 4));
|
||||
|
||||
result = fmt::format_to(buffer, "{}", std::string(1000, '*').c_str());
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ("****", fmt::string_view(buffer, 4));
|
||||
}
|
||||
|
||||
// Test that check is not found by ADL.
|
||||
template <typename T> void check(T);
|
||||
TEST(base_test, adl_check) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", test_struct());
|
||||
EXPECT_EQ(s, "test");
|
||||
}
|
||||
|
||||
struct implicitly_convertible_to_string_view {
|
||||
operator fmt::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(base_test, no_implicit_conversion_to_string_view) {
|
||||
EXPECT_FALSE(
|
||||
fmt::is_formattable<implicitly_convertible_to_string_view>::value);
|
||||
}
|
||||
|
||||
struct explicitly_convertible_to_string_view {
|
||||
explicit operator fmt::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(base_test, format_explicitly_convertible_to_string_view) {
|
||||
// Types explicitly convertible to string_view are not formattable by
|
||||
// default because it may introduce ODR violations.
|
||||
static_assert(
|
||||
!fmt::is_formattable<explicitly_convertible_to_string_view>::value, "");
|
||||
}
|
||||
|
||||
#if FMT_CPLUSPLUS >= 201703L
|
||||
struct implicitly_convertible_to_std_string_view {
|
||||
operator std::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(base_test, no_implicit_conversion_to_std_string_view) {
|
||||
EXPECT_FALSE(
|
||||
fmt::is_formattable<implicitly_convertible_to_std_string_view>::value);
|
||||
}
|
||||
|
||||
struct explicitly_convertible_to_std_string_view {
|
||||
explicit operator std::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(base_test, format_explicitly_convertible_to_std_string_view) {
|
||||
// Types explicitly convertible to string_view are not formattable by
|
||||
// default because it may introduce ODR violations.
|
||||
static_assert(
|
||||
!fmt::is_formattable<explicitly_convertible_to_std_string_view>::value,
|
||||
"");
|
||||
}
|
||||
#endif // FMT_CPLUSPLUS >= 201703L
|
||||
|
||||
TEST(base_test, has_formatter) {
|
||||
EXPECT_TRUE((fmt::detail::has_formatter<const const_formattable, char>()));
|
||||
EXPECT_FALSE(
|
||||
(fmt::detail::has_formatter<const nonconst_formattable, char>()));
|
||||
}
|
||||
|
||||
TEST(base_test, format_nonconst) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", nonconst_formattable());
|
||||
EXPECT_EQ(s, "test");
|
||||
}
|
||||
|
||||
TEST(base_test, throw_in_buffer_dtor) {
|
||||
enum { buffer_size = 256 };
|
||||
|
||||
struct throwing_iterator {
|
||||
int& count;
|
||||
|
||||
auto operator=(char) -> throwing_iterator& {
|
||||
if (++count > buffer_size) throw std::exception();
|
||||
return *this;
|
||||
}
|
||||
auto operator*() -> throwing_iterator& { return *this; }
|
||||
auto operator++() -> throwing_iterator& { return *this; }
|
||||
auto operator++(int) -> throwing_iterator { return *this; }
|
||||
};
|
||||
|
||||
try {
|
||||
int count = 0;
|
||||
fmt::format_to(throwing_iterator{count}, fmt::runtime("{:{}}{"), "",
|
||||
buffer_size + 1);
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
}
|
||||
|
||||
struct its_a_trap {
|
||||
template <typename T> operator T() const {
|
||||
auto v = T();
|
||||
v.x = 42;
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<its_a_trap> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(its_a_trap, format_context& ctx) const
|
||||
-> decltype(ctx.out()) const {
|
||||
auto out = ctx.out();
|
||||
*out++ = 'x';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(base_test, trappy_conversion) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", its_a_trap());
|
||||
EXPECT_EQ(s, "x");
|
||||
}
|
||||
|
||||
struct custom_container {
|
||||
char data;
|
||||
|
||||
using value_type = char;
|
||||
|
||||
size_t size() const { return 0; }
|
||||
void resize(size_t) {}
|
||||
|
||||
void push_back(char) {}
|
||||
char& operator[](size_t) { return data; }
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct is_contiguous<custom_container> : std::true_type {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(base_test, format_to_custom_container) {
|
||||
auto c = custom_container();
|
||||
fmt::format_to(std::back_inserter(c), "");
|
||||
}
|
||||
|
||||
struct nondeterministic_format_string {
|
||||
mutable int i = 0;
|
||||
FMT_CONSTEXPR operator string_view() const {
|
||||
return string_view("{}", i++ != 0 ? 2 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(base_test, no_repeated_format_string_conversions) {
|
||||
#if !FMT_GCC_VERSION
|
||||
char buf[10];
|
||||
fmt::format_to(buf, nondeterministic_format_string());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(base_test, format_context_accessors) {
|
||||
class copier {
|
||||
static fmt::format_context copy(fmt::appender app,
|
||||
const fmt::format_context& ctx) {
|
||||
return fmt::format_context(std::move(app), ctx.args(), ctx.locale());
|
||||
}
|
||||
};
|
||||
}
|
||||
1088
test/chrono-test.cc
Normal file
1088
test/chrono-test.cc
Normal file
File diff suppressed because it is too large
Load Diff
72
test/color-test.cc
Normal file
72
test/color-test.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
// Formatting library for C++ - color tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/color.h"
|
||||
|
||||
#include <iterator> // std::back_inserter
|
||||
|
||||
#include "gtest-extra.h" // EXPECT_WRITE
|
||||
|
||||
TEST(color_test, format) {
|
||||
EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
|
||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"),
|
||||
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
||||
EXPECT_EQ(
|
||||
fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
|
||||
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::faint, "faint"), "\x1b[2mfaint\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"),
|
||||
"\x1b[3mitalic\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"),
|
||||
"\x1b[4munderline\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::blink, "blink"), "\x1b[5mblink\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::reverse, "reverse"),
|
||||
"\x1b[7mreverse\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::conceal, "conceal"),
|
||||
"\x1b[8mconceal\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"),
|
||||
"\x1b[9mstrikethrough\x1b[0m");
|
||||
EXPECT_EQ(
|
||||
fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
|
||||
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"),
|
||||
"\x1b[1mbold error\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue log"),
|
||||
"\x1b[38;2;000;000;255mblue log\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::text_style(), "hi"), "hi");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "tred"),
|
||||
"\x1b[31mtred\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(bg(fmt::terminal_color::cyan), "tcyan"),
|
||||
"\x1b[46mtcyan\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::bright_green), "tbgreen"),
|
||||
"\x1b[92mtbgreen\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
|
||||
"\x1b[105mtbmagenta\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
|
||||
"\x1b[31mfoo\x1b[0m");
|
||||
EXPECT_EQ(fmt::format("{}{}", fmt::styled("red", fg(fmt::color::red)),
|
||||
fmt::styled("bold", fmt::emphasis::bold)),
|
||||
"\x1b[38;2;255;000;000mred\x1b[0m\x1b[1mbold\x1b[0m");
|
||||
EXPECT_EQ(fmt::format("{}", fmt::styled("bar", fg(fmt::color::blue) |
|
||||
fmt::emphasis::underline)),
|
||||
"\x1b[4m\x1b[38;2;000;000;255mbar\x1b[0m");
|
||||
}
|
||||
|
||||
TEST(color_test, format_to) {
|
||||
auto out = std::string();
|
||||
fmt::format_to(std::back_inserter(out), fg(fmt::rgb(255, 20, 30)),
|
||||
"rgb(255,20,30){}{}{}", 1, 2, 3);
|
||||
EXPECT_EQ(fmt::to_string(out),
|
||||
"\x1b[38;2;255;020;030mrgb(255,20,30)123\x1b[0m");
|
||||
}
|
||||
|
||||
TEST(color_test, print) {
|
||||
EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
|
||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
||||
}
|
||||
215
test/compile-error-test/CMakeLists.txt
Normal file
215
test/compile-error-test/CMakeLists.txt
Normal file
@@ -0,0 +1,215 @@
|
||||
# Test if compile errors are produced where necessary.
|
||||
|
||||
cmake_minimum_required(VERSION 3.8...3.25)
|
||||
project(compile-error-test CXX)
|
||||
|
||||
set(fmt_headers "
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/xchar.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <iostream>
|
||||
")
|
||||
|
||||
set(error_test_names "")
|
||||
set(non_error_test_content "")
|
||||
|
||||
# For error tests (we expect them to produce compilation error):
|
||||
# * adds a name of test into `error_test_names` list
|
||||
# * generates a single source file (with the same name) for each test
|
||||
# For non-error tests (we expect them to compile successfully):
|
||||
# * adds a code segment as separate function to `non_error_test_content`
|
||||
function (expect_compile name code_fragment)
|
||||
cmake_parse_arguments(EXPECT_COMPILE "ERROR" "" "" ${ARGN})
|
||||
string(MAKE_C_IDENTIFIER "${name}" test_name)
|
||||
|
||||
if (EXPECT_COMPILE_ERROR)
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/${test_name}.cc" "
|
||||
${fmt_headers}
|
||||
void ${test_name}() {
|
||||
${code_fragment}
|
||||
}
|
||||
")
|
||||
set(error_test_names_copy "${error_test_names}")
|
||||
list(APPEND error_test_names_copy "${test_name}")
|
||||
set(error_test_names "${error_test_names_copy}" PARENT_SCOPE)
|
||||
else()
|
||||
set(non_error_test_content "
|
||||
${non_error_test_content}
|
||||
void ${test_name}() {
|
||||
${code_fragment}
|
||||
}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction ()
|
||||
|
||||
# Generates a source file for non-error test with `non_error_test_content` and
|
||||
# CMake project file with all error and single non-error test targets.
|
||||
function (run_tests)
|
||||
set(cmake_targets "")
|
||||
foreach(test_name IN LISTS error_test_names)
|
||||
set(cmake_targets "
|
||||
${cmake_targets}
|
||||
add_library(test-${test_name} ${test_name}.cc)
|
||||
target_link_libraries(test-${test_name} PRIVATE fmt::fmt)
|
||||
")
|
||||
endforeach()
|
||||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/non_error_test.cc" "
|
||||
${fmt_headers}
|
||||
${non_error_test_content}
|
||||
")
|
||||
set(cmake_targets "
|
||||
${cmake_targets}
|
||||
add_library(non-error-test non_error_test.cc)
|
||||
target_link_libraries(non-error-test PRIVATE fmt::fmt)
|
||||
")
|
||||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/CMakeLists.txt" "
|
||||
cmake_minimum_required(VERSION 3.8...3.25)
|
||||
project(tests CXX)
|
||||
add_subdirectory(${FMT_DIR} fmt)
|
||||
${cmake_targets}
|
||||
")
|
||||
|
||||
set(build_directory "${CMAKE_CURRENT_BINARY_DIR}/test/build")
|
||||
file(MAKE_DIRECTORY "${build_directory}")
|
||||
execute_process(
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}"
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
||||
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||
"-DCMAKE_GENERATOR=${CMAKE_GENERATOR}"
|
||||
"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
|
||||
"-DFMT_DIR=${FMT_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/test"
|
||||
WORKING_DIRECTORY "${build_directory}"
|
||||
RESULT_VARIABLE result_var
|
||||
OUTPUT_VARIABLE output_var
|
||||
ERROR_VARIABLE output_var)
|
||||
if (NOT result_var EQUAL 0)
|
||||
message(FATAL_ERROR "Unable to configure:\n${output_var}")
|
||||
endif()
|
||||
|
||||
foreach(test_name IN LISTS error_test_names)
|
||||
execute_process(
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" --build "${build_directory}" --target "test-${test_name}"
|
||||
WORKING_DIRECTORY "${build_directory}"
|
||||
RESULT_VARIABLE result_var
|
||||
OUTPUT_VARIABLE output_var
|
||||
ERROR_QUIET)
|
||||
if (result_var EQUAL 0)
|
||||
message(SEND_ERROR "No compile error for \"${test_name}\":\n${output_var}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" --build "${build_directory}" --target "non-error-test"
|
||||
WORKING_DIRECTORY "${build_directory}"
|
||||
RESULT_VARIABLE result_var
|
||||
OUTPUT_VARIABLE output_var
|
||||
ERROR_VARIABLE output_var)
|
||||
if (NOT result_var EQUAL 0)
|
||||
message(SEND_ERROR "Compile error for combined non-error test:\n${output_var}")
|
||||
endif ()
|
||||
endfunction ()
|
||||
|
||||
# Check if the source file skeleton compiles.
|
||||
expect_compile(check "")
|
||||
expect_compile(check-error "compilation_error" ERROR)
|
||||
|
||||
# Formatting a wide character with a narrow format string is forbidden.
|
||||
expect_compile(wide-character-narrow-format-string "fmt::format(L\"{}\", L'a');")
|
||||
expect_compile(wide-character-narrow-format-string-error "fmt::format(\"{}\", L'a');" ERROR)
|
||||
|
||||
# Formatting a wide string with a narrow format string is forbidden.
|
||||
expect_compile(wide-string-narrow-format-string "fmt::format(L\"{}\", L\"foo\");")
|
||||
expect_compile(wide-string-narrow-format-string-error "fmt::format(\"{}\", L\"foo\");" ERROR)
|
||||
|
||||
# Formatting a narrow string with a wide format string is forbidden because
|
||||
# mixing UTF-8 with UTF-16/32 can result in an invalid output.
|
||||
expect_compile(narrow-string-wide-format-string "fmt::format(L\"{}\", L\"foo\");")
|
||||
expect_compile(narrow-string-wide-format-string-error "fmt::format(L\"{}\", \"foo\");" ERROR)
|
||||
|
||||
expect_compile(cast-to-string "
|
||||
struct S {
|
||||
operator std::string() const { return std::string(); }
|
||||
};
|
||||
fmt::format(\"{}\", std::string(S()));
|
||||
")
|
||||
expect_compile(cast-to-string-error "
|
||||
struct S {
|
||||
operator std::string() const { return std::string(); }
|
||||
};
|
||||
fmt::format(\"{}\", S());
|
||||
" ERROR)
|
||||
|
||||
# Formatting a function
|
||||
expect_compile(format-function "
|
||||
void (*f)();
|
||||
fmt::format(\"{}\", fmt::ptr(f));
|
||||
")
|
||||
expect_compile(format-function-error "
|
||||
void (*f)();
|
||||
fmt::format(\"{}\", f);
|
||||
" ERROR)
|
||||
|
||||
# Formatting an unformattable argument should always be a compile time error
|
||||
expect_compile(format-lots-of-arguments-with-unformattable "
|
||||
struct E {};
|
||||
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, E());
|
||||
" ERROR)
|
||||
expect_compile(format-lots-of-arguments-with-function "
|
||||
void (*f)();
|
||||
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, f);
|
||||
" ERROR)
|
||||
|
||||
if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
|
||||
# Compile-time argument type check
|
||||
expect_compile(format-string-number-spec "
|
||||
#ifdef FMT_HAS_CONSTEVAL
|
||||
fmt::format(\"{:d}\", 42);
|
||||
#endif
|
||||
")
|
||||
expect_compile(format-string-number-spec-error "
|
||||
#ifdef FMT_HAS_CONSTEVAL
|
||||
fmt::format(\"{:d}\", \"I am not a number\");
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
" ERROR)
|
||||
expect_compile(print-string-number-spec-error "
|
||||
#ifdef FMT_HAS_CONSTEVAL
|
||||
fmt::print(\"{:d}\", \"I am not a number\");
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
" ERROR)
|
||||
expect_compile(print-stream-string-number-spec-error "
|
||||
#ifdef FMT_HAS_CONSTEVAL
|
||||
fmt::print(std::cout, \"{:d}\", \"I am not a number\");
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
" ERROR)
|
||||
|
||||
# Compile-time argument name check
|
||||
expect_compile(format-string-name "
|
||||
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
using namespace fmt::literals;
|
||||
fmt::print(\"{foo}\", \"foo\"_a=42);
|
||||
#endif
|
||||
")
|
||||
expect_compile(format-string-name-error "
|
||||
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
using namespace fmt::literals;
|
||||
fmt::print(\"{foo}\", \"bar\"_a=42);
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
" ERROR)
|
||||
endif ()
|
||||
|
||||
# Run all tests
|
||||
run_tests()
|
||||
61
test/compile-fp-test.cc
Normal file
61
test/compile-fp-test.cc
Normal file
@@ -0,0 +1,61 @@
|
||||
// Formatting library for C++ - formatting library tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/compile.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#if FMT_USE_CONSTEVAL
|
||||
|
||||
template <size_t max_string_length, typename Char = char> struct test_string {
|
||||
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
|
||||
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
|
||||
}
|
||||
Char buffer[max_string_length]{};
|
||||
};
|
||||
|
||||
template <size_t max_string_length, typename Char = char, typename... Args>
|
||||
consteval auto test_format(auto format, const Args&... args) {
|
||||
test_string<max_string_length, Char> string{};
|
||||
fmt::format_to(string.buffer, format, args...);
|
||||
return string;
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, floating_point) {
|
||||
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{}"), 0.0f));
|
||||
EXPECT_EQ("392.500000", test_format<11>(FMT_COMPILE("{0:f}"), 392.5f));
|
||||
|
||||
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:}"), 0.0));
|
||||
EXPECT_EQ("0.000000", test_format<9>(FMT_COMPILE("{:f}"), 0.0));
|
||||
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:g}"), 0.0));
|
||||
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:}"), 392.65));
|
||||
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:g}"), 392.65));
|
||||
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:G}"), 392.65));
|
||||
EXPECT_EQ("4.9014e+06", test_format<11>(FMT_COMPILE("{:g}"), 4.9014e6));
|
||||
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:f}"), -392.65));
|
||||
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:F}"), -392.65));
|
||||
|
||||
EXPECT_EQ("3.926500e+02", test_format<13>(FMT_COMPILE("{0:e}"), 392.65));
|
||||
EXPECT_EQ("3.926500E+02", test_format<13>(FMT_COMPILE("{0:E}"), 392.65));
|
||||
EXPECT_EQ("+0000392.6", test_format<11>(FMT_COMPILE("{0:+010.4g}"), 392.65));
|
||||
EXPECT_EQ("9223372036854775808.000000",
|
||||
test_format<27>(FMT_COMPILE("{:f}"), 9223372036854775807.0));
|
||||
|
||||
constexpr double nan = std::numeric_limits<double>::quiet_NaN();
|
||||
EXPECT_EQ("nan", test_format<4>(FMT_COMPILE("{}"), nan));
|
||||
EXPECT_EQ("+nan", test_format<5>(FMT_COMPILE("{:+}"), nan));
|
||||
if (std::signbit(-nan))
|
||||
EXPECT_EQ("-nan", test_format<5>(FMT_COMPILE("{}"), -nan));
|
||||
else
|
||||
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
|
||||
|
||||
constexpr double inf = std::numeric_limits<double>::infinity();
|
||||
EXPECT_EQ("inf", test_format<4>(FMT_COMPILE("{}"), inf));
|
||||
EXPECT_EQ("+inf", test_format<5>(FMT_COMPILE("{:+}"), inf));
|
||||
EXPECT_EQ("-inf", test_format<5>(FMT_COMPILE("{}"), -inf));
|
||||
}
|
||||
|
||||
#endif // FMT_USE_CONSTEVAL
|
||||
412
test/compile-test.cc
Normal file
412
test/compile-test.cc
Normal file
@@ -0,0 +1,412 @@
|
||||
// Formatting library for C++ - formatting library tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/compile.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "fmt/chrono.h"
|
||||
#include "fmt/ranges.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest-extra.h"
|
||||
|
||||
TEST(compile_test, compile_fallback) {
|
||||
// FMT_COMPILE should fallback on runtime formatting when `if constexpr` is
|
||||
// not available.
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
|
||||
}
|
||||
|
||||
struct type_with_get {
|
||||
template <int> friend void get(type_with_get);
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<type_with_get> : formatter<int> {
|
||||
template <typename FormatContext>
|
||||
auto format(type_with_get, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
return formatter<int>::format(42, ctx);
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(compile_test, compile_type_with_get) {
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), type_with_get()));
|
||||
}
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
struct test_formattable {};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<test_formattable> : formatter<const char*> {
|
||||
char word_spec = 'f';
|
||||
constexpr auto parse(format_parse_context& ctx) {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it == end || *it == '}') return it;
|
||||
if (it != end && (*it == 'f' || *it == 'b')) word_spec = *it++;
|
||||
if (it != end && *it != '}') throw format_error("invalid format");
|
||||
return it;
|
||||
}
|
||||
template <typename FormatContext>
|
||||
constexpr auto format(test_formattable, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<const char*>::format(word_spec == 'f' ? "foo" : "bar",
|
||||
ctx);
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(compile_test, format_default) {
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42u));
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ll));
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ull));
|
||||
EXPECT_EQ("true", fmt::format(FMT_COMPILE("{}"), true));
|
||||
EXPECT_EQ("x", fmt::format(FMT_COMPILE("{}"), 'x'));
|
||||
EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2));
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable()));
|
||||
auto t = std::chrono::system_clock::now();
|
||||
EXPECT_EQ(fmt::format("{}", t), fmt::format(FMT_COMPILE("{}"), t));
|
||||
# ifdef __cpp_lib_byte
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), std::byte{42}));
|
||||
# endif
|
||||
}
|
||||
|
||||
TEST(compile_test, format_escape) {
|
||||
EXPECT_EQ("\"string\"", fmt::format(FMT_COMPILE("{:?}"), "string"));
|
||||
EXPECT_EQ("prefix \"string\"",
|
||||
fmt::format(FMT_COMPILE("prefix {:?}"), "string"));
|
||||
EXPECT_EQ("\"string\" suffix",
|
||||
fmt::format(FMT_COMPILE("{:?} suffix"), "string"));
|
||||
EXPECT_EQ("\"abc\"", fmt::format(FMT_COMPILE("{0:<5?}"), "abc"));
|
||||
EXPECT_EQ("\"abc\" ", fmt::format(FMT_COMPILE("{0:<7?}"), "abc"));
|
||||
}
|
||||
|
||||
TEST(compile_test, format_wide_string) {
|
||||
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42));
|
||||
}
|
||||
|
||||
TEST(compile_test, format_specs) {
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
|
||||
EXPECT_EQ("1.2 ms ",
|
||||
fmt::format(FMT_COMPILE("{:7.1%Q %q}"),
|
||||
std::chrono::duration<double, std::milli>(1.234)));
|
||||
}
|
||||
|
||||
TEST(compile_test, dynamic_format_specs) {
|
||||
EXPECT_EQ("foo ", fmt::format(FMT_COMPILE("{:{}}"), "foo", 5));
|
||||
EXPECT_EQ(" 3.14", fmt::format(FMT_COMPILE("{:{}.{}f}"), 3.141592, 6, 2));
|
||||
EXPECT_EQ(
|
||||
"=1.234ms=",
|
||||
fmt::format(FMT_COMPILE("{:=^{}.{}}"),
|
||||
std::chrono::duration<double, std::milli>(1.234), 9, 3));
|
||||
}
|
||||
|
||||
TEST(compile_test, manual_ordering) {
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{0}"), 42));
|
||||
EXPECT_EQ(" -42", fmt::format(FMT_COMPILE("{0:4}"), -42));
|
||||
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {1}"), 41, 43));
|
||||
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{1} {0}"), 43, 41));
|
||||
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {2}"), 41, 42, 43));
|
||||
EXPECT_EQ(" 41 43", fmt::format(FMT_COMPILE("{1:{2}} {0:4}"), 43, 41, 4));
|
||||
EXPECT_EQ("42 1.2 ms ",
|
||||
fmt::format(FMT_COMPILE("{0} {1:7.1%Q %q}"), 42,
|
||||
std::chrono::duration<double, std::milli>(1.234)));
|
||||
EXPECT_EQ(
|
||||
"true 42 42 foo 0x1234 foo",
|
||||
fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f,
|
||||
"foo", reinterpret_cast<void*>(0x1234), test_formattable()));
|
||||
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{0}"), 42));
|
||||
}
|
||||
|
||||
TEST(compile_test, named) {
|
||||
auto runtime_named_field_compiled =
|
||||
fmt::detail::compile<decltype(fmt::arg("arg", 42))>(FMT_COMPILE("{arg}"));
|
||||
static_assert(std::is_same_v<decltype(runtime_named_field_compiled),
|
||||
fmt::detail::runtime_named_field<char>>);
|
||||
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), fmt::arg("arg", 42)));
|
||||
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{} {}"), fmt::arg("arg", 41),
|
||||
fmt::arg("arg", 43)));
|
||||
|
||||
EXPECT_EQ("foobar",
|
||||
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"),
|
||||
fmt::arg("a1", "bar")));
|
||||
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{}{a1}"), fmt::arg("a0", "foo"),
|
||||
fmt::arg("a1", "bar")));
|
||||
EXPECT_EQ("foofoo", fmt::format(FMT_COMPILE("{a0}{}"), fmt::arg("a0", "foo"),
|
||||
fmt::arg("a1", "bar")));
|
||||
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{0}{a1}"), fmt::arg("a0", "foo"),
|
||||
fmt::arg("a1", "bar")));
|
||||
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{a0}{1}"), fmt::arg("a0", "foo"),
|
||||
fmt::arg("a1", "bar")));
|
||||
|
||||
EXPECT_EQ("foobar",
|
||||
fmt::format(FMT_COMPILE("{}{a1}"), "foo", fmt::arg("a1", "bar")));
|
||||
EXPECT_EQ("foobar",
|
||||
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a1", "bar"),
|
||||
fmt::arg("a2", "baz"), fmt::arg("a0", "foo")));
|
||||
EXPECT_EQ(" bar foo ",
|
||||
fmt::format(FMT_COMPILE(" {foo} {bar} "), fmt::arg("foo", "bar"),
|
||||
fmt::arg("bar", "foo")));
|
||||
|
||||
EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)),
|
||||
fmt::format_error);
|
||||
|
||||
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
using namespace fmt::literals;
|
||||
auto statically_named_field_compiled =
|
||||
fmt::detail::compile<decltype("arg"_a = 42)>(FMT_COMPILE("{arg}"));
|
||||
static_assert(std::is_same_v<decltype(statically_named_field_compiled),
|
||||
fmt::detail::field<char, int, 0>>);
|
||||
|
||||
EXPECT_EQ("41 43",
|
||||
fmt::format(FMT_COMPILE("{a0} {a1}"), "a0"_a = 41, "a1"_a = 43));
|
||||
EXPECT_EQ("41 43",
|
||||
fmt::format(FMT_COMPILE("{a1} {a0}"), "a0"_a = 43, "a1"_a = 41));
|
||||
# endif
|
||||
}
|
||||
|
||||
TEST(compile_test, join) {
|
||||
unsigned char data[] = {0x1, 0x2, 0xaf};
|
||||
EXPECT_EQ("0102af", fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, "")));
|
||||
}
|
||||
|
||||
TEST(compile_test, format_to) {
|
||||
char buf[8];
|
||||
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
|
||||
*end = '\0';
|
||||
EXPECT_STREQ("42", buf);
|
||||
end = fmt::format_to(buf, FMT_COMPILE("{:x}"), 42);
|
||||
*end = '\0';
|
||||
EXPECT_STREQ("2a", buf);
|
||||
}
|
||||
|
||||
TEST(compile_test, format_to_n) {
|
||||
constexpr auto buffer_size = 8;
|
||||
char buffer[buffer_size];
|
||||
auto res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{}"), 42);
|
||||
*res.out = '\0';
|
||||
EXPECT_STREQ("42", buffer);
|
||||
res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{:x}"), 42);
|
||||
*res.out = '\0';
|
||||
EXPECT_STREQ("2a", buffer);
|
||||
}
|
||||
|
||||
TEST(compile_test, output_iterators) {
|
||||
std::list<char> out;
|
||||
fmt::format_to(std::back_inserter(out), FMT_COMPILE("{}"), 42);
|
||||
EXPECT_EQ("42", std::string(out.begin(), out.end()));
|
||||
|
||||
std::stringstream s;
|
||||
fmt::format_to(std::ostream_iterator<char>(s), FMT_COMPILE("{}"), 42);
|
||||
EXPECT_EQ("42", s.str());
|
||||
|
||||
std::stringstream s2;
|
||||
fmt::format_to(std::ostreambuf_iterator<char>(s2), FMT_COMPILE("{}.{:06d}"),
|
||||
42, 43);
|
||||
EXPECT_EQ("42.000043", s2.str());
|
||||
}
|
||||
|
||||
# if FMT_USE_CONSTEVAL && (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940)
|
||||
TEST(compile_test, constexpr_formatted_size) {
|
||||
FMT_CONSTEXPR20 size_t size = fmt::formatted_size(FMT_COMPILE("{}"), 42);
|
||||
EXPECT_EQ(size, 2);
|
||||
FMT_CONSTEXPR20 size_t hex_size =
|
||||
fmt::formatted_size(FMT_COMPILE("{:x}"), 15);
|
||||
EXPECT_EQ(hex_size, 1);
|
||||
FMT_CONSTEXPR20 size_t binary_size =
|
||||
fmt::formatted_size(FMT_COMPILE("{:b}"), 15);
|
||||
EXPECT_EQ(binary_size, 4);
|
||||
FMT_CONSTEXPR20 size_t padded_size =
|
||||
fmt::formatted_size(FMT_COMPILE("{:*^6}"), 42);
|
||||
EXPECT_EQ(padded_size, 6);
|
||||
FMT_CONSTEXPR20 size_t float_size =
|
||||
fmt::formatted_size(FMT_COMPILE("{:.3}"), 12.345);
|
||||
EXPECT_EQ(float_size, 4);
|
||||
FMT_CONSTEXPR20 size_t str_size =
|
||||
fmt::formatted_size(FMT_COMPILE("{:s}"), "abc");
|
||||
EXPECT_EQ(str_size, 3);
|
||||
}
|
||||
# endif
|
||||
|
||||
TEST(compile_test, text_and_arg) {
|
||||
EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42));
|
||||
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
|
||||
}
|
||||
|
||||
TEST(compile_test, unknown_format_fallback) {
|
||||
EXPECT_EQ(" 42 ",
|
||||
fmt::format(FMT_COMPILE("{name:^4}"), fmt::arg("name", 42)));
|
||||
|
||||
std::vector<char> v1;
|
||||
fmt::format_to(std::back_inserter(v1), FMT_COMPILE("{}"), 42);
|
||||
EXPECT_EQ("42", fmt::string_view(v1.data(), v1.size()));
|
||||
|
||||
std::vector<char> v2;
|
||||
fmt::format_to(std::back_inserter(v2), FMT_COMPILE("{name:^4}"),
|
||||
fmt::arg("name", 42));
|
||||
EXPECT_EQ(" 42 ", fmt::string_view(v2.data(), v2.size()));
|
||||
|
||||
char buffer[4];
|
||||
auto result = fmt::format_to_n(buffer, 4, FMT_COMPILE("{name:^5}"),
|
||||
fmt::arg("name", 42));
|
||||
EXPECT_EQ(5u, result.size);
|
||||
EXPECT_EQ(buffer + 4, result.out);
|
||||
EXPECT_EQ(" 42 ", fmt::string_view(buffer, 4));
|
||||
}
|
||||
|
||||
TEST(compile_test, empty) { EXPECT_EQ("", fmt::format(FMT_COMPILE(""))); }
|
||||
|
||||
struct to_stringable {
|
||||
friend fmt::string_view to_string_view(to_stringable) { return {}; }
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<to_stringable> {
|
||||
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const to_stringable&, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(compile_test, to_string_and_formatter) {
|
||||
fmt::format(FMT_COMPILE("{}"), to_stringable());
|
||||
}
|
||||
|
||||
struct std_context_test {};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<std_context_test> : formatter<int> {
|
||||
auto format(std_context_test, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(compile_test, print) {
|
||||
EXPECT_WRITE(stdout, fmt::print(FMT_COMPILE("Don't {}!"), "panic"),
|
||||
"Don't panic!");
|
||||
EXPECT_WRITE(stderr, fmt::print(stderr, FMT_COMPILE("Don't {}!"), "panic"),
|
||||
"Don't panic!");
|
||||
fmt::print(FMT_COMPILE("{}"), std_context_test());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
TEST(compile_test, compile_format_string_literal) {
|
||||
using namespace fmt::literals;
|
||||
EXPECT_EQ("", fmt::format(""_cf));
|
||||
EXPECT_EQ("42", fmt::format("{}"_cf, 42));
|
||||
EXPECT_EQ(L"42", fmt::format(L"{}"_cf, 42));
|
||||
}
|
||||
#endif
|
||||
|
||||
// MSVS 2019 19.29.30145.0 - OK
|
||||
// MSVS 2022 19.32.31332.0, 19.37.32826.1 - compile-test.cc(362,3): fatal error
|
||||
// C1001: Internal compiler error.
|
||||
// (compiler file
|
||||
// 'D:\a\_work\1\s\src\vctools\Compiler\CxxFE\sl\p1\c\constexpr\constexpr.cpp',
|
||||
// line 8635)
|
||||
#if FMT_USE_CONSTEVAL && \
|
||||
(!FMT_MSC_VERSION || \
|
||||
(FMT_MSC_VERSION >= 1928 && FMT_MSC_VERSION < 1930)) && \
|
||||
defined(__cpp_lib_is_constant_evaluated)
|
||||
template <size_t max_string_length, typename Char = char> struct test_string {
|
||||
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
|
||||
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
|
||||
}
|
||||
Char buffer[max_string_length]{};
|
||||
};
|
||||
|
||||
template <size_t max_string_length, typename Char = char, typename... Args>
|
||||
consteval auto test_format(auto format, const Args&... args) {
|
||||
test_string<max_string_length, Char> string{};
|
||||
fmt::format_to(string.buffer, format, args...);
|
||||
return string;
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, bool) {
|
||||
EXPECT_EQ("true", test_format<5>(FMT_COMPILE("{}"), true));
|
||||
EXPECT_EQ("false", test_format<6>(FMT_COMPILE("{}"), false));
|
||||
EXPECT_EQ("true ", test_format<6>(FMT_COMPILE("{:5}"), true));
|
||||
EXPECT_EQ("1", test_format<2>(FMT_COMPILE("{:d}"), true));
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, integer) {
|
||||
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), 42));
|
||||
EXPECT_EQ("420", test_format<4>(FMT_COMPILE("{}"), 420));
|
||||
EXPECT_EQ("42 42", test_format<6>(FMT_COMPILE("{} {}"), 42, 42));
|
||||
EXPECT_EQ("42 42",
|
||||
test_format<6>(FMT_COMPILE("{} {}"), uint32_t{42}, uint64_t{42}));
|
||||
|
||||
EXPECT_EQ("+42", test_format<4>(FMT_COMPILE("{:+}"), 42));
|
||||
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{:-}"), 42));
|
||||
EXPECT_EQ(" 42", test_format<4>(FMT_COMPILE("{: }"), 42));
|
||||
|
||||
EXPECT_EQ("-0042", test_format<6>(FMT_COMPILE("{:05}"), -42));
|
||||
|
||||
EXPECT_EQ("101010", test_format<7>(FMT_COMPILE("{:b}"), 42));
|
||||
EXPECT_EQ("0b101010", test_format<9>(FMT_COMPILE("{:#b}"), 42));
|
||||
EXPECT_EQ("0B101010", test_format<9>(FMT_COMPILE("{:#B}"), 42));
|
||||
EXPECT_EQ("042", test_format<4>(FMT_COMPILE("{:#o}"), 042));
|
||||
EXPECT_EQ("0x4a", test_format<5>(FMT_COMPILE("{:#x}"), 0x4a));
|
||||
EXPECT_EQ("0X4A", test_format<5>(FMT_COMPILE("{:#X}"), 0x4a));
|
||||
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42));
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42l));
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ll));
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ull));
|
||||
|
||||
EXPECT_EQ("42 ", test_format<5>(FMT_COMPILE("{:<4}"), 42));
|
||||
EXPECT_EQ(" 42", test_format<5>(FMT_COMPILE("{:>4}"), 42));
|
||||
EXPECT_EQ(" 42 ", test_format<5>(FMT_COMPILE("{:^4}"), 42));
|
||||
EXPECT_EQ("**-42", test_format<6>(FMT_COMPILE("{:*>5}"), -42));
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, char) {
|
||||
EXPECT_EQ("c", test_format<2>(FMT_COMPILE("{}"), 'c'));
|
||||
|
||||
EXPECT_EQ("c ", test_format<4>(FMT_COMPILE("{:3}"), 'c'));
|
||||
EXPECT_EQ("99", test_format<3>(FMT_COMPILE("{:d}"), 'c'));
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, string) {
|
||||
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), "42"));
|
||||
EXPECT_EQ("The answer is 42",
|
||||
test_format<17>(FMT_COMPILE("{} is {}"), "The answer", "42"));
|
||||
|
||||
EXPECT_EQ("abc**", test_format<6>(FMT_COMPILE("{:*<5}"), "abc"));
|
||||
EXPECT_EQ("**🤡**", test_format<9>(FMT_COMPILE("{:*^6}"), "🤡"));
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, combination) {
|
||||
EXPECT_EQ("420, true, answer",
|
||||
test_format<18>(FMT_COMPILE("{}, {}, {}"), 420, true, "answer"));
|
||||
|
||||
EXPECT_EQ(" -42", test_format<5>(FMT_COMPILE("{:{}}"), -42, 4));
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, custom_type) {
|
||||
EXPECT_EQ("foo", test_format<4>(FMT_COMPILE("{}"), test_formattable()));
|
||||
EXPECT_EQ("bar", test_format<4>(FMT_COMPILE("{:b}"), test_formattable()));
|
||||
}
|
||||
|
||||
TEST(compile_time_formatting_test, multibyte_fill) {
|
||||
EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42));
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user