mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
572 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bcc2c94b9 | ||
|
|
377930d004 | ||
|
|
a9526b7cc1 | ||
|
|
ff01a6359b | ||
|
|
6c3ea29157 | ||
|
|
36be1a8f7d | ||
|
|
691c3764ac | ||
|
|
aa0292ada1 | ||
|
|
e4429527e3 | ||
|
|
f06285e3a4 | ||
|
|
6d47cefefd | ||
|
|
fe71fc6a30 | ||
|
|
0e649bc70b | ||
|
|
e0915d8372 | ||
|
|
3f4d9cda85 | ||
|
|
4e25988961 | ||
|
|
b1502c754a | ||
|
|
303cef78ed | ||
|
|
a72f282156 | ||
|
|
32e77a2bd3 | ||
|
|
a53fdfae82 | ||
|
|
806ab5ad01 | ||
|
|
f5ddc0d7c6 | ||
|
|
a6eb5d32d8 | ||
|
|
b03c982706 | ||
|
|
7835ebd14f | ||
|
|
fd67049cf9 | ||
|
|
c2f05371e4 | ||
|
|
5c9c071086 | ||
|
|
f7677105ed | ||
|
|
9e2a73c7a7 | ||
|
|
c9f5f03d02 | ||
|
|
c313736334 | ||
|
|
1eb9a60b4a | ||
|
|
e50fe50daf | ||
|
|
643c83c2a0 | ||
|
|
44733d7655 | ||
|
|
fcdd43fc78 | ||
|
|
78643623c3 | ||
|
|
b27846ce39 | ||
|
|
b87b8eb7bb | ||
|
|
709dfdd3f2 | ||
|
|
faef28d5c4 | ||
|
|
309dd4f847 | ||
|
|
506897fab2 | ||
|
|
4e0aff053c | ||
|
|
2ba6fbbcc2 | ||
|
|
e987eac545 | ||
|
|
6b9781fee6 | ||
|
|
181ceb38cc | ||
|
|
595ce0ea19 | ||
|
|
b624330155 | ||
|
|
380c316869 | ||
|
|
31dacc2d21 | ||
|
|
b557a82009 | ||
|
|
e4af1c4244 | ||
|
|
7c26ac5578 | ||
|
|
2948d50b0d | ||
|
|
48fefddcb2 | ||
|
|
f4d8af2f0d | ||
|
|
afa3108623 | ||
|
|
6fcfddf19a | ||
|
|
6d2f442cbd | ||
|
|
e8260e7191 | ||
|
|
48a4367a2c | ||
|
|
edd3540f34 | ||
|
|
111c32c5ed | ||
|
|
af22ca3ae0 | ||
|
|
5e2caa326c | ||
|
|
50f9f60341 | ||
|
|
65f61b143a | ||
|
|
10f4892b7e | ||
|
|
f71d518f75 | ||
|
|
c5b11fe484 | ||
|
|
068fd04f15 | ||
|
|
a461750b55 | ||
|
|
291df6a0e4 | ||
|
|
8afeb4ea61 | ||
|
|
b30f246900 | ||
|
|
7fd042b197 | ||
|
|
b6b3e364f2 | ||
|
|
70e5f18971 | ||
|
|
1fb35593d5 | ||
|
|
b1b9c32644 | ||
|
|
8eeed7d42c | ||
|
|
584493d945 | ||
|
|
da8e551e77 | ||
|
|
a717930d5a | ||
|
|
abc000f614 | ||
|
|
cd51f1def3 | ||
|
|
f5573cf0ab | ||
|
|
1d036a4897 | ||
|
|
f9eced6244 | ||
|
|
90a7253c66 | ||
|
|
31e065f83a | ||
|
|
571f443339 | ||
|
|
4a4157919c | ||
|
|
e73aa0e81b | ||
|
|
2343246315 | ||
|
|
e5f41ce175 | ||
|
|
8184f2eaa9 | ||
|
|
e0bb465945 | ||
|
|
55749a63eb | ||
|
|
aa1b8db3ea | ||
|
|
023713fd67 | ||
|
|
35093c3e37 | ||
|
|
4e5dac3e25 | ||
|
|
c52e84ac41 | ||
|
|
7f8488771d | ||
|
|
57ff271f4b | ||
|
|
43703755f8 | ||
|
|
17b6cc00ab | ||
|
|
a03563b366 | ||
|
|
ff9da17498 | ||
|
|
722bc94270 | ||
|
|
d51a5db5b1 | ||
|
|
04541ae2ab | ||
|
|
c58a67815b | ||
|
|
085f964cd9 | ||
|
|
a8b6e448eb | ||
|
|
78ab8381d9 | ||
|
|
49a5d82086 | ||
|
|
4ed129ccac | ||
|
|
ed09dca17e | ||
|
|
e64fbb2f0e | ||
|
|
e37f8a6521 | ||
|
|
b54bcc0e20 | ||
|
|
db37d51bb1 | ||
|
|
197b9fc560 | ||
|
|
fd30b00205 | ||
|
|
f182379d24 | ||
|
|
32ba08980d | ||
|
|
1e1f08abb9 | ||
|
|
cbe20c0eed | ||
|
|
ec288ffa62 | ||
|
|
7e18c02c7e | ||
|
|
4a505cc239 | ||
|
|
35c81106c6 | ||
|
|
1094222d3f | ||
|
|
065d0db4c9 | ||
|
|
bc51537080 | ||
|
|
b7dfcb282b | ||
|
|
78a9411766 | ||
|
|
4724f67596 | ||
|
|
e0851bb86f | ||
|
|
08e68d9563 | ||
|
|
0b6dccae51 | ||
|
|
60adfd5046 | ||
|
|
3e782d355d | ||
|
|
22a7324b69 | ||
|
|
f3b4c50909 | ||
|
|
a45f27e6e9 | ||
|
|
2f84bf0cca | ||
|
|
3e2c3e5075 | ||
|
|
154259d0a6 | ||
|
|
7d2d05ff59 | ||
|
|
f7c587c9a8 | ||
|
|
9162b30b18 | ||
|
|
14cfe37c8b | ||
|
|
a27a0ab49d | ||
|
|
0742fe07ec | ||
|
|
65a92470d3 | ||
|
|
10dc1a2da2 | ||
|
|
aad2128c32 | ||
|
|
2640678cac | ||
|
|
8b90e2d53d | ||
|
|
f87175dc7f | ||
|
|
b30444c0d0 | ||
|
|
c1da0caf15 | ||
|
|
c4a8fc5b71 | ||
|
|
8eb46b5a4c | ||
|
|
8be16d1039 | ||
|
|
76e6208d1b | ||
|
|
bc09080ba5 | ||
|
|
a6eb257a3a | ||
|
|
e62450d255 | ||
|
|
1aa922f700 | ||
|
|
4c9d2f99b1 | ||
|
|
f6e899b570 | ||
|
|
695c39fba2 | ||
|
|
e5616cff98 | ||
|
|
76d5994c1e | ||
|
|
cbb40832a1 | ||
|
|
e4bdcde1ca | ||
|
|
863e119ff4 | ||
|
|
2ccf6dc872 | ||
|
|
24ebf1b4f1 | ||
|
|
ed2832434c | ||
|
|
5e160fca8f | ||
|
|
a0ef82e221 | ||
|
|
3e7ac3d66c | ||
|
|
730e6fa737 | ||
|
|
cdfcd9fddd | ||
|
|
b6930c10b9 | ||
|
|
852734580d | ||
|
|
d1dc6a9c1d | ||
|
|
4fa6d3ed3f | ||
|
|
92e190ad6c | ||
|
|
da4fcffef4 | ||
|
|
1a5731dd8e | ||
|
|
e764c5cd4e | ||
|
|
e23b247947 | ||
|
|
3d7792436f | ||
|
|
d8187fbea4 | ||
|
|
02259ad0a5 | ||
|
|
220a68df9a | ||
|
|
2ced24f69e | ||
|
|
ec91d0dc74 | ||
|
|
46874f4673 | ||
|
|
9eac47dc6c | ||
|
|
9e3fd5c2e0 | ||
|
|
ae4be6e2b1 | ||
|
|
434df49a7d | ||
|
|
c939c0fcd5 | ||
|
|
952c39f324 | ||
|
|
0fea7e2a70 | ||
|
|
c1baab68d0 | ||
|
|
ccef18f7a9 | ||
|
|
8cb056bde3 | ||
|
|
6ecaaee9e0 | ||
|
|
c5f916bda0 | ||
|
|
52a9a4649c | ||
|
|
d2219b4dbd | ||
|
|
155f603245 | ||
|
|
cb7630a6ab | ||
|
|
284fba1ce3 | ||
|
|
aa4bd6c88c | ||
|
|
623993930b | ||
|
|
dbf2c854c6 | ||
|
|
25351bc05c | ||
|
|
27cc5f499c | ||
|
|
b7c2f39a17 | ||
|
|
3541c1ccf8 | ||
|
|
7a05738d11 | ||
|
|
686220ae0c | ||
|
|
cf380d36b9 | ||
|
|
50bc0193ac | ||
|
|
2162a72831 | ||
|
|
313666f85b | ||
|
|
e9d79263b4 | ||
|
|
4ede6d65fd | ||
|
|
14d2eee371 | ||
|
|
717f370be0 | ||
|
|
d05e4b9727 | ||
|
|
697c53b4d8 | ||
|
|
d9b58ec3ce | ||
|
|
6c8b37d7ca | ||
|
|
39f43e766d | ||
|
|
5379a13944 | ||
|
|
cd0c1607ef | ||
|
|
26a4f71385 | ||
|
|
06b3e6ad71 | ||
|
|
79d22a8d77 | ||
|
|
9914212600 | ||
|
|
765f55e67b | ||
|
|
2d922cc035 | ||
|
|
42e0625ab3 | ||
|
|
c72e894fc7 | ||
|
|
5bc2342d47 | ||
|
|
ea2b0b5e59 | ||
|
|
d70cc0221a | ||
|
|
b12587b44e | ||
|
|
c4708bdc35 | ||
|
|
1fa2c0bf50 | ||
|
|
b4c70d357a | ||
|
|
f18262ee96 | ||
|
|
c1f1761482 | ||
|
|
067c3eea16 | ||
|
|
6957cc7001 | ||
|
|
7dea23eea8 | ||
|
|
319ec1f774 | ||
|
|
2079532e83 | ||
|
|
de1d646fe9 | ||
|
|
4bc3ab6285 | ||
|
|
1adc9cbb49 | ||
|
|
7cdf5eefc9 | ||
|
|
c7ee72647d | ||
|
|
5434af348e | ||
|
|
169cea0f01 | ||
|
|
a8f3ec8184 | ||
|
|
7796b2a12b | ||
|
|
d9cffd58ba | ||
|
|
e566386240 | ||
|
|
45af1e172f | ||
|
|
768b2e52a6 | ||
|
|
7abd2009b0 | ||
|
|
46f075e891 | ||
|
|
832c381ac4 | ||
|
|
e021282264 | ||
|
|
2a60d385c6 | ||
|
|
4d37e35675 | ||
|
|
df3868a280 | ||
|
|
0799bb8cf1 | ||
|
|
69048dede4 | ||
|
|
76df6d1f43 | ||
|
|
2d03b21f2b | ||
|
|
62cbd44933 | ||
|
|
44c8f6d8b0 | ||
|
|
f3fc1dd59c | ||
|
|
708931e48b | ||
|
|
81800d2883 | ||
|
|
d0411d7ddf | ||
|
|
70e232cab3 | ||
|
|
f90396bda4 | ||
|
|
ae8808b86e | ||
|
|
8d5b827432 | ||
|
|
cb672697e7 | ||
|
|
0bae9fc29b | ||
|
|
49c8b68700 | ||
|
|
1e2fcd17e0 | ||
|
|
468b9d2655 | ||
|
|
a3305ff791 | ||
|
|
814b0d5873 | ||
|
|
863f3e82ac | ||
|
|
529c756458 | ||
|
|
67b98dbdaa | ||
|
|
a16981cbe5 | ||
|
|
777bf338fa | ||
|
|
3ba8d9ebff | ||
|
|
db5384e19c | ||
|
|
fd3984287b | ||
|
|
31dbea4e0b | ||
|
|
0992e784f1 | ||
|
|
c59cc1fbb7 | ||
|
|
903edc79f7 | ||
|
|
4c94c69f02 | ||
|
|
4c57c214bd | ||
|
|
1cbeea3016 | ||
|
|
0d18738192 | ||
|
|
1e7c7db29b | ||
|
|
7c098a2665 | ||
|
|
3ab539be1e | ||
|
|
b46d5e4efc | ||
|
|
db06e11a7c | ||
|
|
757ed33e4f | ||
|
|
8eb5dfce85 | ||
|
|
f34db72a97 | ||
|
|
3dfdc8ee6f | ||
|
|
5a846296ca | ||
|
|
0bea015dcd | ||
|
|
fe0b401edd | ||
|
|
69f8e82c3f | ||
|
|
79d3d43a85 | ||
|
|
e8a7f596bc | ||
|
|
a096c00b68 | ||
|
|
e284ef8906 | ||
|
|
154a8750dc | ||
|
|
0de4ca4a19 | ||
|
|
23c9c9f72e | ||
|
|
96ff10c692 | ||
|
|
30bc7ea132 | ||
|
|
d9ea1591b0 | ||
|
|
0cc1bb5ad8 | ||
|
|
509bbd7605 | ||
|
|
4632afe1ab | ||
|
|
6680698ba6 | ||
|
|
2b06b12ca2 | ||
|
|
9b53916e06 | ||
|
|
f3ce1dd7a3 | ||
|
|
91b0426d68 | ||
|
|
63a5b95939 | ||
|
|
480a3fe171 | ||
|
|
b160eac49f | ||
|
|
37ba82b8b7 | ||
|
|
2d604145f1 | ||
|
|
d60a6df313 | ||
|
|
236d9e3028 | ||
|
|
175327e711 | ||
|
|
6342f99504 | ||
|
|
6164ae9f60 | ||
|
|
d2a5b70b2e | ||
|
|
b2be5dcb59 | ||
|
|
b67c03cc75 | ||
|
|
d613701780 | ||
|
|
4b62562fce | ||
|
|
6ffaca45da | ||
|
|
56fe0b32e6 | ||
|
|
f7c0d6af73 | ||
|
|
b625e2c47a | ||
|
|
97300d59a9 | ||
|
|
f45840a29f | ||
|
|
bfff6ed406 | ||
|
|
ad6f5fd6af | ||
|
|
7bdf349b9d | ||
|
|
9412fbcefb | ||
|
|
c2af0097c5 | ||
|
|
9e5b69ee54 | ||
|
|
f6e0d1d368 | ||
|
|
5bb18bee17 | ||
|
|
d0fb219939 | ||
|
|
e2b04726cf | ||
|
|
b293cdc9ba | ||
|
|
3f93b3a39d | ||
|
|
a4de6e45db | ||
|
|
213a89ab72 | ||
|
|
8dcca62d0c | ||
|
|
4ed0bcbda8 | ||
|
|
b2587e676d | ||
|
|
90af9b2f01 | ||
|
|
d915a0b945 | ||
|
|
ac9c5eaae9 | ||
|
|
0891da303c | ||
|
|
55e9b51faa | ||
|
|
55dc0ade47 | ||
|
|
2cf7083718 | ||
|
|
15df532d68 | ||
|
|
884d2302a9 | ||
|
|
bacdfd6018 | ||
|
|
dc7a3bbbd3 | ||
|
|
ff0d791783 | ||
|
|
a3d8a0dde0 | ||
|
|
a8c908d113 | ||
|
|
01849d5305 | ||
|
|
23968d3e2b | ||
|
|
7246a64ae5 | ||
|
|
729e050adb | ||
|
|
003452fbbb | ||
|
|
419b6bd0a3 | ||
|
|
668c3d9a08 | ||
|
|
9a6f878051 | ||
|
|
50fc750154 | ||
|
|
9fe8235eda | ||
|
|
f7b9c48998 | ||
|
|
17bf27c018 | ||
|
|
80ca5ea5fd | ||
|
|
3afa9ca403 | ||
|
|
842190e15e | ||
|
|
717775d9ab | ||
|
|
a19bb91041 | ||
|
|
a545982a28 | ||
|
|
2109df04ca | ||
|
|
f485cf8ebc | ||
|
|
bb48110f95 | ||
|
|
718adda749 | ||
|
|
a170c7ccb1 | ||
|
|
fec3fe3b6b | ||
|
|
00f19c9777 | ||
|
|
93aae28593 | ||
|
|
8be2b907b3 | ||
|
|
fcca07765b | ||
|
|
559e4e75eb | ||
|
|
8ae84614d5 | ||
|
|
18a7e8b22c | ||
|
|
01120f6120 | ||
|
|
07be6bb5ae | ||
|
|
39b4905ef1 | ||
|
|
6c49a5aa9d | ||
|
|
aaeff2ea0f | ||
|
|
cd48e78667 | ||
|
|
f2ab4e840e | ||
|
|
9a476f8283 | ||
|
|
8e24ad724c | ||
|
|
c70aba2ca5 | ||
|
|
c6a20961b8 | ||
|
|
4741354883 | ||
|
|
a3051f5d58 | ||
|
|
730207e75b | ||
|
|
27e067889d | ||
|
|
22c9433c1c | ||
|
|
c6b558cb3d | ||
|
|
a6d5598c08 | ||
|
|
13ee2abeef | ||
|
|
ca9c841477 | ||
|
|
0dbae3c46c | ||
|
|
045bcbc7da | ||
|
|
9f98e28b08 | ||
|
|
59dfbae9b4 | ||
|
|
3f0250957b | ||
|
|
73595d93f3 | ||
|
|
19b8755c89 | ||
|
|
14aad730de | ||
|
|
6c7eec5778 | ||
|
|
2c5ce5763a | ||
|
|
b568e1387a | ||
|
|
85bd46e457 | ||
|
|
bd4a77992e | ||
|
|
a8750ce8ad | ||
|
|
4e8887c80b | ||
|
|
c38a0cdec9 | ||
|
|
6f961edcb1 | ||
|
|
bdd9f30404 | ||
|
|
f94d5faaf2 | ||
|
|
c1ffd93f28 | ||
|
|
05bf7af859 | ||
|
|
eae359a3b8 | ||
|
|
2156906341 | ||
|
|
e7bd669362 | ||
|
|
17ac5b5e06 | ||
|
|
671cc753b5 | ||
|
|
fd81b47413 | ||
|
|
710b07a857 | ||
|
|
5b93d2642b | ||
|
|
38d792fd97 | ||
|
|
fed266f5ac | ||
|
|
a547d10ab9 | ||
|
|
4cc6043737 | ||
|
|
0a42313b6f | ||
|
|
0b53f541d1 | ||
|
|
ddd17b18d7 | ||
|
|
915f4cc618 | ||
|
|
d4d9b3e461 | ||
|
|
49f5221170 | ||
|
|
96459090a6 | ||
|
|
ccc8b38b77 | ||
|
|
c6d1c8063b | ||
|
|
0ffb6d6362 | ||
|
|
252aaa500e | ||
|
|
d456908e37 | ||
|
|
cd13bfb429 | ||
|
|
ff87bc5889 | ||
|
|
42cd80c172 | ||
|
|
123cd3a092 | ||
|
|
cbc3c4e6eb | ||
|
|
b50e39e5cb | ||
|
|
bbe5ef451a | ||
|
|
c359c0e747 | ||
|
|
99ecb0b60f | ||
|
|
cfc7e45020 | ||
|
|
0307d064ad | ||
|
|
89cd824c70 | ||
|
|
1066e8a5e9 | ||
|
|
d2c31df106 | ||
|
|
a56ffee8f7 | ||
|
|
7c798126e3 | ||
|
|
a755131488 | ||
|
|
648ff65a76 | ||
|
|
854d1c0a1a | ||
|
|
4f561aa9e9 | ||
|
|
8c1c4df10d | ||
|
|
a9e963e84b | ||
|
|
4a509610fe | ||
|
|
7de5066c87 | ||
|
|
24b1be1dd2 | ||
|
|
ee00213961 | ||
|
|
b51b32c758 | ||
|
|
d16e669538 | ||
|
|
50d258fae9 | ||
|
|
494cceff73 | ||
|
|
9885e61962 | ||
|
|
4b88a290c4 | ||
|
|
ee8335e5f1 | ||
|
|
fcde7fdb80 | ||
|
|
3d42da3e97 | ||
|
|
c81a37b740 | ||
|
|
4fa005ade0 | ||
|
|
bf656e892f | ||
|
|
abf074eaf4 | ||
|
|
47657b51ab | ||
|
|
76f8ffeb90 | ||
|
|
e68ae91b59 | ||
|
|
9222c21b4a | ||
|
|
c837d9c91c | ||
|
|
cdf7bef150 | ||
|
|
eb52da9702 | ||
|
|
8a1f2a151d | ||
|
|
1b4ced3e55 | ||
|
|
29cd068dbd | ||
|
|
6681614f1a | ||
|
|
1030db87d4 | ||
|
|
356ab30e89 | ||
|
|
0f09b8df77 | ||
|
|
23c495b939 | ||
|
|
2ac0420903 | ||
|
|
aae070f826 | ||
|
|
6ad825d1e0 | ||
|
|
7910506b3c | ||
|
|
5393d724c5 | ||
|
|
c8b1e4c4e6 | ||
|
|
d373cb602d | ||
|
|
58f195fc04 | ||
|
|
f6675808fc | ||
|
|
aa64712354 |
54
.github/CONTRIBUTING.md
vendored
54
.github/CONTRIBUTING.md
vendored
@@ -1,54 +0,0 @@
|
||||
# So you want to contribute to PCSX2? Great
|
||||
|
||||
As a first step, please review these links as they'll help you understand how the development of PCSX2 works.
|
||||
|
||||
* [Just Starting Out](#just-starting-out)
|
||||
* [Issue Reporting](#issue-reporting)
|
||||
* [Pull Request Guidelines](#pull-request-guidelines)
|
||||
* [General Documentation And Coding Strategies](#general-documentation-and-coding-strategies)
|
||||
* [Tasks](#tasks)
|
||||
|
||||
## Just Starting Out
|
||||
|
||||
* If you're unfamilar with git, check out this [brief introduction to Git](https://github.com/PCSX2/pcsx2/wiki/07-Git-survival-guide)
|
||||
* [How to build PCSX2 for Windows](https://github.com/PCSX2/pcsx2/wiki/12-Building-on-Windows)
|
||||
* [How to build PCSX2 for Linux](https://github.com/PCSX2/pcsx2/wiki/10-Building-on-Linux)
|
||||
|
||||
## Issue Reporting
|
||||
|
||||
* [How to write a useful issue](https://github.com/PCSX2/pcsx2/wiki/How-to-create-useful-and-valid-issues)
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
The following is a list of *general* style recommendations that will make reviewing and merging easier:
|
||||
|
||||
* Commit Messages
|
||||
* Please try to prefix your commit message, indicating what area of the project was modified.
|
||||
* For example `gs: message...`.
|
||||
* Looking at the project's commit history will help with keeping prefixes consistent overtime, *there is no strictly enforced list*.
|
||||
|
||||
* Try to keep messages brief and informative
|
||||
|
||||
* Remove unnecessary commits and squash commits together when appropriate.
|
||||
* If you are not familiar with rebasing with git, check out the following resources:
|
||||
* CLI - https://thoughtbot.com/blog/git-interactive-rebase-squash-amend-rewriting-history
|
||||
* GUI (SourceTree) - https://www.atlassian.com/blog/sourcetree/interactive-rebase-sourcetree
|
||||
|
||||
* Code Styling and Formatting
|
||||
* [Consult the style guide](https://github.com/tadanokojin/pcsx2/blob/coding-guide/pcsx2/Docs/Coding_Guidelines.md)
|
||||
|
||||
* Run `clang-format` using the configuration file in the root of the repository
|
||||
* Visual Studio Setup - https://devblogs.microsoft.com/cppblog/clangformat-support-in-visual-studio-2017-15-7-preview-1/
|
||||
* IMPORTANT - if you are running `clang-format` on unrelated changes (ie. formatting an entire file), please do so in a separate commit.
|
||||
* If you cannot scope your `clang-format` to just your changes and do not want to format unrelated code. Try your best to stick with the existing formatting already established in the file in question.
|
||||
|
||||
## General Documentation And Coding Strategies
|
||||
|
||||
* [Commenting Etiquette](https://github.com/PCSX2/pcsx2/wiki/06-Commenting-Etiquette)
|
||||
|
||||
* [Coding style](https://github.com/PCSX2/pcsx2/wiki/Code-Formatting-Guidelines)
|
||||
* [More comprehensive style-guide (Currently in Draft)](https://github.com/tadanokojin/pcsx2/blob/coding-guide/pcsx2/Docs/Coding_Guidelines.md)
|
||||
|
||||
## Tasks
|
||||
|
||||
* [Issues](https://github.com/PCSX2/pcsx2/issues)
|
||||
2
.github/ISSUE_TEMPLATE/app_bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/app_bug_report.yaml
vendored
@@ -70,6 +70,8 @@ body:
|
||||
- Windows 11
|
||||
- Windows 10 (64bit)
|
||||
- Linux (64bit) - Specify distro below
|
||||
- macOS 26 (Tahoe)
|
||||
- macOS 15 (Sequoia)
|
||||
- macOS 14 (Sonoma)
|
||||
- macOS 13 (Ventura)
|
||||
- macOS 12 (Monterey)
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
12
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
@@ -66,9 +66,9 @@ body:
|
||||
|
||||
Performance issues as a result of not meeting our hardware requirements are not valid.
|
||||
|
||||
Please read our known issues pages for AMD and Intel drivers.
|
||||
- [Intel Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-Intel-GPUs-All-you-need-to-know).
|
||||
- [AMD Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-AMD-GPUs---All-you-need-to-know).
|
||||
Please read our troubleshooting pages and our issue reporting guide.
|
||||
- [Troubleshooting page](https://pcsx2.net/docs/category/troubleshooting).
|
||||
- [Issue reporting guide](https://pcsx2.net/docs/troubleshooting/identify).
|
||||
|
||||
We are **not** accepting issues related to the **libretro** core. The libretro core is being maintained separately at this time
|
||||
- type: input
|
||||
@@ -87,6 +87,8 @@ body:
|
||||
- Windows 11
|
||||
- Windows 10 (64bit)
|
||||
- Linux (64bit) - Specify distro below
|
||||
- macOS 26 (Tahoe)
|
||||
- macOS 15 (Sequoia)
|
||||
- macOS 14 (Sonoma)
|
||||
- macOS 13 (Ventura)
|
||||
- macOS 12 (Monterey)
|
||||
@@ -104,14 +106,14 @@ body:
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "Example: i5-7600"
|
||||
placeholder: "Example: Intel i5 12400F"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "Example: GTX 1070"
|
||||
placeholder: "Example: Nvidia RTX 4060"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -6,3 +6,6 @@
|
||||
|
||||
### Suggested Testing Steps
|
||||
<!-- If applicable, including examples you've already tested with / recommendations for how to test further is very helpful! -->
|
||||
|
||||
### Did you use AI to help find, test, or implement this issue or feature?
|
||||
<!-- Answer yes or no. If you answer yes, please provide a brief explanation how. -->
|
||||
|
||||
57
.github/workflows/cron_publish_flatpak.yml
vendored
57
.github/workflows/cron_publish_flatpak.yml
vendored
@@ -6,36 +6,45 @@ on:
|
||||
workflow_dispatch: # As well as manually.
|
||||
|
||||
jobs:
|
||||
check:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Check if release is needed"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 180
|
||||
outputs:
|
||||
PCSX2_RELEASE: ${{ steps.getinfo.outputs.PCSX2_RELEASE }}
|
||||
FLATHUB_RELEASE: ${{ steps.getinfo.outputs.FLATHUB_RELEASE }}
|
||||
steps:
|
||||
- name: Get latest tag and Flathub release
|
||||
id: getinfo
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
PCSX2_RELEASE=$(gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/PCSX2/pcsx2/releases | jq -r '.[0].tag_name')
|
||||
FLATHUB_RELEASE=$(curl -L -s https://flathub.org/api/v2/appstream/net.pcsx2.PCSX2 | jq -r '.releases | max_by(.version) | .version')
|
||||
echo "Latest PCSX2 release is: '${PCSX2_RELEASE}'"
|
||||
echo "Latest Flathub release is: '${FLATHUB_RELEASE}'"
|
||||
PCSX2_RELEASE=$(echo $PCSX2_RELEASE | sed 's/[^0-9]*//g')
|
||||
FLATHUB_RELEASE=$(echo $FLATHUB_RELEASE | sed 's/[^0-9]*//g')
|
||||
echo "PCSX2_RELEASE=${PCSX2_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||
echo "FLATHUB_RELEASE=${FLATHUB_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# check is disabled as the flathub api does not give us beta repository information
|
||||
# Alternatively we can "flatpak remote-info or parse the appstream directly for the beta repo"
|
||||
# Maybe in the future if we don't want to publish the same version twice if we get no commits
|
||||
# for 24 hours.
|
||||
|
||||
# check:
|
||||
# if: github.repository == 'PCSX2/pcsx2'
|
||||
# name: "Check if release is needed"
|
||||
# runs-on: ubuntu-latest
|
||||
# timeout-minutes: 180
|
||||
# outputs:
|
||||
# PCSX2_RELEASE: ${{ steps.getinfo.outputs.PCSX2_RELEASE }}
|
||||
# FLATHUB_RELEASE: ${{ steps.getinfo.outputs.FLATHUB_RELEASE }}
|
||||
# steps:
|
||||
# - name: Get latest tag and Flathub release
|
||||
# id: getinfo
|
||||
# env:
|
||||
# GH_TOKEN: ${{ github.token }}
|
||||
# run: |
|
||||
# PCSX2_RELEASE=$(gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/PCSX2/pcsx2/releases | jq -r '.[0].tag_name')
|
||||
# FLATHUB_RELEASE=$(curl -L -s https://flathub.org/api/v2/appstream/net.pcsx2.PCSX2 | jq -r '.releases | max_by(.version) | .version')
|
||||
# echo "Latest PCSX2 release is: '${PCSX2_RELEASE}'"
|
||||
# echo "Latest Flathub release is: '${FLATHUB_RELEASE}'"
|
||||
# PCSX2_RELEASE=$(echo $PCSX2_RELEASE | sed 's/[^0-9]*//g')
|
||||
# FLATHUB_RELEASE=$(echo $FLATHUB_RELEASE | sed 's/[^0-9]*//g')
|
||||
# echo "PCSX2_RELEASE=${PCSX2_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||
# echo "FLATHUB_RELEASE=${FLATHUB_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build:
|
||||
needs: check
|
||||
# needs: check
|
||||
# outputs are automatically compared as strings. This doesn't work in our favour
|
||||
# Use fromJson() to convert them to proper integers...
|
||||
# see: https://github.com/github/docs/pull/25870
|
||||
# and: https://github.com/orgs/community/discussions/57480
|
||||
#if: fromJson(needs.check.outputs.FLATHUB_RELEASE) < fromJson(needs.check.outputs.PCSX2_RELEASE)
|
||||
|
||||
# if: fromJson(needs.check.outputs.FLATHUB_RELEASE) < fromJson(needs.check.outputs.PCSX2_RELEASE)
|
||||
# As the check step is disabled, perform repository check here
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Build and publish Flatpak"
|
||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||
with:
|
||||
|
||||
21
.github/workflows/linux_build_flatpak.yml
vendored
21
.github/workflows/linux_build_flatpak.yml
vendored
@@ -54,19 +54,16 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
set-safe-directory: ${{ env.GITHUB_WORKSPACE }}
|
||||
# 10 here, since the odds of having 10 untagged commits in a row should be slim to none
|
||||
# This is required for the tagging logic in generate-metainfo.sh
|
||||
fetch-depth: 10
|
||||
fetch-tags: true
|
||||
|
||||
# Work around container ownership issue
|
||||
- name: Set Safe Directory
|
||||
shell: bash
|
||||
run: git config --global --add safe.directory "*"
|
||||
|
||||
# Hackity hack. When running the workflow on a schedule, we don't have the tag,
|
||||
# it doesn't fetch tags, therefore we don't get a version. So grab them manually.
|
||||
# actions/checkout elides tags, fetch them primarily for releases
|
||||
- name: Fetch tags
|
||||
if: ${{ inputs.fetchTags }}
|
||||
run: git fetch --tags --no-recurse-submodules
|
||||
|
||||
- name: Add stable release identifier file
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
shell: bash
|
||||
@@ -96,7 +93,7 @@ jobs:
|
||||
|
||||
- name: Build Flatpak (beta)
|
||||
if: ${{ inputs.stableBuild == false || inputs.stableBuild == 'false' }}
|
||||
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||
upload-artifact: false
|
||||
@@ -112,7 +109,7 @@ jobs:
|
||||
|
||||
- name: Build Flatpak (stable)
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||
upload-artifact: false
|
||||
@@ -125,14 +122,14 @@ jobs:
|
||||
cache: true
|
||||
restore-cache: true
|
||||
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
|
||||
|
||||
|
||||
#- name: Validate build
|
||||
# run: |
|
||||
# flatpak-builder-lint repo repo
|
||||
|
||||
- name: Push to Flathub (beta)
|
||||
if: ${{ inputs.publish == true && (inputs.stableBuild == false || inputs.stableBuild == 'false') }}
|
||||
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flat-manager@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
flat-manager-url: https://hub.flathub.org/
|
||||
repository: beta
|
||||
@@ -141,7 +138,7 @@ jobs:
|
||||
|
||||
- name: Push to Flathub (stable)
|
||||
if: ${{ inputs.publish == true && (inputs.stableBuild == true || inputs.stableBuild == 'true') }}
|
||||
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flat-manager@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
flat-manager-url: https://hub.flathub.org/
|
||||
repository: stable
|
||||
|
||||
3
.github/workflows/linux_build_qt.yml
vendored
3
.github/workflows/linux_build_qt.yml
vendored
@@ -140,9 +140,12 @@ jobs:
|
||||
-DCMAKE_CXX_COMPILER=clang++-17 \
|
||||
-DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" \
|
||||
-DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DENABLE_SETCAP=OFF \
|
||||
-DDISABLE_ADVANCE_SIMD=TRUE \
|
||||
-DUSE_LINKED_FFMPEG=ON \
|
||||
-DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON \
|
||||
$ADDITIONAL_CMAKE_ARGS
|
||||
|
||||
- name: Build PCSX2
|
||||
|
||||
4
.github/workflows/release_cut_new.yml
vendored
4
.github/workflows/release_cut_new.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
|
||||
|
||||
- name: Create a GitHub Release (Manual)
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
tag_name: ${{ steps.tag_version.outputs.new_tag }}
|
||||
|
||||
- name: Create a GitHub Release (Push)
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name != 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
|
||||
44
.github/workflows/scripts/linux/appimage-qt.sh
vendored
44
.github/workflows/scripts/linux/appimage-qt.sh
vendored
@@ -45,16 +45,6 @@ declare -a MANUAL_LIBS=(
|
||||
"libshaderc_shared.so.1"
|
||||
)
|
||||
|
||||
declare -a MANUAL_QT_LIBS=(
|
||||
"libQt6WaylandEglClientHwIntegration.so.6"
|
||||
)
|
||||
|
||||
declare -a MANUAL_QT_PLUGINS=(
|
||||
"wayland-decoration-client"
|
||||
"wayland-graphics-integration-client"
|
||||
"wayland-shell-integration"
|
||||
)
|
||||
|
||||
declare -a REMOVE_LIBS=(
|
||||
'libwayland-client.so*'
|
||||
'libwayland-cursor.so*'
|
||||
@@ -66,7 +56,6 @@ set -e
|
||||
LINUXDEPLOY=./linuxdeploy-x86_64.AppImage
|
||||
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
APPIMAGETOOL=./appimagetool-x86_64.AppImage
|
||||
PATCHELF=patchelf
|
||||
|
||||
if [ ! -f "$LINUXDEPLOY" ]; then
|
||||
"$PCSX2DIR/tools/retry.sh" wget -O "$LINUXDEPLOY" https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||
@@ -125,7 +114,10 @@ cp "$PCSX2DIR/.github/workflows/scripts/linux/pcsx2-qt.desktop" "net.pcsx2.PCSX2
|
||||
cp "$PCSX2DIR/bin/resources/icons/AppIconLarge.png" "PCSX2.png"
|
||||
|
||||
echo "Running linuxdeploy to create AppDir..."
|
||||
EXTRA_QT_PLUGINS="core;gui;svg;waylandclient;widgets;xcbqpa" \
|
||||
# The wayland platform plugin requires the plugins deployed for the waylandcompositor module
|
||||
# Interestingly, specifying the module doesn't copy the module, only the required plugins for it
|
||||
# https://github.com/linuxdeploy/linuxdeploy-plugin-qt/issues/160#issuecomment-2655543893
|
||||
EXTRA_QT_MODULES="core;gui;svg;waylandclient;waylandcompositor;widgets;xcbqpa" \
|
||||
EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" \
|
||||
DEPLOY_PLATFORM_THEMES="1" \
|
||||
QMAKE="$DEPSDIR/bin/qmake" \
|
||||
@@ -136,34 +128,6 @@ $LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/pcsx2-qt
|
||||
echo "Copying resources into AppDir..."
|
||||
cp -a "$BUILDDIR/bin/resources" "$OUTDIR/usr/bin"
|
||||
|
||||
# LinuxDeploy's Qt plugin doesn't include Wayland support. So manually copy in the additional Wayland libraries.
|
||||
echo "Copying Qt Wayland libraries..."
|
||||
for lib in "${MANUAL_QT_LIBS[@]}"; do
|
||||
srcpath="$DEPSDIR/lib/$lib"
|
||||
dstpath="$OUTDIR/usr/lib/$lib"
|
||||
echo " $srcpath -> $dstpath"
|
||||
cp "$srcpath" "$dstpath"
|
||||
$PATCHELF --set-rpath '$ORIGIN' "$dstpath"
|
||||
done
|
||||
|
||||
# .. and plugins.
|
||||
echo "Copying Qt Wayland plugins..."
|
||||
for GROUP in "${MANUAL_QT_PLUGINS[@]}"; do
|
||||
srcpath="$DEPSDIR/plugins/$GROUP"
|
||||
dstpath="$OUTDIR/usr/plugins/$GROUP"
|
||||
echo " $srcpath -> $dstpath"
|
||||
mkdir -p "$dstpath"
|
||||
|
||||
for srcsopath in $(find "$DEPSDIR/plugins/$GROUP" -iname '*.so'); do
|
||||
# This is ../../ because it's usually plugins/group/name.so
|
||||
soname=$(basename "$srcsopath")
|
||||
dstsopath="$dstpath/$soname"
|
||||
echo " $srcsopath -> $dstsopath"
|
||||
cp "$srcsopath" "$dstsopath"
|
||||
$PATCHELF --set-rpath '$ORIGIN/../../lib:$ORIGIN' "$dstsopath"
|
||||
done
|
||||
done
|
||||
|
||||
# Why do we have to manually remove these libs? Because the linuxdeploy Qt plugin
|
||||
# copies them, not the "main" linuxdeploy binary, and plugins don't inherit the
|
||||
# include list...
|
||||
|
||||
@@ -16,13 +16,15 @@ fi
|
||||
|
||||
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
|
||||
LIBJPEGTURBO=3.1.0
|
||||
LIBPNG=1.6.45
|
||||
LIBPNG=1.6.48
|
||||
LIBWEBP=1.5.0
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
SDL=SDL3-3.2.8
|
||||
QT=6.8.2
|
||||
SDL=SDL3-3.2.16
|
||||
QT=6.9.1
|
||||
LZ4=1.10.0
|
||||
ZSTD=1.5.7
|
||||
KDDOCKWIDGETS=2.2.1
|
||||
KDDOCKWIDGETS=2.2.3
|
||||
PLUTOVG=1.1.0
|
||||
PLUTOSVG=0.0.7
|
||||
|
||||
SHADERC=2024.1
|
||||
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -35,22 +37,24 @@ cd deps-build
|
||||
cat > SHASUMS <<EOF
|
||||
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
|
||||
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
46fd06ff37db1db64c0dc288d78a3f5efd23ad9ac41561193f983e20937ece03 libpng-$LIBPNG.tar.xz
|
||||
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
|
||||
6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8 $SDL.tar.gz
|
||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
|
||||
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
aa2579f21ca66d19cbcf31d87e9067e07932635d36869c8239d4decd0a9dc1fa qtsvg-everywhere-src-$QT.tar.xz
|
||||
326381b7d43f07913612f291abc298ae79bd95382e2233abce982cff2b53d2c0 qttools-everywhere-src-$QT.tar.xz
|
||||
d2106e8a580bfd77702c4c1840299288d344902b0e2c758ca813ea04c6d6a3d1 qttranslations-everywhere-src-$QT.tar.xz
|
||||
5e46157908295f2bf924462d8c0855b0508ba338ced9e810891fefa295dc9647 qtwayland-everywhere-src-$QT.tar.xz
|
||||
40caedbf83cc9a1959610830563565889878bc95f115868bbf545d1914acf28e qtbase-everywhere-src-$QT.tar.xz
|
||||
ebe9f238daaf9bb752c7233edadf4af33fc4fa30d914936812b6410d3af1577c qtimageformats-everywhere-src-$QT.tar.xz
|
||||
2dfc5de5fd891ff2afd9861e519bf1a26e6deb729b3133f68a28ba763c9abbd5 qtsvg-everywhere-src-$QT.tar.xz
|
||||
90c4a562f4ccfd043fd99f34c600853e0b5ba9babc6ec616c0f306f2ce3f4b4c qttools-everywhere-src-$QT.tar.xz
|
||||
9761a1a555f447cdeba79fdec6a705dee8a7882ac10c12e85f49467ddd01a741 qttranslations-everywhere-src-$QT.tar.xz
|
||||
7d21ea0e687180ebb19b9a1f86ae9cfa7a25b4f02d5db05ec834164409932e3e qtwayland-everywhere-src-$QT.tar.xz
|
||||
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
|
||||
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
8693e06abee0c88517d8480b22647702a51a0708f3c876ed5385d9a4e356e1a5 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
b8529755b2d54205341766ae168e83177c6120660539f9afba71af6bca4b81ec KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
8aa9860519c407890668c29998e8bb88896ef6a2e6d7ce5ac1e57f18d79e1525 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
@@ -58,7 +62,7 @@ curl -L \
|
||||
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
|
||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
|
||||
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||
@@ -71,7 +75,9 @@ curl -L \
|
||||
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz"
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
|
||||
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
|
||||
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
|
||||
|
||||
shasum -a 256 --check SHASUMS
|
||||
|
||||
@@ -104,7 +110,7 @@ cd ..
|
||||
|
||||
echo "Building LZ4..."
|
||||
rm -fr "lz4-$LZ4"
|
||||
tar xf "$LZ4.tar.gz"
|
||||
tar xf "lz4-$LZ4.tar.gz"
|
||||
cd "lz4-$LZ4"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir -G Ninja build/cmake
|
||||
cmake --build build-dir --parallel
|
||||
@@ -193,32 +199,9 @@ echo "Installing Qt Tools..."
|
||||
rm -fr "qttools-everywhere-src-$QT"
|
||||
tar xf "qttools-everywhere-src-$QT.tar.xz"
|
||||
cd "qttools-everywhere-src-$QT"
|
||||
# Force disable clang scanning, it gets very confused.
|
||||
patch -u configure.cmake <<EOF
|
||||
--- configure.cmake
|
||||
+++ configure.cmake
|
||||
@@ -14,12 +14,12 @@
|
||||
# Presumably because 6.0 ClangConfig.cmake files are not good enough?
|
||||
# In any case explicitly request a minimum version of 8.x for now, otherwise
|
||||
# building with CMake will fail at compilation time.
|
||||
-qt_find_package(WrapLibClang 8 PROVIDED_TARGETS WrapLibClang::WrapLibClang)
|
||||
+#qt_find_package(WrapLibClang 8 PROVIDED_TARGETS WrapLibClang::WrapLibClang)
|
||||
# special case end
|
||||
|
||||
-if(TARGET WrapLibClang::WrapLibClang)
|
||||
- set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE)
|
||||
-endif()
|
||||
+#if(TARGET WrapLibClang::WrapLibClang)
|
||||
+# set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE)
|
||||
+#endif()
|
||||
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
||||
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
||||
cmake --build . --parallel
|
||||
ninja install
|
||||
cd ../../
|
||||
@@ -244,6 +227,24 @@ cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building PlutoVG..."
|
||||
rm -fr "plutovg-$PLUTOVG"
|
||||
tar xf "plutovg-$PLUTOVG.tar.gz"
|
||||
cd "plutovg-$PLUTOVG"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build -G Ninja
|
||||
cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building PlutoSVG..."
|
||||
rm -fr "plutosvg-$PLUTOSVG"
|
||||
tar xf "plutosvg-$PLUTOSVG.tar.gz"
|
||||
cd "plutosvg-$PLUTOSVG"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DPLUTOSVG_ENABLE_FREETYPE=OFF -DPLUTOSVG_BUILD_EXAMPLES=OFF -B build -G Ninja
|
||||
cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building shaderc..."
|
||||
rm -fr "shaderc-$SHADERC"
|
||||
tar xf "shaderc-$SHADERC.tar.gz"
|
||||
|
||||
48
.github/workflows/scripts/linux/build-gammaray.sh
vendored
Executable file
48
.github/workflows/scripts/linux/build-gammaray.sh
vendored
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Syntax: $0 <deps directory> <output directory>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEPSDIR=$(realpath "$1")
|
||||
INSTALLDIR=$(realpath "$2")
|
||||
|
||||
if [ ! -d "$DEPSDIR/include/QtCore" ]; then
|
||||
echo "Error: The build-dependencies-qt.sh script must be run on the deps directory first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GAMMARAY=master
|
||||
|
||||
mkdir -p gammaray-build
|
||||
cd gammaray-build
|
||||
|
||||
echo "Downloading..."
|
||||
curl -L -o "GammaRay-$GAMMARAY.tar.gz" https://github.com/KDAB/GammaRay/archive/$GAMMARAY.tar.gz
|
||||
|
||||
rm -fr "GammaRay-$GAMMARAY"
|
||||
|
||||
echo "Extracting..."
|
||||
tar xf "GammaRay-$GAMMARAY.tar.gz"
|
||||
|
||||
cd "GammaRay-$GAMMARAY"
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
echo "Configuring..."
|
||||
cmake -DCMAKE_PREFIX_PATH="$DEPSDIR" -G Ninja -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DGAMMARAY_BUILD_DOCS=false ..
|
||||
|
||||
echo "Building..."
|
||||
cmake --build . --parallel
|
||||
|
||||
echo "Installing..."
|
||||
cmake --build . --target install
|
||||
|
||||
cd ../..
|
||||
|
||||
echo "Cleaning up..."
|
||||
cd ..
|
||||
rm -r gammaray-build
|
||||
@@ -14,8 +14,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://libsdl.org/release/SDL3-3.2.8.tar.gz",
|
||||
"sha256": "13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03"
|
||||
"url": "https://libsdl.org/release/SDL3-3.2.16.tar.gz",
|
||||
"sha256": "6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/KDAB/KDDockWidgets.git",
|
||||
"tag": "v2.2.1",
|
||||
"commit": "3aaccddc00a11a643e0959a24677838993de15ac",
|
||||
"tag": "v2.2.3",
|
||||
"commit": "28d16d0431d7cdc9f36cb619d22621146fdfab44",
|
||||
"disable-submodules": true
|
||||
},
|
||||
{
|
||||
|
||||
28
.github/workflows/scripts/linux/flatpak/modules/24-plutovg.json
vendored
Normal file
28
.github/workflows/scripts/linux/flatpak/modules/24-plutovg.json
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "plutovg",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"-DBUILD_SHARED_LIBS=ON",
|
||||
"-DPLUTOVG_BUILD_EXAMPLES=OFF"
|
||||
],
|
||||
"build-options": {
|
||||
"strip": true
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/sammycage/plutovg.git",
|
||||
"tag": "v1.1.0",
|
||||
"commit": "1a8412d0574c4345dd7ef8a91ce7b58c7dcfe253"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
"/bin",
|
||||
"/include",
|
||||
"/lib/*.a",
|
||||
"/lib/*.la",
|
||||
"/lib/cmake",
|
||||
"/lib/pkgconfig"
|
||||
]
|
||||
}
|
||||
29
.github/workflows/scripts/linux/flatpak/modules/25-plutosvg.json
vendored
Normal file
29
.github/workflows/scripts/linux/flatpak/modules/25-plutosvg.json
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "plutosvg",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"-DBUILD_SHARED_LIBS=ON",
|
||||
"-DPLUTOSVG_BUILD_EXAMPLES=OFF",
|
||||
"-DPLUTOSVG_ENABLE_FREETYPE=ON"
|
||||
],
|
||||
"build-options": {
|
||||
"strip": true
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/sammycage/plutosvg.git",
|
||||
"tag": "v0.0.7",
|
||||
"commit": "31f7d2675416cd777c8e86220b035364873b2a8b"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
"/bin",
|
||||
"/include",
|
||||
"/lib/*.a",
|
||||
"/lib/*.la",
|
||||
"/lib/cmake",
|
||||
"/lib/pkgconfig"
|
||||
]
|
||||
}
|
||||
@@ -30,6 +30,8 @@
|
||||
"modules/21-libbacktrace.json",
|
||||
"modules/22-shaderc.json",
|
||||
"modules/23-kddockwidgets.json",
|
||||
"modules/24-plutovg.json",
|
||||
"modules/25-plutosvg.json",
|
||||
{
|
||||
"name": "pcsx2",
|
||||
"buildsystem": "cmake-ninja",
|
||||
|
||||
@@ -12,12 +12,24 @@ GIT_DATE=$(git log -1 --pretty=%cd --date=iso8601)
|
||||
GIT_VERSION=$(git tag --points-at HEAD)
|
||||
GIT_HASH=$(git rev-parse HEAD)
|
||||
|
||||
if [[ "${GIT_VERSION}" == "" ]]; then
|
||||
# In the odd event that we run this script before the release gets tagged.
|
||||
GIT_VERSION=$(git describe --tags)
|
||||
if [[ "${GIT_VERSION}" == "" ]]; then
|
||||
GIT_VERSION=$(git rev-parse HEAD)
|
||||
fi
|
||||
if [[ -z "${GIT_VERSION}" ]]; then
|
||||
if git branch -r --contains HEAD | grep -q 'origin/master'; then
|
||||
# Our master doesn't have a tagged commit
|
||||
# This happens when the commit is "ci skip"
|
||||
# abbrev so we have just the latest tag
|
||||
# ie v2.3.420 (Yes, that's the current master at the time of writing)
|
||||
GIT_VERSION=$(git describe --tags --abbrev=0)
|
||||
else
|
||||
# We are probably building a PR
|
||||
# Keep the short SHA in the version
|
||||
# ie v2.3.420-1-g10dc1a2da
|
||||
GIT_VERSION=$(git describe --tags)
|
||||
fi
|
||||
|
||||
if [[ -z "${GIT_VERSION}" ]]; then
|
||||
# Fallback to raw commit hash
|
||||
GIT_VERSION=$(git rev-parse HEAD)
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "GIT_DATE: ${GIT_DATE}"
|
||||
|
||||
@@ -11,7 +11,7 @@ merge_binaries() {
|
||||
"
|
||||
pushd "$X86DIR"
|
||||
for X86BIN in $(find . -type f \( -name '*.dylib' -o -name '*.a' -o -perm +111 \)); do
|
||||
if file "$X86DIR/$X86BIN" | grep "Mach-O " >/dev/null; then
|
||||
if file "$X86DIR/$X86BIN" | grep "Mach-O.*x86_64" >/dev/null; then
|
||||
ARMBIN="${ARMDIR}/${X86BIN}"
|
||||
echo "Merge $ARMBIN to $X86BIN..."
|
||||
lipo -create "$X86BIN" "$ARMBIN" -o "$X86BIN"
|
||||
@@ -39,17 +39,19 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||
fi
|
||||
|
||||
FREETYPE=2.13.3
|
||||
HARFBUZZ=10.0.1
|
||||
SDL=SDL3-3.2.8
|
||||
HARFBUZZ=11.2.0
|
||||
SDL=SDL3-3.2.16
|
||||
ZSTD=1.5.7
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.45
|
||||
LZ4=1.10.0
|
||||
LIBPNG=1.6.48
|
||||
LIBJPEGTURBO=3.1.0
|
||||
LIBWEBP=1.5.0
|
||||
FFMPEG=6.0
|
||||
MOLTENVK=1.2.9
|
||||
QT=6.7.3
|
||||
KDDOCKWIDGETS=2.2.1
|
||||
KDDOCKWIDGETS=2.2.3
|
||||
PLUTOVG=1.1.0
|
||||
PLUTOSVG=0.0.7
|
||||
|
||||
SHADERC=2024.1
|
||||
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -76,11 +78,11 @@ CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
|
||||
16c0204704f3ebeed057aba100fe7db18d71035505cb10e595ea33d346457fc8 harfbuzz-$HARFBUZZ.tar.gz
|
||||
6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8 $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||
46fd06ff37db1db64c0dc288d78a3f5efd23ad9ac41561193f983e20937ece03 libpng-$LIBPNG.tar.xz
|
||||
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
|
||||
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
||||
@@ -94,7 +96,9 @@ eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADE
|
||||
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
8693e06abee0c88517d8480b22647702a51a0708f3c876ed5385d9a4e356e1a5 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
b8529755b2d54205341766ae168e83177c6120660539f9afba71af6bca4b81ec KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
8aa9860519c407890668c29998e8bb88896ef6a2e6d7ce5ac1e57f18d79e1525 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
EOF
|
||||
|
||||
curl -C - -L \
|
||||
@@ -102,22 +106,24 @@ curl -C - -L \
|
||||
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
|
||||
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
|
||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
||||
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz"
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
|
||||
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
|
||||
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
|
||||
|
||||
shasum -a 256 --check SHASUMS
|
||||
|
||||
@@ -181,7 +187,7 @@ cd ..
|
||||
|
||||
echo "Installing LZ4..."
|
||||
rm -fr "lz4-$LZ4"
|
||||
tar xf "$LZ4.tar.gz"
|
||||
tar xf "lz4-$LZ4.tar.gz"
|
||||
cd "lz4-$LZ4"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_X64" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir build/cmake
|
||||
make -C build-dir "-j$NPROCS"
|
||||
@@ -207,8 +213,11 @@ echo "Installing libjpegturbo..."
|
||||
rm -fr "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
tar xf "libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
|
||||
cd "libjpeg-turbo-$LIBJPEGTURBO"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_ARM64" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build-arm64
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_X64" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build
|
||||
make -C build "-j$NPROCS"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_ARM64" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build-arm64
|
||||
make -C build-arm64 "-j$NPROCS"
|
||||
merge_binaries $(realpath build) $(realpath build-arm64)
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
@@ -370,6 +379,24 @@ cmake --build build --parallel
|
||||
cmake --install build
|
||||
cd ..
|
||||
|
||||
echo "Building PlutoVG..."
|
||||
rm -fr "plutovg-$PLUTOVG"
|
||||
tar xf "plutovg-$PLUTOVG.tar.gz"
|
||||
cd "plutovg-$PLUTOVG"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building PlutoSVG..."
|
||||
rm -fr "plutosvg-$PLUTOSVG"
|
||||
tar xf "plutosvg-$PLUTOSVG.tar.gz"
|
||||
cd "plutosvg-$PLUTOSVG"
|
||||
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DBUILD_SHARED_LIBS=ON -DPLUTOSVG_ENABLE_FREETYPE=ON -DPLUTOSVG_BUILD_EXAMPLES=OFF -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Cleaning up..."
|
||||
cd ..
|
||||
rm -rf deps-build
|
||||
|
||||
@@ -21,17 +21,19 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||
fi
|
||||
|
||||
FREETYPE=2.13.3
|
||||
HARFBUZZ=10.0.1
|
||||
SDL=SDL3-3.2.8
|
||||
HARFBUZZ=11.2.0
|
||||
SDL=SDL3-3.2.16
|
||||
ZSTD=1.5.7
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.45
|
||||
LZ4=1.10.0
|
||||
LIBPNG=1.6.48
|
||||
LIBJPEGTURBO=3.1.0
|
||||
LIBWEBP=1.5.0
|
||||
FFMPEG=6.0
|
||||
MOLTENVK=1.2.9
|
||||
QT=6.7.3
|
||||
KDDOCKWIDGETS=2.2.1
|
||||
KDDOCKWIDGETS=2.2.3
|
||||
PLUTOVG=1.1.0
|
||||
PLUTOSVG=0.0.7
|
||||
|
||||
SHADERC=2024.1
|
||||
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -56,11 +58,11 @@ CMAKE_COMMON=(
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
|
||||
16c0204704f3ebeed057aba100fe7db18d71035505cb10e595ea33d346457fc8 harfbuzz-$HARFBUZZ.tar.gz
|
||||
6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8 $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||
46fd06ff37db1db64c0dc288d78a3f5efd23ad9ac41561193f983e20937ece03 libpng-$LIBPNG.tar.xz
|
||||
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
|
||||
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
||||
@@ -74,7 +76,9 @@ eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADE
|
||||
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
8693e06abee0c88517d8480b22647702a51a0708f3c876ed5385d9a4e356e1a5 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
b8529755b2d54205341766ae168e83177c6120660539f9afba71af6bca4b81ec KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
8aa9860519c407890668c29998e8bb88896ef6a2e6d7ce5ac1e57f18d79e1525 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
@@ -82,22 +86,24 @@ curl -L \
|
||||
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
|
||||
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
|
||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
||||
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz"
|
||||
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
|
||||
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
|
||||
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
|
||||
|
||||
shasum -a 256 --check SHASUMS
|
||||
|
||||
@@ -140,7 +146,7 @@ cd ..
|
||||
|
||||
echo "Installing LZ4..."
|
||||
rm -fr "lz4-$LZ4"
|
||||
tar xf "$LZ4.tar.gz"
|
||||
tar xf "lz4-$LZ4.tar.gz"
|
||||
cd "lz4-$LZ4"
|
||||
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir build/cmake
|
||||
make -C build-dir "-j$NPROCS"
|
||||
@@ -335,6 +341,24 @@ make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building PlutoVG..."
|
||||
rm -fr "plutovg-$PLUTOVG"
|
||||
tar xf "plutovg-$PLUTOVG.tar.gz"
|
||||
cd "plutovg-$PLUTOVG"
|
||||
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Building PlutoSVG..."
|
||||
rm -fr "plutosvg-$PLUTOSVG"
|
||||
tar xf "plutosvg-$PLUTOSVG.tar.gz"
|
||||
cd "plutosvg-$PLUTOSVG"
|
||||
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DPLUTOSVG_ENABLE_FREETYPE=ON -DPLUTOSVG_BUILD_EXAMPLES=OFF -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Cleaning up..."
|
||||
cd ..
|
||||
rm -rf deps-build
|
||||
|
||||
@@ -66,7 +66,7 @@ const embed = new MessageEmbed()
|
||||
.setDescription("To download the latest or previous builds, [visit the official downloads page](https://pcsx2.net/downloads/).")
|
||||
.addFields(
|
||||
{ name: 'Version', value: releaseInfo.tag_name, inline: true },
|
||||
{ name: 'Installation Steps', value: '[See Here](https://github.com/PCSX2/pcsx2/wiki/Nightly-Build-Usage-Guide)', inline: true },
|
||||
{ name: 'Installation Steps', value: '[See Here](https://pcsx2.net/docs/category/setup)', inline: true },
|
||||
{ name: 'Included Changes', value: releaseInfo.body, inline: false }
|
||||
);
|
||||
console.log(embed);
|
||||
|
||||
411
.github/workflows/scripts/releases/generate-release-notes/package-lock.json
generated
vendored
411
.github/workflows/scripts/releases/generate-release-notes/package-lock.json
generated
vendored
@@ -9,123 +9,11 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/plugin-throttling": "^9.6.0",
|
||||
"@octokit/rest": "^21.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
|
||||
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.1.0.tgz",
|
||||
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-retry": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz",
|
||||
"integrity": "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"bottleneck": "^2.15.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-3.5.2.tgz",
|
||||
"integrity": "sha512-Eu7kfJxU8vmHqWGNszWpg+GVp2tnAfax3XQV5CkYPEE69C+KvInJXW9WajgSeW+cxYe0UVdouzCtcreGNuJo7A==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.1",
|
||||
"bottleneck": "^2.15.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "^3.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz",
|
||||
"integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
||||
"@octokit/plugin-request-log": "^5.3.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/auth-token": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz",
|
||||
"integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==",
|
||||
@@ -134,7 +22,7 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/core": {
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz",
|
||||
"integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==",
|
||||
@@ -152,7 +40,22 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/endpoint": {
|
||||
"node_modules/@octokit/core/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/core/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz",
|
||||
"integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==",
|
||||
@@ -165,7 +68,22 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/graphql": {
|
||||
"node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/endpoint/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz",
|
||||
"integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==",
|
||||
@@ -179,6 +97,139 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/graphql/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.1.0.tgz",
|
||||
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-retry": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz",
|
||||
"integrity": "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"bottleneck": "^2.15.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.6.0.tgz",
|
||||
"integrity": "sha512-zn7m1N3vpJDaVzLqjCRdJ0cRzNiekHEWPi8Ww9xyPNrDt5PStHvVE0eR8wy4RSU8Eg7YO8MHyvn6sv25EGVhhg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.7.0",
|
||||
"bottleneck": "^2.15.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "^6.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
|
||||
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^10.1.3",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"fast-content-type-parse": "^2.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
|
||||
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/request-error/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/request/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
||||
"@octokit/plugin-request-log": "^5.3.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
@@ -227,34 +278,6 @@
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/request": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
|
||||
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^10.1.3",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"fast-content-type-parse": "^2.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/request-error": {
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
|
||||
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
@@ -264,18 +287,6 @@
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/before-after-hook": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/universal-user-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "6.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.33.0.tgz",
|
||||
@@ -285,22 +296,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==",
|
||||
"peer": true
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
|
||||
@@ -317,77 +322,11 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"peer": true
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==",
|
||||
"license": "ISC"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/plugin-throttling": "^9.6.0",
|
||||
"@octokit/rest": "^21.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,18 +43,20 @@ echo INSTALLDIR=%INSTALLDIR%
|
||||
cd "%BUILDDIR%"
|
||||
|
||||
set FREETYPE=2.13.3
|
||||
set HARFBUZZ=10.0.1
|
||||
set HARFBUZZ=11.2.0
|
||||
set LIBJPEGTURBO=3.1.0
|
||||
set LIBPNG=1645
|
||||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.8.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL3-3.2.8
|
||||
set LIBPNG=1648
|
||||
set SDL=SDL3-3.2.16
|
||||
set QT=6.9.1
|
||||
set QTMINOR=6.9
|
||||
set LZ4=1.10.0
|
||||
set WEBP=1.5.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
set ZSTD=1.5.7
|
||||
set KDDOCKWIDGETS=2.2.1
|
||||
set KDDOCKWIDGETS=2.2.3
|
||||
set PLUTOVG=1.1.0
|
||||
set PLUTOSVG=0.0.7
|
||||
|
||||
set SHADERC=2024.1
|
||||
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -62,20 +64,22 @@ set SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
|
||||
set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1645.zip a66c4b1350b67776e90263e2550933067cd9ccbd318db489f84dcc0d2b033249 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 850cb5e38e21106c0abba86c5b73f8f74b9a32d7725505901d081080b0d3f0b3 || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1648.zip 2e5f080360f77376eb2bfa9e2ed773b9c7728159aba47b638ad53ca839379040 || goto error
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 0cc7430fb827c1f843e31b8b26ba7f083b1eeb8f6315a65d3744fd4d25b6c373 || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" efa6d8ef9f7ae0fd9f7d280fbff574d71882b60a357ae639e516dc173cf26986 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 8439d3394bc380fd17a920ee96df1d2272bf8d3490871d948ef750f95e0ded06 || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" a8f90c768b54e28d61e02c1229b74a2b834e9852af523e5c70bcd2ae4c34a772 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 38db91c4a8044c395eac89e325ecc25edbda12606fc28812491ef5e5b6b53dd6 || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" fd2e776164751fb486495efeee336d26d85fe1ca1f6a7b9eb6aafca2e3d333aa || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v2.2.1.zip" 78b5e242bf47476e150175b7de934ab84069459e151beb2d5ce84fd067138aa5 || goto error
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 1ba8e5b48f3b4d47d2de7121529d448532200fa36d9ed21f93909f6eb03f61cb || goto error
|
||||
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 83b2cd6230909a8d586518f49e79e4a1b1e9fab3847db6a678ec9d2dacab052a || goto error
|
||||
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
|
||||
@@ -242,12 +246,39 @@ cmake --build . --parallel || goto error
|
||||
ninja install || goto error
|
||||
cd ..\.. || goto error
|
||||
|
||||
if %DEBUG%==1 (
|
||||
set KDDOCKWIDGETSBUILDSPEC=-DCMAKE_CONFIGURATION_TYPES="Release;Debug" -DCMAKE_CROSS_CONFIGS=all -DCMAKE_DEFAULT_BUILD_TYPE=Release -DCMAKE_DEFAULT_CONFIGS=all -G "Ninja Multi-Config"
|
||||
) else (
|
||||
rem kddockwidgets slightly changes the name of the dll depending on if CMAKE_BUILD_TYPE or CMAKE_CONFIGURATION_TYPES is used
|
||||
rem The dll name being kddockwidgets-qt62.dll or kddockwidgets-qt62.dll respectively
|
||||
rem Always use CMAKE_CONFIGURATION_TYPES to give consistant naming
|
||||
set KDDOCKWIDGETSBUILDSPEC=-DCMAKE_CONFIGURATION_TYPES=Release -DCMAKE_CROSS_CONFIGS=all -DCMAKE_DEFAULT_BUILD_TYPE=Release -DCMAKE_DEFAULT_CONFIGS=Release -G "Ninja Multi-Config"
|
||||
)
|
||||
|
||||
echo "Building KDDockWidgets..."
|
||||
rmdir /S /Q "KDDockWidgets-%KDDOCKWIDGETS%"
|
||||
%SEVENZIP% x "KDDockWidgets-%KDDOCKWIDGETS%.zip" || goto error
|
||||
cd "KDDockWidgets-%KDDOCKWIDGETS%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\..\common\kddockwidgets-dodgy-include.patch" || goto error
|
||||
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets -B build -G Ninja || goto error
|
||||
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets %KDDOCKWIDGETSBUILDSPEC% || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo "Building PlutoVG..."
|
||||
rmdir /S /Q "plutovg-%PLUTOVG%"
|
||||
%SEVENZIP% x "plutovg-%PLUTOVG%.zip" || goto error
|
||||
cd "plutovg-%PLUTOVG%" || goto error
|
||||
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo "Building PlutoSVG..."
|
||||
rmdir /S /Q "plutosvg-%PLUTOSVG%"
|
||||
%SEVENZIP% x "plutosvg-%PLUTOSVG%.zip" || goto error
|
||||
cd "plutosvg-%PLUTOSVG%" || goto error
|
||||
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DPLUTOSVG_ENABLE_FREETYPE=ON -DPLUTOSVG_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
@@ -41,18 +41,20 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
|
||||
cd "%BUILDDIR%"
|
||||
|
||||
set FREETYPE=2.13.3
|
||||
set HARFBUZZ=10.0.1
|
||||
set HARFBUZZ=11.2.0
|
||||
set LIBJPEGTURBO=3.1.0
|
||||
set LIBPNG=1645
|
||||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.8.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL3-3.2.8
|
||||
set LIBPNG=1648
|
||||
set SDL=SDL3-3.2.16
|
||||
set QT=6.9.1
|
||||
set QTMINOR=6.9
|
||||
set LZ4=1.10.0
|
||||
set WEBP=1.5.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
set ZSTD=1.5.7
|
||||
set KDDOCKWIDGETS=2.2.1
|
||||
set KDDOCKWIDGETS=2.2.3
|
||||
set PLUTOVG=1.1.0
|
||||
set PLUTOSVG=0.0.7
|
||||
|
||||
set SHADERC=2024.1
|
||||
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||
@@ -60,20 +62,22 @@ set SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
|
||||
set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1645.zip a66c4b1350b67776e90263e2550933067cd9ccbd318db489f84dcc0d2b033249 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 850cb5e38e21106c0abba86c5b73f8f74b9a32d7725505901d081080b0d3f0b3 || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1648.zip 2e5f080360f77376eb2bfa9e2ed773b9c7728159aba47b638ad53ca839379040 || goto error
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 0cc7430fb827c1f843e31b8b26ba7f083b1eeb8f6315a65d3744fd4d25b6c373 || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" efa6d8ef9f7ae0fd9f7d280fbff574d71882b60a357ae639e516dc173cf26986 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 8439d3394bc380fd17a920ee96df1d2272bf8d3490871d948ef750f95e0ded06 || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" a8f90c768b54e28d61e02c1229b74a2b834e9852af523e5c70bcd2ae4c34a772 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 38db91c4a8044c395eac89e325ecc25edbda12606fc28812491ef5e5b6b53dd6 || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" fd2e776164751fb486495efeee336d26d85fe1ca1f6a7b9eb6aafca2e3d333aa || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v2.2.1.zip" 78b5e242bf47476e150175b7de934ab84069459e151beb2d5ce84fd067138aa5 || goto error
|
||||
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 1ba8e5b48f3b4d47d2de7121529d448532200fa36d9ed21f93909f6eb03f61cb || goto error
|
||||
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 83b2cd6230909a8d586518f49e79e4a1b1e9fab3847db6a678ec9d2dacab052a || goto error
|
||||
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
|
||||
@@ -86,7 +90,7 @@ if %DEBUG%==1 (
|
||||
echo Building release libraries...
|
||||
)
|
||||
|
||||
set FORCEPDB=-DCMAKE_SHARED_LINKER_FLAGS_RELEASE="/DEBUG"
|
||||
set FORCEPDB=-DCMAKE_SHARED_LINKER_FLAGS_RELEASE="/DEBUG" -DCMAKE_MODULE_LINKER_FLAGS_RELEASE="/DEBUG"
|
||||
|
||||
echo Building Zlib...
|
||||
rmdir /S /Q "zlib-%ZLIB%"
|
||||
@@ -194,9 +198,6 @@ cd "qtbase-everywhere-src-%QT%" || goto error
|
||||
rem Disable the PCRE2 JIT, it doesn't properly verify AVX2 support.
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\qtbase-disable-pcre2-jit.patch" || goto error
|
||||
|
||||
rem Hackfix settings icon stretching
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\qtbase-fix-icon-stretch.patch" || goto error
|
||||
|
||||
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
@@ -246,12 +247,39 @@ cmake --build . --parallel || goto error
|
||||
ninja install || goto error
|
||||
cd ..\.. || goto error
|
||||
|
||||
if %DEBUG%==1 (
|
||||
set KDDOCKWIDGETSBUILDSPEC=-DCMAKE_CONFIGURATION_TYPES="Release;Debug" -DCMAKE_CROSS_CONFIGS=all -DCMAKE_DEFAULT_BUILD_TYPE=Release -DCMAKE_DEFAULT_CONFIGS=all -G "Ninja Multi-Config"
|
||||
) else (
|
||||
rem kddockwidgets slightly changes the name of the dll depending on if CMAKE_BUILD_TYPE or CMAKE_CONFIGURATION_TYPES is used
|
||||
rem The dll name being kddockwidgets-qt62.dll or kddockwidgets-qt6.dll respectively
|
||||
rem Always use CMAKE_CONFIGURATION_TYPES to give consistent naming
|
||||
set KDDOCKWIDGETSBUILDSPEC=-DCMAKE_CONFIGURATION_TYPES=Release -DCMAKE_CROSS_CONFIGS=all -DCMAKE_DEFAULT_BUILD_TYPE=Release -DCMAKE_DEFAULT_CONFIGS=Release -G "Ninja Multi-Config"
|
||||
)
|
||||
|
||||
echo "Building KDDockWidgets..."
|
||||
rmdir /S /Q "KDDockWidgets-%KDDOCKWIDGETS%"
|
||||
%SEVENZIP% x "KDDockWidgets-%KDDOCKWIDGETS%.zip" || goto error
|
||||
cd "KDDockWidgets-%KDDOCKWIDGETS%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\..\common\kddockwidgets-dodgy-include.patch" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets -B build -G Ninja || goto error
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DKDDockWidgets_QT6=true -DKDDockWidgets_EXAMPLES=false -DKDDockWidgets_FRONTENDS=qtwidgets %KDDOCKWIDGETSBUILDSPEC% || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo "Building PlutoVG..."
|
||||
rmdir /S /Q "plutovg-%PLUTOVG%"
|
||||
%SEVENZIP% x "plutovg-%PLUTOVG%.zip" || goto error
|
||||
cd "plutovg-%PLUTOVG%" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo "Building PlutoSVG..."
|
||||
rmdir /S /Q "plutosvg-%PLUTOSVG%"
|
||||
%SEVENZIP% x "plutosvg-%PLUTOSVG%.zip" || goto error
|
||||
cd "plutosvg-%PLUTOSVG%" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DPLUTOSVG_ENABLE_FREETYPE=ON -DPLUTOSVG_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
68
.github/workflows/scripts/windows/build-gammaray.bat
vendored
Normal file
68
.github/workflows/scripts/windows/build-gammaray.bat
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo Setting environment...
|
||||
if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" (
|
||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
||||
) else if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" (
|
||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
) else (
|
||||
echo Visual Studio 2022 not found.
|
||||
goto error
|
||||
)
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
cd ..\..\..\..
|
||||
cd deps || goto error
|
||||
set "DEPSDIR=%CD%"
|
||||
cd ..
|
||||
mkdir gammaray
|
||||
cd gammaray || goto error
|
||||
set "INSTALLDIR=%CD%"
|
||||
cd ..
|
||||
mkdir gammaray-build
|
||||
cd gammaray-build || goto error
|
||||
set "BUILDDIR=%CD%"
|
||||
|
||||
echo DEPSDIR=%DEPSDIR%
|
||||
echo BUILDDIR=%BUILDDIR%
|
||||
echo INSTALLDIR=%INSTALLDIR%
|
||||
|
||||
set GAMMARAY="master"
|
||||
|
||||
echo Downloading...
|
||||
curl -L -o "GammaRay-%GAMMARAY%.tar.gz" "https://github.com/KDAB/GammaRay/archive/%GAMMARAY%.tar.gz" || goto error
|
||||
|
||||
rmdir /s /q "GammaRay-%GAMMARAY%"
|
||||
|
||||
echo Extracting...
|
||||
tar -xf "GammaRay-%GAMMARAY%.tar.gz" || goto error
|
||||
|
||||
echo Configuring...
|
||||
cmake "GammaRay-%GAMMARAY%" -B build -DCMAKE_PREFIX_PATH="%DEPSDIR%" -G Ninja -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DGAMMARAY_BUILD_DOCS=false || goto error
|
||||
|
||||
echo Building...
|
||||
cmake --build build --parallel || goto error
|
||||
|
||||
echo Installing...
|
||||
cmake --build build --target install || goto errorlevel
|
||||
|
||||
echo Copying DLLs...
|
||||
xcopy /y "%DEPSDIR%\bin\*.dll" "%INSTALLDIR%\bin\"
|
||||
xcopy /y /e /s "%DEPSDIR%\plugins" "%INSTALLDIR%\bin\"
|
||||
|
||||
echo Cleaning up...
|
||||
cd ..
|
||||
rd /s /q gammaray-build
|
||||
|
||||
echo Exiting with success.
|
||||
popd
|
||||
pause
|
||||
exit 0
|
||||
|
||||
:error
|
||||
echo Failed with error #%errorlevel%.
|
||||
popd
|
||||
pause
|
||||
exit %errorlevel%
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
|
||||
index 208420d7e8..26ef6f31ef 100644
|
||||
--- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
|
||||
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
|
||||
@@ -4232,8 +4232,6 @@ QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption
|
||||
|
||||
case SE_ItemViewItemDecoration:
|
||||
rect = QWindowsStyle::subElementRect(element, option, widget);
|
||||
- if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
|
||||
- rect.adjust(-2, 0, 2, 0);
|
||||
break;
|
||||
|
||||
case SE_ItemViewItemFocusRect:
|
||||
2
.github/workflows/triage_pr.yml
vendored
2
.github/workflows/triage_pr.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
pr-message: |-
|
||||
## Thank you for submitting a contribution to PCSX2
|
||||
|
||||
As this is your first pull request, [please be aware of the contributing guidelines](https://github.com/PCSX2/pcsx2/blob/master/.github/CONTRIBUTING.md).
|
||||
As this is your first pull request, [please be aware of the contributing guidelines](https://pcsx2.net/docs/contributing/).
|
||||
|
||||
Additionally, as per recent changes in GitHub Actions, your pull request will need to be approved by a maintainer before GitHub Actions can run against it. [You can find more information about this change here.](https://github.blog/2021-04-22-github-actions-update-helping-maintainers-combat-bad-actors/)
|
||||
|
||||
|
||||
2
.github/workflows/windows_build_qt.yml
vendored
2
.github/workflows/windows_build_qt.yml
vendored
@@ -168,7 +168,7 @@ jobs:
|
||||
!./bin/**/*.lib
|
||||
|
||||
- name: Install the Breakpad Symbol Generator
|
||||
uses: baptiste0928/cargo-install@91c5da15570085bcde6f4d7aed98cb82d6769fd3
|
||||
uses: baptiste0928/cargo-install@e38323ef017552d7f7af73a3f4db467f278310ed
|
||||
with:
|
||||
crate: dump_syms
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -109,6 +109,8 @@ oprofile_data/
|
||||
/deps-build
|
||||
/deps
|
||||
/deps-arm64
|
||||
/gammaray-build
|
||||
/gammaray
|
||||
/ipch
|
||||
|
||||
!/3rdparty/libjpeg/change.log
|
||||
|
||||
11
3rdparty/cpuinfo/include/cpuinfo.h
vendored
11
3rdparty/cpuinfo/include/cpuinfo.h
vendored
@@ -522,6 +522,8 @@ enum cpuinfo_uarch {
|
||||
cpuinfo_uarch_falkor = 0x00400103,
|
||||
/** Qualcomm Saphira. */
|
||||
cpuinfo_uarch_saphira = 0x00400104,
|
||||
/** Qualcomm Oryon. */
|
||||
cpuinfo_uarch_oryon = 0x00400105,
|
||||
|
||||
/** Nvidia Denver. */
|
||||
cpuinfo_uarch_denver = 0x00500100,
|
||||
@@ -821,6 +823,7 @@ struct cpuinfo_x86_isa {
|
||||
bool avx512_4vnniw;
|
||||
bool avx512_4fmaps;
|
||||
bool avx10_1;
|
||||
bool avx10_2;
|
||||
bool amx_bf16;
|
||||
bool amx_tile;
|
||||
bool amx_int8;
|
||||
@@ -1444,6 +1447,14 @@ static inline bool cpuinfo_has_x86_avx10_1(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool cpuinfo_has_x86_avx10_2(void) {
|
||||
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
|
||||
return cpuinfo_isa.avx10_2;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool cpuinfo_has_x86_hle(void) {
|
||||
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
|
||||
return cpuinfo_isa.hle;
|
||||
|
||||
28
3rdparty/cpuinfo/src/arm/api.h
vendored
28
3rdparty/cpuinfo/src/arm/api.h
vendored
@@ -1,5 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define RESTRICT_STATIC /* nothing for MSVC */
|
||||
#else
|
||||
#define RESTRICT_STATIC restrict static
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -82,11 +88,11 @@ struct cpuinfo_arm_chipset {
|
||||
|
||||
#ifndef __cplusplus
|
||||
CPUINFO_INTERNAL void cpuinfo_arm_chipset_to_string(
|
||||
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||
char name[restrict static CPUINFO_ARM_CHIPSET_NAME_MAX]);
|
||||
const struct cpuinfo_arm_chipset chipset[RESTRICT_STATIC 1],
|
||||
char name[RESTRICT_STATIC CPUINFO_ARM_CHIPSET_NAME_MAX]);
|
||||
|
||||
CPUINFO_INTERNAL void cpuinfo_arm_fixup_chipset(
|
||||
struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||
struct cpuinfo_arm_chipset chipset[RESTRICT_STATIC 1],
|
||||
uint32_t cores,
|
||||
uint32_t max_cpu_freq_max);
|
||||
|
||||
@@ -95,23 +101,23 @@ CPUINFO_INTERNAL void cpuinfo_arm_decode_vendor_uarch(
|
||||
#if CPUINFO_ARCH_ARM
|
||||
bool has_vfpv4,
|
||||
#endif
|
||||
enum cpuinfo_vendor vendor[restrict static 1],
|
||||
enum cpuinfo_uarch uarch[restrict static 1]);
|
||||
enum cpuinfo_vendor vendor[RESTRICT_STATIC 1],
|
||||
enum cpuinfo_uarch uarch[RESTRICT_STATIC 1]);
|
||||
|
||||
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
|
||||
enum cpuinfo_uarch uarch,
|
||||
uint32_t cluster_cores,
|
||||
uint32_t midr,
|
||||
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||
const struct cpuinfo_arm_chipset chipset[RESTRICT_STATIC 1],
|
||||
uint32_t cluster_id,
|
||||
uint32_t arch_version,
|
||||
struct cpuinfo_cache l1i[restrict static 1],
|
||||
struct cpuinfo_cache l1d[restrict static 1],
|
||||
struct cpuinfo_cache l2[restrict static 1],
|
||||
struct cpuinfo_cache l3[restrict static 1]);
|
||||
struct cpuinfo_cache l1i[RESTRICT_STATIC 1],
|
||||
struct cpuinfo_cache l1d[RESTRICT_STATIC 1],
|
||||
struct cpuinfo_cache l2[RESTRICT_STATIC 1],
|
||||
struct cpuinfo_cache l3[RESTRICT_STATIC 1]);
|
||||
|
||||
CPUINFO_INTERNAL uint32_t
|
||||
cpuinfo_arm_compute_max_cache_size(const struct cpuinfo_processor processor[restrict static 1]);
|
||||
cpuinfo_arm_compute_max_cache_size(const struct cpuinfo_processor processor[RESTRICT_STATIC 1]);
|
||||
#else /* defined(__cplusplus) */
|
||||
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
|
||||
enum cpuinfo_uarch uarch,
|
||||
|
||||
1
3rdparty/cpuinfo/src/arm/mach/init.c
vendored
1
3rdparty/cpuinfo/src/arm/mach/init.c
vendored
@@ -101,7 +101,6 @@ static enum cpuinfo_uarch decode_uarch(uint32_t cpu_family, uint32_t core_index,
|
||||
return cpuinfo_uarch_unknown;
|
||||
}
|
||||
|
||||
/* Small bodge until cpuinfo merges PR #246 */
|
||||
static int read_package_name_from_brand_string(char* package_name) {
|
||||
size_t size;
|
||||
if (sysctlbyname("machdep.cpu.brand_string", NULL, &size, NULL, 0) != 0) {
|
||||
|
||||
7
3rdparty/cpuinfo/src/arm/uarch.c
vendored
7
3rdparty/cpuinfo/src/arm/uarch.c
vendored
@@ -9,8 +9,8 @@ void cpuinfo_arm_decode_vendor_uarch(
|
||||
#if CPUINFO_ARCH_ARM
|
||||
bool has_vfpv4,
|
||||
#endif /* CPUINFO_ARCH_ARM */
|
||||
enum cpuinfo_vendor vendor[restrict static 1],
|
||||
enum cpuinfo_uarch uarch[restrict static 1]) {
|
||||
enum cpuinfo_vendor vendor[RESTRICT_STATIC 1],
|
||||
enum cpuinfo_uarch uarch[RESTRICT_STATIC 1]) {
|
||||
switch (midr_get_implementer(midr)) {
|
||||
case 'A':
|
||||
*vendor = cpuinfo_vendor_arm;
|
||||
@@ -332,6 +332,9 @@ void cpuinfo_arm_decode_vendor_uarch(
|
||||
*uarch = cpuinfo_uarch_cortex_a55;
|
||||
break;
|
||||
#if CPUINFO_ARCH_ARM64
|
||||
case 0x001:
|
||||
*uarch = cpuinfo_uarch_oryon;
|
||||
break;
|
||||
case 0xC00:
|
||||
*uarch = cpuinfo_uarch_falkor;
|
||||
break;
|
||||
|
||||
@@ -750,11 +750,14 @@ void store_core_info_per_processor(
|
||||
if (cores) {
|
||||
processors[processor_global_index].core = cores + core_id;
|
||||
cores[core_id].core_id = core_id;
|
||||
get_core_uarch_for_efficiency(
|
||||
chip_info->chip_name,
|
||||
core_info->Processor.EfficiencyClass,
|
||||
&(cores[core_id].uarch),
|
||||
&(cores[core_id].frequency));
|
||||
|
||||
if (chip_info->uarchs == NULL) {
|
||||
cpuinfo_log_error("uarch is NULL for core %d", core_id);
|
||||
return;
|
||||
}
|
||||
|
||||
cores[core_id].uarch = chip_info->uarchs[0].uarch;
|
||||
cores[core_id].frequency = chip_info->uarchs[0].frequency;
|
||||
|
||||
/* We don't have cluster information, so we handle it as
|
||||
* fixed 1 to (cluster / cores).
|
||||
|
||||
187
3rdparty/cpuinfo/src/arm/windows/init.c
vendored
187
3rdparty/cpuinfo/src/arm/windows/init.c
vendored
@@ -7,6 +7,9 @@
|
||||
#include <cpuinfo/internal-api.h>
|
||||
#include <cpuinfo/log.h>
|
||||
|
||||
#include <arm/api.h>
|
||||
#include <arm/midr.h>
|
||||
|
||||
#include "windows-arm-init.h"
|
||||
|
||||
struct cpuinfo_arm_isa cpuinfo_isa;
|
||||
@@ -14,62 +17,7 @@ struct cpuinfo_arm_isa cpuinfo_isa;
|
||||
static void set_cpuinfo_isa_fields(void);
|
||||
static struct woa_chip_info* get_system_info_from_registry(void);
|
||||
|
||||
static struct woa_chip_info woa_chip_unknown = {
|
||||
L"Unknown",
|
||||
woa_chip_name_unknown,
|
||||
{{cpuinfo_vendor_unknown, cpuinfo_uarch_unknown, 0}}};
|
||||
|
||||
/* Please add new SoC/chip info here! */
|
||||
static struct woa_chip_info woa_chips[woa_chip_name_last] = {
|
||||
/* Microsoft SQ1 Kryo 495 4 + 4 cores (3 GHz + 1.80 GHz) */
|
||||
[woa_chip_name_microsoft_sq_1] =
|
||||
{L"Microsoft SQ1",
|
||||
woa_chip_name_microsoft_sq_1,
|
||||
{{
|
||||
cpuinfo_vendor_arm,
|
||||
cpuinfo_uarch_cortex_a55,
|
||||
1800000000,
|
||||
},
|
||||
{
|
||||
cpuinfo_vendor_arm,
|
||||
cpuinfo_uarch_cortex_a76,
|
||||
3000000000,
|
||||
}}},
|
||||
/* Microsoft SQ2 Kryo 495 4 + 4 cores (3.15 GHz + 2.42 GHz) */
|
||||
[woa_chip_name_microsoft_sq_2] =
|
||||
{L"Microsoft SQ2",
|
||||
woa_chip_name_microsoft_sq_2,
|
||||
{{
|
||||
cpuinfo_vendor_arm,
|
||||
cpuinfo_uarch_cortex_a55,
|
||||
2420000000,
|
||||
},
|
||||
{cpuinfo_vendor_arm, cpuinfo_uarch_cortex_a76, 3150000000}}},
|
||||
/* Snapdragon (TM) 8cx Gen 3 @ 3.0 GHz */
|
||||
[woa_chip_name_microsoft_sq_3] =
|
||||
{L"Snapdragon (TM) 8cx Gen 3",
|
||||
woa_chip_name_microsoft_sq_3,
|
||||
{{
|
||||
cpuinfo_vendor_arm,
|
||||
cpuinfo_uarch_cortex_a78,
|
||||
2420000000,
|
||||
},
|
||||
{cpuinfo_vendor_arm, cpuinfo_uarch_cortex_x1, 3000000000}}},
|
||||
/* Microsoft Windows Dev Kit 2023 */
|
||||
[woa_chip_name_microsoft_sq_3_devkit] =
|
||||
{L"Snapdragon Compute Platform",
|
||||
woa_chip_name_microsoft_sq_3_devkit,
|
||||
{{
|
||||
cpuinfo_vendor_arm,
|
||||
cpuinfo_uarch_cortex_a78,
|
||||
2420000000,
|
||||
},
|
||||
{cpuinfo_vendor_arm, cpuinfo_uarch_cortex_x1, 3000000000}}},
|
||||
/* Ampere Altra */
|
||||
[woa_chip_name_ampere_altra] = {
|
||||
L"Ampere(R) Altra(R) Processor",
|
||||
woa_chip_name_ampere_altra,
|
||||
{{cpuinfo_vendor_arm, cpuinfo_uarch_neoverse_n1, 3000000000}}}};
|
||||
static struct woa_chip_info woa_chip_unknown = {L"Unknown", {{cpuinfo_vendor_unknown, cpuinfo_uarch_unknown, 0}}};
|
||||
|
||||
BOOL CALLBACK cpuinfo_arm_windows_init(PINIT_ONCE init_once, PVOID parameter, PVOID* context) {
|
||||
struct woa_chip_info* chip_info = NULL;
|
||||
@@ -87,23 +35,6 @@ BOOL CALLBACK cpuinfo_arm_windows_init(PINIT_ONCE init_once, PVOID parameter, PV
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_core_uarch_for_efficiency(
|
||||
enum woa_chip_name chip,
|
||||
BYTE EfficiencyClass,
|
||||
enum cpuinfo_uarch* uarch,
|
||||
uint64_t* frequency) {
|
||||
/* For currently supported WoA chips, the Efficiency class selects
|
||||
* the pre-defined little and big core.
|
||||
* Any further supported SoC's logic should be implemented here.
|
||||
*/
|
||||
if (uarch && frequency && chip < woa_chip_name_last && EfficiencyClass < MAX_WOA_VALID_EFFICIENCY_CLASSES) {
|
||||
*uarch = woa_chips[chip].uarchs[EfficiencyClass].uarch;
|
||||
*frequency = woa_chips[chip].uarchs[EfficiencyClass].frequency;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Static helper functions */
|
||||
|
||||
static wchar_t* read_registry(LPCWSTR subkey, LPCWSTR value) {
|
||||
@@ -149,40 +80,112 @@ static wchar_t* read_registry(LPCWSTR subkey, LPCWSTR value) {
|
||||
return text_buffer;
|
||||
}
|
||||
|
||||
static uint64_t read_registry_qword(LPCWSTR subkey, LPCWSTR value) {
|
||||
DWORD key_type = 0;
|
||||
DWORD data_size = sizeof(uint64_t);
|
||||
const DWORD flags = RRF_RT_REG_QWORD; /* Only read QWORD (REG_QWORD) values */
|
||||
uint64_t qword_value = 0;
|
||||
LSTATUS result = RegGetValueW(HKEY_LOCAL_MACHINE, subkey, value, flags, &key_type, &qword_value, &data_size);
|
||||
if (result != ERROR_SUCCESS || data_size != sizeof(uint64_t)) {
|
||||
cpuinfo_log_error("Registry QWORD read error");
|
||||
return 0;
|
||||
}
|
||||
return qword_value;
|
||||
}
|
||||
|
||||
static uint64_t read_registry_dword(LPCWSTR subkey, LPCWSTR value) {
|
||||
DWORD key_type = 0;
|
||||
DWORD data_size = sizeof(DWORD);
|
||||
DWORD dword_value = 0;
|
||||
LSTATUS result =
|
||||
RegGetValueW(HKEY_LOCAL_MACHINE, subkey, value, RRF_RT_REG_DWORD, &key_type, &dword_value, &data_size);
|
||||
if (result != ERROR_SUCCESS || data_size != sizeof(DWORD)) {
|
||||
cpuinfo_log_error("Registry DWORD read error");
|
||||
return 0;
|
||||
}
|
||||
return (uint64_t)dword_value;
|
||||
}
|
||||
|
||||
static wchar_t* wcsndup(const wchar_t* src, size_t n) {
|
||||
size_t len = wcsnlen(src, n);
|
||||
wchar_t* dup = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(wchar_t));
|
||||
if (dup) {
|
||||
wcsncpy_s(dup, len + 1, src, len);
|
||||
dup[len] = L'\0';
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
static struct core_info_by_chip_name get_core_info_from_midr(uint32_t midr, uint64_t frequency) {
|
||||
struct core_info_by_chip_name info;
|
||||
enum cpuinfo_vendor vendor;
|
||||
enum cpuinfo_uarch uarch;
|
||||
|
||||
#if CPUINFO_ARCH_ARM
|
||||
bool has_vfpv4 = false;
|
||||
cpuinfo_arm_decode_vendor_uarch(midr, has_vfpv4, &vendor, &uarch);
|
||||
#else
|
||||
cpuinfo_arm_decode_vendor_uarch(midr, &vendor, &uarch);
|
||||
#endif
|
||||
|
||||
info.vendor = vendor;
|
||||
info.uarch = uarch;
|
||||
info.frequency = frequency;
|
||||
return info;
|
||||
}
|
||||
|
||||
static struct woa_chip_info* get_system_info_from_registry(void) {
|
||||
wchar_t* text_buffer = NULL;
|
||||
LPCWSTR cpu0_subkey = L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
|
||||
LPCWSTR chip_name_value = L"ProcessorNameString";
|
||||
LPCWSTR chip_midr_value = L"CP 4000";
|
||||
LPCWSTR chip_mhz_value = L"~MHz";
|
||||
struct woa_chip_info* chip_info = NULL;
|
||||
|
||||
HANDLE heap = GetProcessHeap();
|
||||
|
||||
/* Read processor model name from registry and find in the hard-coded
|
||||
* list. */
|
||||
text_buffer = read_registry(cpu0_subkey, chip_name_value);
|
||||
if (text_buffer == NULL) {
|
||||
cpuinfo_log_error("Registry read error");
|
||||
cpuinfo_log_error("Registry read error for processor name");
|
||||
return NULL;
|
||||
}
|
||||
for (uint32_t i = 0; i < (uint32_t)woa_chip_name_last; i++) {
|
||||
size_t compare_length = wcsnlen(woa_chips[i].chip_name_string, CPUINFO_PACKAGE_NAME_MAX);
|
||||
int compare_result = wcsncmp(text_buffer, woa_chips[i].chip_name_string, compare_length);
|
||||
if (compare_result == 0) {
|
||||
chip_info = woa_chips + i;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* https://developer.arm.com/documentation/100442/0100/register-descriptions/aarch32-system-registers/midr--main-id-register
|
||||
* Regedit for MIDR :
|
||||
*HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0\CP 4000
|
||||
*/
|
||||
uint64_t midr_qword = (uint32_t)read_registry_qword(cpu0_subkey, chip_midr_value);
|
||||
if (midr_qword == 0) {
|
||||
cpuinfo_log_error("Registry read error for MIDR value");
|
||||
return NULL;
|
||||
}
|
||||
// MIDR is only 32 bits, so we need to cast it to uint32_t
|
||||
uint32_t midr_value = (uint32_t)midr_qword;
|
||||
|
||||
/* Read the frequency from the registry
|
||||
* The value is in MHz, so we need to convert it to Hz */
|
||||
uint64_t frequency_mhz = read_registry_dword(cpu0_subkey, chip_mhz_value);
|
||||
if (frequency_mhz == 0) {
|
||||
cpuinfo_log_error("Registry read error for frequency value");
|
||||
return NULL;
|
||||
}
|
||||
// Convert MHz to Hz
|
||||
uint64_t frequency_hz = frequency_mhz * 1000000;
|
||||
|
||||
// Allocate chip_info before using it.
|
||||
chip_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct woa_chip_info));
|
||||
if (chip_info == NULL) {
|
||||
/* No match was found, so print a warning and assign the unknown
|
||||
* case. */
|
||||
cpuinfo_log_error(
|
||||
"Unknown chip model name '%ls'.\nPlease add new Windows on Arm SoC/chip support to arm/windows/init.c!",
|
||||
text_buffer);
|
||||
} else {
|
||||
cpuinfo_log_debug("detected chip model name: %s", chip_info->chip_name_string);
|
||||
cpuinfo_log_error("Heap allocation error for chip_info");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HeapFree(heap, 0, text_buffer);
|
||||
// set chip_info fields
|
||||
chip_info->chip_name_string = wcsndup(text_buffer, CPUINFO_PACKAGE_NAME_MAX - 1);
|
||||
chip_info->uarchs[0] = get_core_info_from_midr(midr_value, frequency_hz);
|
||||
|
||||
cpuinfo_log_debug("detected chip model name: %ls", chip_info->chip_name_string);
|
||||
|
||||
return chip_info;
|
||||
}
|
||||
|
||||
@@ -216,4 +219,4 @@ static void set_cpuinfo_isa_fields(void) {
|
||||
cpuinfo_isa.pmull = crypto;
|
||||
|
||||
cpuinfo_isa.crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0;
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,6 @@
|
||||
/* Efficiency class = 0 means little core, while 1 means big core for now. */
|
||||
#define MAX_WOA_VALID_EFFICIENCY_CLASSES 2
|
||||
|
||||
/* List of known and supported Windows on Arm SoCs/chips. */
|
||||
enum woa_chip_name {
|
||||
woa_chip_name_microsoft_sq_1 = 0,
|
||||
woa_chip_name_microsoft_sq_2 = 1,
|
||||
woa_chip_name_microsoft_sq_3 = 2,
|
||||
woa_chip_name_microsoft_sq_3_devkit = 3,
|
||||
woa_chip_name_ampere_altra = 4,
|
||||
woa_chip_name_unknown = 5,
|
||||
woa_chip_name_last = woa_chip_name_unknown
|
||||
};
|
||||
|
||||
/* Topology information hard-coded by SoC/chip name */
|
||||
struct core_info_by_chip_name {
|
||||
enum cpuinfo_vendor vendor;
|
||||
@@ -26,14 +15,7 @@ struct core_info_by_chip_name {
|
||||
*/
|
||||
struct woa_chip_info {
|
||||
wchar_t* chip_name_string;
|
||||
enum woa_chip_name chip_name;
|
||||
struct core_info_by_chip_name uarchs[MAX_WOA_VALID_EFFICIENCY_CLASSES];
|
||||
};
|
||||
|
||||
bool get_core_uarch_for_efficiency(
|
||||
enum woa_chip_name chip,
|
||||
BYTE EfficiencyClass,
|
||||
enum cpuinfo_uarch* uarch,
|
||||
uint64_t* frequency);
|
||||
|
||||
bool cpu_info_init_by_logical_sys_info(const struct woa_chip_info* chip_info, enum cpuinfo_vendor vendor);
|
||||
|
||||
11
3rdparty/cpuinfo/src/x86/isa.c
vendored
11
3rdparty/cpuinfo/src/x86/isa.c
vendored
@@ -46,6 +46,8 @@ struct cpuinfo_x86_isa cpuinfo_x86_detect_isa(
|
||||
(max_base_index >= 7) ? cpuidex(7, 0) : (struct cpuid_regs){0, 0, 0, 0};
|
||||
const struct cpuid_regs structured_feature_info1 =
|
||||
(max_base_index >= 7) ? cpuidex(7, 1) : (struct cpuid_regs){0, 0, 0, 0};
|
||||
const struct cpuid_regs structured_feature_info2 =
|
||||
(max_base_index >= 7) ? cpuidex(0x24, 0) : (struct cpuid_regs){0, 0, 0, 0};
|
||||
|
||||
const uint32_t processor_capacity_info_index = UINT32_C(0x80000008);
|
||||
const struct cpuid_regs processor_capacity_info = (max_extended_index >= processor_capacity_info_index)
|
||||
@@ -430,10 +432,17 @@ struct cpuinfo_x86_isa cpuinfo_x86_detect_isa(
|
||||
isa.avx512f = avx512_regs && !!(structured_feature_info0.ebx & UINT32_C(0x00010000));
|
||||
|
||||
/*
|
||||
* AVX 10.1 instructions:
|
||||
* AVX 10.1 instructions: avx 10 isa supported.
|
||||
* - Intel: edx[bit 19] in structured feature info (ecx = 1).
|
||||
*/
|
||||
isa.avx10_1 = avx512_regs && !!(structured_feature_info1.edx & UINT32_C(0x00080000));
|
||||
|
||||
/*
|
||||
* AVX 10.2 instructions: avx 10 version information.
|
||||
* - Intel: ebx[bits 0-7] in structured features info (eax = 24 ecx = 0).
|
||||
*/
|
||||
isa.avx10_2 = ((structured_feature_info2.ebx & UINT32_C(0x000000FF)) >= 2) && isa.avx10_1;
|
||||
|
||||
/*
|
||||
* AVX512PF instructions:
|
||||
* - Intel: ebx[bit 26] in structured feature info (ecx = 0).
|
||||
|
||||
5
3rdparty/cpuinfo/src/x86/linux/cpuinfo.c
vendored
5
3rdparty/cpuinfo/src/x86/linux/cpuinfo.c
vendored
@@ -83,8 +83,9 @@ struct proc_cpuinfo_parser_state {
|
||||
static bool parse_line(
|
||||
const char* line_start,
|
||||
const char* line_end,
|
||||
struct proc_cpuinfo_parser_state state[restrict static 1],
|
||||
void* context,
|
||||
uint64_t line_number) {
|
||||
struct proc_cpuinfo_parser_state* restrict state = context;
|
||||
/* Empty line. Skip. */
|
||||
if (line_start == line_end) {
|
||||
return true;
|
||||
@@ -215,5 +216,5 @@ bool cpuinfo_x86_linux_parse_proc_cpuinfo(
|
||||
.processors = processors,
|
||||
};
|
||||
return cpuinfo_linux_parse_multiline_file(
|
||||
"/proc/cpuinfo", BUFFER_SIZE, (cpuinfo_line_callback)parse_line, &state);
|
||||
"/proc/cpuinfo", BUFFER_SIZE, parse_line, &state);
|
||||
}
|
||||
|
||||
31
3rdparty/d3d12memalloc/CHANGELOG.md
vendored
31
3rdparty/d3d12memalloc/CHANGELOG.md
vendored
@@ -1,3 +1,34 @@
|
||||
# 3.0.1 (2025-05-08)
|
||||
|
||||
- Fixed macros `D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS`, `D3D12MA_RECOMMENDED_POOL_FLAGS` (#73).
|
||||
|
||||
# 3.0.0 (2025-05-05)
|
||||
|
||||
It has been a long time since the previous official release, so hopefully everyone has been using the latest code from "master" branch, which is always maintained in a good state, not the old version. For completeness, here is the list of changes since v2.0.1. The major version number has changed, so there are some compatibility-breaking changes, but the basic API stays the same and is mostly backward-compatible.
|
||||
|
||||
- Added helper structs: `CALLOCATION_DESC`, `CPOOL_DESC`, `CVIRTUAL_BLOCK_DESC`, `CVIRTUAL_ALLOCATION_DESC`.
|
||||
- Added macros: `D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS`, `D3D12MA_RECOMMENDED_HEAP_FLAGS`, `D3D12MA_RECOMMENDED_POOL_FLAGS`.
|
||||
- Added functions: `Allocator::CreateResource3`, `CreateAliasingResource2`.
|
||||
- They support parameters: `D3D12_BARRIER_LAYOUT InitialLayout`, `const DXGI_FORMAT* pCastableFormats`.
|
||||
- They require recent DirectX 12 Agility SDK. To use them, `ID3D12Device10` must be available.
|
||||
To use non-empty list of castable formats, `ID3D12Device12` must be available.
|
||||
- Added support for GPU Upload Heaps (`D3D12_HEAP_TYPE_GPU_UPLOAD`).
|
||||
- Requires recent DirectX 12 Agility SDK. Support on the user's machine is available only when supported by the motherboard, GPU, drivers, and enabled as "Resizable BAR" in UEFI settings. It can be queried using new `Allocator::IsGPUUploadHeapSupported` function.
|
||||
- `TotalStatistics::HeapType` array was extended from 4 to 5 elements.
|
||||
- Added missing function `Allocator::CreateAliasingResource1`.
|
||||
- Added `POOL_DESC::ResidencyPriority` member.
|
||||
- Removed `Allocation::WasZeroInitialized` function. It wasn't fully implemented anyway.
|
||||
- Added `POOL_FLAG_ALWAYS_COMMITTED`.
|
||||
- Added a heuristic that prefers creating small buffers as committed to save memory.
|
||||
- It is enabled by default. It can be disabled by new flag `ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED`.
|
||||
- Macro `D3D12MA_OPTIONS16_SUPPORTED` is no longer exposed in the header or Cmake script.
|
||||
It is defined automatically based on the Agility SDK version.
|
||||
- Added macro `D3D12MA_DEBUG_LOG`, which can be used to log unfreed allocations.
|
||||
- Many improvements in the documentation, including new chapters: "Frequently asked questions", "Optimal resource allocation".
|
||||
- Countless fixes and improvements, including performance optimizations, compatibility with various compilers, tests.
|
||||
- Major changes in the Cmake script.
|
||||
- Fixes in "GpuMemDumpVis.py" script.
|
||||
|
||||
# 2.0.1 (2022-04-05)
|
||||
|
||||
A maintenance release with some bug fixes and improvements. There are no changes in the library API.
|
||||
|
||||
2
3rdparty/d3d12memalloc/LICENSE.txt
vendored
2
3rdparty/d3d12memalloc/LICENSE.txt
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2019-2024 Advanced Micro Devices, Inc. All rights reserved.
|
||||
Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
9
3rdparty/d3d12memalloc/README.md
vendored
9
3rdparty/d3d12memalloc/README.md
vendored
@@ -10,10 +10,6 @@ Easy to integrate memory allocation library for Direct3D 12.
|
||||
|
||||
**Product page:** [D3D12 Memory Allocator on GPUOpen](https://gpuopen.com/gaming-product/d3d12-memory-allocator/)
|
||||
|
||||
**Build status:**
|
||||
|
||||
Windows: [](https://ci.appveyor.com/project/adam-sawicki-amd/d3d12memoryallocator)
|
||||
|
||||
[](http://isitmaintained.com/project/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator "Average time to resolve an issue")
|
||||
|
||||
# Problem
|
||||
@@ -91,7 +87,7 @@ With this one function call:
|
||||
|
||||
# Binaries
|
||||
|
||||
The release comes with precompiled binary executable for "D3D12Sample" application which contains test suite. It is compiled using Visual Studio 2019, so it requires appropriate libraries to work, including "MSVCP140.dll", "VCRUNTIME140.dll", "VCRUNTIME140_1.dll". If its launch fails with error message telling about those files missing, please download and install [Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads), "x64" version.
|
||||
The release comes with precompiled binary executable for "D3D12Sample" application which contains test suite. It is compiled using Visual Studio 2022, so it requires appropriate libraries to work, including "MSVCP140.dll", "VCRUNTIME140.dll", "VCRUNTIME140_1.dll". If its launch fails with error message telling about those files missing, please download and install [Microsoft Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170), "X64" version.
|
||||
|
||||
# Copyright notice
|
||||
|
||||
@@ -113,7 +109,8 @@ For more information see [NOTICES.txt](NOTICES.txt).
|
||||
|
||||
- **[Qt Project](https://github.com/qt)**
|
||||
- **[Ghost of Tsushima: Director's Cut PC](https://www.youtube.com/watch?v=cPKBDbCYctc&t=698s)** - Information avaliable in 11:38 of credits
|
||||
- **[Godot Engine](https://github.com/godotengine/godot/)** - multi-platform 2D and 3D game engine. License: MIT.
|
||||
- **[The Forge](https://github.com/ConfettiFX/The-Forge)** - cross-platform rendering framework. Apache License 2.0.
|
||||
- **[Wicked Engine<img src="https://github.com/turanszkij/WickedEngine/blob/master/Content/logo_small.png" width="28px" align="center"/>](https://github.com/turanszkij/WickedEngine)** - 3D engine with modern graphics
|
||||
- **[Wicked Engine](https://github.com/turanszkij/WickedEngine)** - 3D engine with modern graphics
|
||||
|
||||
[Some other projects on GitHub](https://github.com/search?q=D3D12MemAlloc.h&type=Code) and some game development studios that use DX12 in their games.
|
||||
|
||||
1062
3rdparty/d3d12memalloc/include/D3D12MemAlloc.h
vendored
1062
3rdparty/d3d12memalloc/include/D3D12MemAlloc.h
vendored
File diff suppressed because it is too large
Load Diff
467
3rdparty/d3d12memalloc/src/D3D12MemAlloc.cpp
vendored
467
3rdparty/d3d12memalloc/src/D3D12MemAlloc.cpp
vendored
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2019-2024 Advanced Micro Devices, Inc. All rights reserved.
|
||||
// Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -33,6 +33,13 @@
|
||||
#include <shared_mutex>
|
||||
#endif
|
||||
|
||||
// Includes needed for MinGW - see #71.
|
||||
#ifndef _MSC_VER
|
||||
#include <guiddef.h>
|
||||
// guiddef.h must be included first.
|
||||
#include <dxguids.h>
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -42,6 +49,14 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _D3D12MA_CONFIGURATION
|
||||
|
||||
#if !defined(D3D12MA_CPP20)
|
||||
#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20
|
||||
#define D3D12MA_CPP20 1
|
||||
#else
|
||||
#define D3D12MA_CPP20 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if !defined(WINVER) || WINVER < 0x0600
|
||||
#error Required at least WinAPI version supporting: client = Windows Vista, server = Windows Server 2008.
|
||||
@@ -64,6 +79,10 @@
|
||||
#define D3D12MA_ASSERT(cond) assert(cond)
|
||||
#endif
|
||||
|
||||
#if D3D12MA_CPP20
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
// Assert that will be called very often, like inside data structures e.g. operator[].
|
||||
// Making it non-empty can make program slow.
|
||||
#ifndef D3D12MA_HEAVY_ASSERT
|
||||
@@ -107,6 +126,14 @@ especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs.
|
||||
#define D3D12MA_DEFAULT_BLOCK_SIZE (64ull * 1024 * 1024)
|
||||
#endif
|
||||
|
||||
#ifndef D3D12MA_OPTIONS16_SUPPORTED
|
||||
#if D3D12_SDK_VERSION >= 610
|
||||
#define D3D12MA_OPTIONS16_SUPPORTED 1
|
||||
#else
|
||||
#define D3D12MA_OPTIONS16_SUPPORTED 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef D3D12MA_DEBUG_LOG
|
||||
#define D3D12MA_DEBUG_LOG(format, ...)
|
||||
/*
|
||||
@@ -128,10 +155,6 @@ especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs.
|
||||
|
||||
#define D3D12MA_IID_PPV_ARGS(ppType) __uuidof(**(ppType)), reinterpret_cast<void**>(ppType)
|
||||
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
#define D3D12MA_CREATE_NOT_ZEROED_AVAILABLE 1
|
||||
#endif
|
||||
|
||||
namespace D3D12MA
|
||||
{
|
||||
static constexpr UINT HEAP_TYPE_COUNT = 5;
|
||||
@@ -292,6 +315,10 @@ static UINT8 BitScanLSB(UINT64 mask)
|
||||
if (_BitScanForward64(&pos, mask))
|
||||
return static_cast<UINT8>(pos);
|
||||
return UINT8_MAX;
|
||||
#elif D3D12MA_CPP20
|
||||
if (mask != 0)
|
||||
return static_cast<uint8_t>(std::countr_zero(mask));
|
||||
return UINT8_MAX;
|
||||
#elif defined __GNUC__ || defined __clang__
|
||||
return static_cast<UINT8>(__builtin_ffsll(mask)) - 1U;
|
||||
#else
|
||||
@@ -314,6 +341,10 @@ static UINT8 BitScanLSB(UINT32 mask)
|
||||
if (_BitScanForward(&pos, mask))
|
||||
return static_cast<UINT8>(pos);
|
||||
return UINT8_MAX;
|
||||
#elif D3D12MA_CPP20
|
||||
if (mask != 0)
|
||||
return static_cast<uint8_t>(std::countr_zero(mask));
|
||||
return UINT8_MAX;
|
||||
#elif defined __GNUC__ || defined __clang__
|
||||
return static_cast<UINT8>(__builtin_ffs(mask)) - 1U;
|
||||
#else
|
||||
@@ -336,6 +367,9 @@ static UINT8 BitScanMSB(UINT64 mask)
|
||||
unsigned long pos;
|
||||
if (_BitScanReverse64(&pos, mask))
|
||||
return static_cast<UINT8>(pos);
|
||||
#elif D3D12MA_CPP20
|
||||
if (mask != 0)
|
||||
return 63 - static_cast<uint8_t>(std::countl_zero(mask));
|
||||
#elif defined __GNUC__ || defined __clang__
|
||||
if (mask)
|
||||
return 63 - static_cast<UINT8>(__builtin_clzll(mask));
|
||||
@@ -358,6 +392,9 @@ static UINT8 BitScanMSB(UINT32 mask)
|
||||
unsigned long pos;
|
||||
if (_BitScanReverse(&pos, mask))
|
||||
return static_cast<UINT8>(pos);
|
||||
#elif D3D12MA_CPP20
|
||||
if (mask != 0)
|
||||
return 31 - static_cast<uint8_t>(std::countl_zero(mask));
|
||||
#elif defined __GNUC__ || defined __clang__
|
||||
if (mask)
|
||||
return 31 - static_cast<UINT8>(__builtin_clz(mask));
|
||||
@@ -2791,7 +2828,7 @@ class AllocationObjectAllocator
|
||||
D3D12MA_CLASS_NO_COPY(AllocationObjectAllocator);
|
||||
public:
|
||||
AllocationObjectAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, bool useMutex)
|
||||
: m_Allocator(allocationCallbacks, 1024), m_UseMutex(useMutex) {}
|
||||
: m_UseMutex(useMutex), m_Allocator(allocationCallbacks, 1024) {}
|
||||
|
||||
template<typename... Types>
|
||||
Allocation* Allocate(Types... args);
|
||||
@@ -2982,7 +3019,7 @@ void BlockMetadata::DebugLogAllocation(UINT64 offset, UINT64 size, void* private
|
||||
LPCWSTR name = allocation->GetName();
|
||||
|
||||
D3D12MA_DEBUG_LOG(L"UNFREED ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p; Name: %s",
|
||||
offset, size, privateData, name ? name : L"D3D12MA_Empty");
|
||||
offset, size, privateData, name ? name : L"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5369,8 +5406,8 @@ struct CREATE_RESOURCE_PARAMS
|
||||
{
|
||||
CREATE_RESOURCE_PARAMS() = delete;
|
||||
CREATE_RESOURCE_PARAMS(
|
||||
const D3D12_RESOURCE_DESC* pResourceDesc,
|
||||
D3D12_RESOURCE_STATES InitialResourceState,
|
||||
const D3D12_RESOURCE_DESC* pResourceDesc,
|
||||
D3D12_RESOURCE_STATES InitialResourceState,
|
||||
const D3D12_CLEAR_VALUE* pOptimizedClearValue)
|
||||
: Variant(VARIANT_WITH_STATE)
|
||||
, pResourceDesc(pResourceDesc)
|
||||
@@ -5380,8 +5417,8 @@ struct CREATE_RESOURCE_PARAMS
|
||||
}
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
CREATE_RESOURCE_PARAMS(
|
||||
const D3D12_RESOURCE_DESC1* pResourceDesc,
|
||||
D3D12_RESOURCE_STATES InitialResourceState,
|
||||
const D3D12_RESOURCE_DESC1* pResourceDesc,
|
||||
D3D12_RESOURCE_STATES InitialResourceState,
|
||||
const D3D12_CLEAR_VALUE* pOptimizedClearValue)
|
||||
: Variant(VARIANT_WITH_STATE_AND_DESC1)
|
||||
, pResourceDesc1(pResourceDesc)
|
||||
@@ -5396,7 +5433,7 @@ struct CREATE_RESOURCE_PARAMS
|
||||
D3D12_BARRIER_LAYOUT InitialLayout,
|
||||
const D3D12_CLEAR_VALUE* pOptimizedClearValue,
|
||||
UINT32 NumCastableFormats,
|
||||
DXGI_FORMAT* pCastableFormats)
|
||||
const DXGI_FORMAT* pCastableFormats)
|
||||
: Variant(VARIANT_WITH_LAYOUT)
|
||||
, pResourceDesc1(pResourceDesc)
|
||||
, InitialLayout(InitialLayout)
|
||||
@@ -5466,7 +5503,7 @@ struct CREATE_RESOURCE_PARAMS
|
||||
D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
|
||||
return NumCastableFormats;
|
||||
}
|
||||
DXGI_FORMAT* GetCastableFormats() const
|
||||
const DXGI_FORMAT* GetCastableFormats() const
|
||||
{
|
||||
D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
|
||||
return pCastableFormats;
|
||||
@@ -5491,7 +5528,7 @@ private:
|
||||
const D3D12_CLEAR_VALUE* pOptimizedClearValue;
|
||||
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
|
||||
UINT32 NumCastableFormats;
|
||||
DXGI_FORMAT* pCastableFormats;
|
||||
const DXGI_FORMAT* pCastableFormats;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -5541,6 +5578,7 @@ public:
|
||||
UINT64 size,
|
||||
UINT64 alignment,
|
||||
const ALLOCATION_DESC& allocDesc,
|
||||
bool committedAllowed,
|
||||
size_t allocationCount,
|
||||
Allocation** pAllocations);
|
||||
|
||||
@@ -5551,6 +5589,7 @@ public:
|
||||
UINT64 alignment,
|
||||
const ALLOCATION_DESC& allocDesc,
|
||||
const CREATE_RESOURCE_PARAMS& createParams,
|
||||
bool committedAllowed,
|
||||
Allocation** ppAllocation,
|
||||
REFIID riidResource,
|
||||
void** ppvResource);
|
||||
@@ -5601,6 +5640,7 @@ private:
|
||||
UINT64 size,
|
||||
UINT64 alignment,
|
||||
const ALLOCATION_DESC& allocDesc,
|
||||
bool committedAllowed,
|
||||
Allocation** pAllocation);
|
||||
|
||||
HRESULT AllocateFromBlock(
|
||||
@@ -5706,29 +5746,31 @@ HRESULT CurrentBudgetData::UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex)
|
||||
DXGI_QUERY_VIDEO_MEMORY_INFO infoLocal = {};
|
||||
DXGI_QUERY_VIDEO_MEMORY_INFO infoNonLocal = {};
|
||||
const HRESULT hrLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &infoLocal);
|
||||
if (FAILED(hrLocal))
|
||||
{
|
||||
return hrLocal;
|
||||
}
|
||||
const HRESULT hrNonLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &infoNonLocal);
|
||||
if (FAILED(hrNonLocal))
|
||||
{
|
||||
return hrNonLocal;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hrLocal) || SUCCEEDED(hrNonLocal))
|
||||
{
|
||||
MutexLockWrite lockWrite(m_BudgetMutex, useMutex);
|
||||
|
||||
if (SUCCEEDED(hrLocal))
|
||||
{
|
||||
m_D3D12Usage[0] = infoLocal.CurrentUsage;
|
||||
m_D3D12Budget[0] = infoLocal.Budget;
|
||||
}
|
||||
if (SUCCEEDED(hrNonLocal))
|
||||
{
|
||||
m_D3D12Usage[1] = infoNonLocal.CurrentUsage;
|
||||
m_D3D12Budget[1] = infoNonLocal.Budget;
|
||||
}
|
||||
m_D3D12Usage[0] = infoLocal.CurrentUsage;
|
||||
m_D3D12Budget[0] = infoLocal.Budget;
|
||||
|
||||
m_D3D12Usage[1] = infoNonLocal.CurrentUsage;
|
||||
m_D3D12Budget[1] = infoNonLocal.Budget;
|
||||
|
||||
m_BlockBytesAtD3D12Fetch[0] = m_BlockBytes[0];
|
||||
m_BlockBytesAtD3D12Fetch[1] = m_BlockBytes[1];
|
||||
m_OperationsSinceBudgetFetch = 0;
|
||||
}
|
||||
|
||||
return FAILED(hrLocal) ? hrLocal : hrNonLocal;
|
||||
return S_OK;
|
||||
}
|
||||
#endif // #if D3D12MA_DXGI_1_4
|
||||
|
||||
@@ -5847,6 +5889,7 @@ public:
|
||||
|
||||
AllocatorPimpl* GetAllocator() const { return m_Allocator; }
|
||||
const POOL_DESC& GetDesc() const { return m_Desc; }
|
||||
bool AlwaysCommitted() const { return (m_Desc.Flags & POOL_FLAG_ALWAYS_COMMITTED) != 0; }
|
||||
bool SupportsCommittedAllocations() const { return m_Desc.BlockSize == 0; }
|
||||
LPCWSTR GetName() const { return m_Name; }
|
||||
|
||||
@@ -5903,6 +5946,12 @@ public:
|
||||
#endif
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
ID3D12Device8* GetDevice8() const { return m_Device8; }
|
||||
#endif
|
||||
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
|
||||
ID3D12Device10* GetDevice10() const { return m_Device10; }
|
||||
#endif
|
||||
#ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
ID3D12Device12* GetDevice12() const { return m_Device12; }
|
||||
#endif
|
||||
// Shortcut for "Allocation Callbacks", because this function is called so often.
|
||||
const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; }
|
||||
@@ -6011,6 +6060,9 @@ private:
|
||||
#endif
|
||||
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
|
||||
ID3D12Device10* m_Device10 = NULL; // AddRef, optional
|
||||
#endif
|
||||
#ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
ID3D12Device12* m_Device12 = NULL; // AddRef, optional
|
||||
#endif
|
||||
IDXGIAdapter* m_Adapter; // AddRef
|
||||
#if D3D12MA_DXGI_1_4
|
||||
@@ -6071,12 +6123,26 @@ private:
|
||||
HRESULT UpdateD3D12Budget();
|
||||
|
||||
D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const;
|
||||
HRESULT GetResourceAllocationInfoMiddle(D3D12_RESOURCE_DESC& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const;
|
||||
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const;
|
||||
D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo2Native(const D3D12_RESOURCE_DESC1& resourceDesc) const;
|
||||
HRESULT GetResourceAllocationInfoMiddle(D3D12_RESOURCE_DESC1& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const;
|
||||
#endif
|
||||
|
||||
#ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo3Native(const D3D12_RESOURCE_DESC1& resourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats) const;
|
||||
#endif
|
||||
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const;
|
||||
HRESULT GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const;
|
||||
|
||||
bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size);
|
||||
|
||||
@@ -6148,6 +6214,10 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
|
||||
m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device10));
|
||||
#endif
|
||||
|
||||
#ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device12));
|
||||
#endif
|
||||
|
||||
HRESULT hr = m_Adapter->GetDesc(&m_AdapterDesc);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
@@ -6163,9 +6233,6 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
|
||||
m_D3D12Options.ResourceHeapTier = (D3D12MA_FORCE_RESOURCE_HEAP_TIER);
|
||||
#endif
|
||||
|
||||
// You must define this macro to like `#define D3D12MA_OPTIONS16_SUPPORTED 1` to enable GPU Upload Heaps!
|
||||
// Unfortunately there is no way to programmatically check if the included <d3d12.h> defines D3D12_FEATURE_DATA_D3D12_OPTIONS16 or not.
|
||||
// Main interfaces have respective macros like __ID3D12Device4_INTERFACE_DEFINED__, but structures like this do not.
|
||||
#if D3D12MA_OPTIONS16_SUPPORTED
|
||||
{
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16 = {};
|
||||
@@ -6175,7 +6242,7 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
|
||||
m_GPUUploadHeapSupported = options16.GPUUploadHeapSupported;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // #if D3D12MA_OPTIONS16_SUPPORTED
|
||||
|
||||
hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &m_D3D12Architecture, sizeof(m_D3D12Architecture));
|
||||
if (FAILED(hr))
|
||||
@@ -6223,6 +6290,9 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
|
||||
|
||||
AllocatorPimpl::~AllocatorPimpl()
|
||||
{
|
||||
#ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
SAFE_RELEASE(m_Device12);
|
||||
#endif
|
||||
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
|
||||
SAFE_RELEASE(m_Device10);
|
||||
#endif
|
||||
@@ -6319,12 +6389,15 @@ HRESULT AllocatorPimpl::CreatePlacedResourceWrap(
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
// Microsoft defined pCastableFormats parameter as pointer to non-const and only fixed it in later Agility SDK,
|
||||
// thus we need const_cast.
|
||||
return m_Device10->CreatePlacedResource2(pHeap, HeapOffset,
|
||||
createParams.GetResourceDesc1(), createParams.GetInitialLayout(),
|
||||
createParams.GetOptimizedClearValue(), createParams.GetNumCastableFormats(),
|
||||
createParams.GetCastableFormats(), riidResource, ppvResource);
|
||||
} else
|
||||
const_cast<DXGI_FORMAT*>(createParams.GetCastableFormats()), riidResource, ppvResource);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
|
||||
{
|
||||
@@ -6335,21 +6408,19 @@ HRESULT AllocatorPimpl::CreatePlacedResourceWrap(
|
||||
return m_Device8->CreatePlacedResource1(pHeap, HeapOffset,
|
||||
createParams.GetResourceDesc1(), createParams.GetInitialResourceState(),
|
||||
createParams.GetOptimizedClearValue(), riidResource, ppvResource);
|
||||
} else
|
||||
}
|
||||
#endif
|
||||
|
||||
if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
|
||||
{
|
||||
return m_Device->CreatePlacedResource(pHeap, HeapOffset,
|
||||
createParams.GetResourceDesc(), createParams.GetInitialResourceState(),
|
||||
createParams.GetOptimizedClearValue(), riidResource, ppvResource);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D12MA_ASSERT(0);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
D3D12MA_ASSERT(0);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT AllocatorPimpl::CreateResource(
|
||||
const ALLOCATION_DESC* pAllocDesc,
|
||||
@@ -6366,6 +6437,7 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
*ppvResource = NULL;
|
||||
}
|
||||
|
||||
HRESULT hr = E_NOINTERFACE;
|
||||
CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
|
||||
D3D12_RESOURCE_DESC finalResourceDesc;
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
@@ -6376,45 +6448,49 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
{
|
||||
finalResourceDesc = *createParams.GetResourceDesc();
|
||||
finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
|
||||
resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo);
|
||||
}
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
|
||||
{
|
||||
if (!m_Device8)
|
||||
if (m_Device8 != NULL)
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo);
|
||||
}
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
|
||||
}
|
||||
#endif
|
||||
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
|
||||
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
|
||||
{
|
||||
if (!m_Device10)
|
||||
if (m_Device10 != NULL)
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1,
|
||||
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo);
|
||||
}
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
D3D12MA_ASSERT(0);
|
||||
return E_INVALIDARG;
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));
|
||||
// We've seen UINT64_MAX returned when the call to GetResourceAllocationInfo was invalid.
|
||||
D3D12MA_ASSERT(resAllocInfo.SizeInBytes != UINT64_MAX);
|
||||
D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);
|
||||
|
||||
BlockVector* blockVector = NULL;
|
||||
CommittedAllocationParameters committedAllocationParams = {};
|
||||
bool preferCommitted = false;
|
||||
|
||||
HRESULT hr;
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
if (createParams.Variant >= CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
|
||||
{
|
||||
@@ -6445,7 +6521,7 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
if (blockVector != NULL)
|
||||
{
|
||||
hr = blockVector->CreateResource(resAllocInfo.SizeInBytes, resAllocInfo.Alignment,
|
||||
*pAllocDesc, finalCreateParams,
|
||||
*pAllocDesc, finalCreateParams, committedAllocationParams.IsValid(),
|
||||
ppAllocation, riidResource, ppvResource);
|
||||
if (SUCCEEDED(hr))
|
||||
return hr;
|
||||
@@ -6488,7 +6564,7 @@ HRESULT AllocatorPimpl::AllocateMemory(
|
||||
if (blockVector != NULL)
|
||||
{
|
||||
hr = blockVector->Allocate(pAllocInfo->SizeInBytes, pAllocInfo->Alignment,
|
||||
*pAllocDesc, 1, (Allocation**)ppAllocation);
|
||||
*pAllocDesc, committedAllocationParams.IsValid(), 1, (Allocation**)ppAllocation);
|
||||
if (SUCCEEDED(hr))
|
||||
return hr;
|
||||
}
|
||||
@@ -6510,6 +6586,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
|
||||
{
|
||||
*ppvResource = NULL;
|
||||
|
||||
HRESULT hr = E_NOINTERFACE;
|
||||
CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
|
||||
D3D12_RESOURCE_DESC finalResourceDesc;
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
@@ -6520,37 +6597,40 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
|
||||
{
|
||||
finalResourceDesc = *createParams.GetResourceDesc();
|
||||
finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
|
||||
resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo);
|
||||
}
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
|
||||
{
|
||||
if (!m_Device8)
|
||||
if (m_Device8 != NULL)
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo);
|
||||
}
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
|
||||
}
|
||||
#endif
|
||||
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
|
||||
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
|
||||
{
|
||||
if (!m_Device10)
|
||||
if (m_Device10 != NULL)
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1,
|
||||
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo);
|
||||
}
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
D3D12MA_ASSERT(0);
|
||||
return E_INVALIDARG;
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));
|
||||
D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);
|
||||
|
||||
@@ -6773,42 +6853,41 @@ void AllocatorPimpl::GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget
|
||||
outLocalBudget ? &outLocalBudget->BudgetBytes : NULL,
|
||||
outNonLocalBudget ? &outNonLocalBudget->UsageBytes : NULL,
|
||||
outNonLocalBudget ? &outNonLocalBudget->BudgetBytes : NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (SUCCEEDED(UpdateD3D12Budget()))
|
||||
{
|
||||
UpdateD3D12Budget();
|
||||
GetBudget(outLocalBudget, outNonLocalBudget); // Recursion
|
||||
GetBudget(outLocalBudget, outNonLocalBudget); // Recursion.
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
// Fallback path - manual calculation, not real budget.
|
||||
if (outLocalBudget)
|
||||
{
|
||||
if (outLocalBudget)
|
||||
{
|
||||
outLocalBudget->UsageBytes = outLocalBudget->Stats.BlockBytes;
|
||||
outLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY) * 8 / 10; // 80% heuristics.
|
||||
}
|
||||
if (outNonLocalBudget)
|
||||
{
|
||||
outNonLocalBudget->UsageBytes = outNonLocalBudget->Stats.BlockBytes;
|
||||
outNonLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY) * 8 / 10; // 80% heuristics.
|
||||
}
|
||||
outLocalBudget->UsageBytes = outLocalBudget->Stats.BlockBytes;
|
||||
outLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY) * 8 / 10; // 80% heuristics.
|
||||
}
|
||||
if (outNonLocalBudget)
|
||||
{
|
||||
outNonLocalBudget->UsageBytes = outNonLocalBudget->Stats.BlockBytes;
|
||||
outNonLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY) * 8 / 10; // 80% heuristics.
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType)
|
||||
{
|
||||
switch (heapType)
|
||||
const bool isLocal = StandardHeapTypeToMemorySegmentGroup(heapType) ==
|
||||
DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
|
||||
if (isLocal)
|
||||
{
|
||||
case D3D12_HEAP_TYPE_DEFAULT:
|
||||
case D3D12_HEAP_TYPE_GPU_UPLOAD_COPY:
|
||||
GetBudget(&outBudget, NULL);
|
||||
break;
|
||||
case D3D12_HEAP_TYPE_UPLOAD:
|
||||
case D3D12_HEAP_TYPE_READBACK:
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBudget(NULL, &outBudget);
|
||||
break;
|
||||
default: D3D12MA_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7248,12 +7327,15 @@ HRESULT AllocatorPimpl::AllocateCommittedResource(
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
// Microsoft defined pCastableFormats parameter as pointer to non-const and only fixed it in later Agility SDK,
|
||||
// thus we need const_cast.
|
||||
hr = m_Device10->CreateCommittedResource3(
|
||||
&committedAllocParams.m_HeapProperties,
|
||||
committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
|
||||
createParams.GetResourceDesc1(), createParams.GetInitialLayout(),
|
||||
createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession,
|
||||
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(),
|
||||
createParams.GetNumCastableFormats(), const_cast<DXGI_FORMAT*>(createParams.GetCastableFormats()),
|
||||
D3D12MA_IID_PPV_ARGS(&res));
|
||||
} else
|
||||
#endif
|
||||
@@ -7396,8 +7478,8 @@ HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, U
|
||||
outCommittedAllocationParams = CommittedAllocationParameters();
|
||||
outPreferCommitted = false;
|
||||
|
||||
D3D12MA_ASSERT((allocDesc.HeapType != D3D12_HEAP_TYPE_GPU_UPLOAD_COPY || IsGPUUploadHeapSupported()) &&
|
||||
"Trying to allocate from D3D12_HEAP_TYPE_GPU_UPLOAD while GPUUploadHeapSupported == FALSE or D3D12MA_OPTIONS16_SUPPORTED macro was not defined when compiling D3D12MA library.");
|
||||
if (allocDesc.HeapType == D3D12_HEAP_TYPE_GPU_UPLOAD_COPY && !IsGPUUploadHeapSupported())
|
||||
return E_NOTIMPL;
|
||||
|
||||
bool msaaAlwaysCommitted;
|
||||
if (allocDesc.CustomPool != NULL)
|
||||
@@ -7405,7 +7487,8 @@ HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, U
|
||||
PoolPimpl* const pool = allocDesc.CustomPool->m_Pimpl;
|
||||
|
||||
msaaAlwaysCommitted = pool->GetBlockVector()->DeniesMsaaTextures();
|
||||
outBlockVector = pool->GetBlockVector();
|
||||
if(!pool->AlwaysCommitted())
|
||||
outBlockVector = pool->GetBlockVector();
|
||||
|
||||
const auto& desc = pool->GetDesc();
|
||||
outCommittedAllocationParams.m_ProtectedSession = desc.pProtectedSession;
|
||||
@@ -7444,12 +7527,6 @@ HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, U
|
||||
outPreferCommitted = true;
|
||||
}
|
||||
}
|
||||
|
||||
const D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
|
||||
if (outBlockVector != NULL && extraHeapFlags != 0)
|
||||
{
|
||||
outBlockVector = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((allocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0 ||
|
||||
@@ -7479,12 +7556,7 @@ UINT AllocatorPimpl::CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, Reso
|
||||
D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
|
||||
|
||||
#if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
|
||||
// If allocator was created with ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED, also ignore
|
||||
// D3D12_HEAP_FLAG_CREATE_NOT_ZEROED.
|
||||
if(m_DefaultPoolsNotZeroed)
|
||||
{
|
||||
extraHeapFlags &= ~D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
||||
}
|
||||
extraHeapFlags &= ~D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
||||
#endif
|
||||
|
||||
if (extraHeapFlags != 0)
|
||||
@@ -7603,7 +7675,7 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(c
|
||||
}
|
||||
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const
|
||||
D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo2Native(const D3D12_RESOURCE_DESC1& resourceDesc) const
|
||||
{
|
||||
D3D12MA_ASSERT(m_Device8 != NULL);
|
||||
D3D12_RESOURCE_ALLOCATION_INFO1 info1Unused;
|
||||
@@ -7619,8 +7691,71 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(c
|
||||
}
|
||||
#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
|
||||
#ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo3Native(const D3D12_RESOURCE_DESC1& resourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats) const
|
||||
{
|
||||
D3D12MA_ASSERT(m_Device12 != NULL);
|
||||
D3D12_RESOURCE_ALLOCATION_INFO1 info1Unused;
|
||||
|
||||
// This is how new D3D12 headers define GetResourceAllocationInfo function -
|
||||
// different signature depending on these macros.
|
||||
#if defined(_MSC_VER) || !defined(_WIN32)
|
||||
return m_Device12->GetResourceAllocationInfo3(0, 1, &resourceDesc,
|
||||
&NumCastableFormats, &pCastableFormats, &info1Unused);
|
||||
#else
|
||||
D3D12_RESOURCE_ALLOCATION_INFO retVal;
|
||||
return *m_Device12->GetResourceAllocationInfo3(&retVal, 0, 1, &resourceDesc,
|
||||
&NumCastableFormats, &pCastableFormats, &info1Unused);
|
||||
#endif
|
||||
}
|
||||
#endif // #ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
|
||||
HRESULT AllocatorPimpl::GetResourceAllocationInfoMiddle(
|
||||
D3D12_RESOURCE_DESC& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const
|
||||
{
|
||||
if (NumCastableFormats > 0)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
outAllocInfo = GetResourceAllocationInfoNative(inOutResourceDesc);
|
||||
return outAllocInfo.SizeInBytes != UINT64_MAX ? S_OK : E_INVALIDARG;
|
||||
}
|
||||
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
|
||||
HRESULT AllocatorPimpl::GetResourceAllocationInfoMiddle(
|
||||
D3D12_RESOURCE_DESC1& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const
|
||||
{
|
||||
if (NumCastableFormats > 0)
|
||||
{
|
||||
#ifdef __ID3D12Device12_INTERFACE_DEFINED__
|
||||
if (m_Device12 != NULL)
|
||||
{
|
||||
outAllocInfo = GetResourceAllocationInfo3Native(inOutResourceDesc, NumCastableFormats, pCastableFormats);
|
||||
return outAllocInfo.SizeInBytes != UINT64_MAX ? S_OK : E_INVALIDARG;
|
||||
}
|
||||
#else
|
||||
return E_NOTIMPL;
|
||||
#endif
|
||||
}
|
||||
|
||||
outAllocInfo = GetResourceAllocationInfo2Native(inOutResourceDesc);
|
||||
return outAllocInfo.SizeInBytes != UINT64_MAX ? S_OK : E_INVALIDARG;
|
||||
}
|
||||
|
||||
#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const
|
||||
HRESULT AllocatorPimpl::GetResourceAllocationInfo(
|
||||
D3D12_RESOURCE_DESC_T& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const
|
||||
{
|
||||
#ifdef __ID3D12Device1_INTERFACE_DEFINED__
|
||||
/* Optional optimization: Microsoft documentation says:
|
||||
@@ -7634,12 +7769,15 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_R
|
||||
if (inOutResourceDesc.Alignment == 0 &&
|
||||
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
||||
{
|
||||
return {
|
||||
outAllocInfo = {
|
||||
AlignUp<UINT64>(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes
|
||||
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT }; // Alignment
|
||||
return S_OK;
|
||||
}
|
||||
#endif // #ifdef __ID3D12Device1_INTERFACE_DEFINED__
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
|
||||
if (inOutResourceDesc.Alignment == 0 &&
|
||||
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
|
||||
@@ -7657,17 +7795,19 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_R
|
||||
D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :
|
||||
D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
|
||||
inOutResourceDesc.Alignment = smallAlignmentToTry;
|
||||
const D3D12_RESOURCE_ALLOCATION_INFO smallAllocInfo = GetResourceAllocationInfoNative(inOutResourceDesc);
|
||||
hr = GetResourceAllocationInfoMiddle(
|
||||
inOutResourceDesc, NumCastableFormats, pCastableFormats, outAllocInfo);
|
||||
// Check if alignment requested has been granted.
|
||||
if (smallAllocInfo.Alignment == smallAlignmentToTry)
|
||||
if (SUCCEEDED(hr) && outAllocInfo.Alignment == smallAlignmentToTry)
|
||||
{
|
||||
return smallAllocInfo;
|
||||
return S_OK;
|
||||
}
|
||||
inOutResourceDesc.Alignment = 0; // Restore original
|
||||
}
|
||||
#endif // #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
|
||||
|
||||
return GetResourceAllocationInfoNative(inOutResourceDesc);
|
||||
return GetResourceAllocationInfoMiddle(
|
||||
inOutResourceDesc, NumCastableFormats, pCastableFormats, outAllocInfo);
|
||||
}
|
||||
|
||||
bool AllocatorPimpl::NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size)
|
||||
@@ -7988,6 +8128,7 @@ HRESULT BlockVector::Allocate(
|
||||
UINT64 size,
|
||||
UINT64 alignment,
|
||||
const ALLOCATION_DESC& allocDesc,
|
||||
bool committedAllowed,
|
||||
size_t allocationCount,
|
||||
Allocation** pAllocations)
|
||||
{
|
||||
@@ -8002,6 +8143,7 @@ HRESULT BlockVector::Allocate(
|
||||
size,
|
||||
alignment,
|
||||
allocDesc,
|
||||
committedAllowed,
|
||||
pAllocations + allocIndex);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
@@ -8090,40 +8232,43 @@ HRESULT BlockVector::CreateResource(
|
||||
UINT64 alignment,
|
||||
const ALLOCATION_DESC& allocDesc,
|
||||
const CREATE_RESOURCE_PARAMS& createParams,
|
||||
bool committedAllowed,
|
||||
Allocation** ppAllocation,
|
||||
REFIID riidResource,
|
||||
void** ppvResource)
|
||||
{
|
||||
HRESULT hr = Allocate(size, alignment, allocDesc, 1, ppAllocation);
|
||||
HRESULT hr = Allocate(size, alignment, allocDesc, committedAllowed, 1, ppAllocation);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
ID3D12Resource* res = NULL;
|
||||
hr = m_hAllocator->CreatePlacedResourceWrap(
|
||||
(*ppAllocation)->m_Placed.block->GetHeap(),
|
||||
(*ppAllocation)->GetOffset(),
|
||||
createParams,
|
||||
D3D12MA_IID_PPV_ARGS(&res));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ID3D12Resource* res = NULL;
|
||||
hr = m_hAllocator->CreatePlacedResourceWrap(
|
||||
(*ppAllocation)->m_Placed.block->GetHeap(),
|
||||
(*ppAllocation)->GetOffset(),
|
||||
createParams,
|
||||
D3D12MA_IID_PPV_ARGS(&res));
|
||||
if (ppvResource != NULL)
|
||||
{
|
||||
hr = res->QueryInterface(riidResource, ppvResource);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (ppvResource != NULL)
|
||||
{
|
||||
hr = res->QueryInterface(riidResource, ppvResource);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
(*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc());
|
||||
}
|
||||
else
|
||||
{
|
||||
res->Release();
|
||||
SAFE_RELEASE(*ppAllocation);
|
||||
}
|
||||
(*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc());
|
||||
}
|
||||
else
|
||||
{
|
||||
res->Release();
|
||||
SAFE_RELEASE(*ppAllocation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SAFE_RELEASE(*ppAllocation);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
@@ -8241,6 +8386,7 @@ HRESULT BlockVector::AllocatePage(
|
||||
UINT64 size,
|
||||
UINT64 alignment,
|
||||
const ALLOCATION_DESC& allocDesc,
|
||||
bool committedAllowed,
|
||||
Allocation** pAllocation)
|
||||
{
|
||||
// Early reject: requested allocation size is larger that maximum block size for this block vector.
|
||||
@@ -8257,13 +8403,19 @@ HRESULT BlockVector::AllocatePage(
|
||||
freeMemory = (budget.UsageBytes < budget.BudgetBytes) ? (budget.BudgetBytes - budget.UsageBytes) : 0;
|
||||
}
|
||||
|
||||
const bool canCreateNewBlock =
|
||||
const bool canExceedFreeMemory = !committedAllowed;
|
||||
|
||||
bool canCreateNewBlock =
|
||||
((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) &&
|
||||
(m_Blocks.size() < m_MaxBlockCount) &&
|
||||
// Even if we don't have to stay within budget with this allocation, when the
|
||||
// budget would be exceeded, we don't want to allocate new blocks, but always
|
||||
// create resources as committed.
|
||||
freeMemory >= size;
|
||||
(m_Blocks.size() < m_MaxBlockCount);
|
||||
|
||||
// Even if we don't have to stay within budget with this allocation, when the
|
||||
// budget would be exceeded, we don't want to allocate new blocks, but always
|
||||
// create resources as committed.
|
||||
if (freeMemory < size && !canExceedFreeMemory)
|
||||
{
|
||||
canCreateNewBlock = false;
|
||||
}
|
||||
|
||||
// 1. Search existing allocations
|
||||
{
|
||||
@@ -8313,26 +8465,29 @@ HRESULT BlockVector::AllocatePage(
|
||||
}
|
||||
}
|
||||
|
||||
size_t newBlockIndex = 0;
|
||||
HRESULT hr = newBlockSize <= freeMemory ?
|
||||
CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
|
||||
size_t newBlockIndex = SIZE_MAX;
|
||||
HRESULT hr = E_OUTOFMEMORY;
|
||||
if (newBlockSize <= freeMemory || canExceedFreeMemory)
|
||||
{
|
||||
hr = CreateBlock(newBlockSize, &newBlockIndex);
|
||||
}
|
||||
// Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
|
||||
if (!m_ExplicitBlockSize)
|
||||
{
|
||||
while (FAILED(hr) && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
|
||||
{
|
||||
const UINT64 smallerNewBlockSize = newBlockSize / 2;
|
||||
if (smallerNewBlockSize >= size)
|
||||
{
|
||||
newBlockSize = smallerNewBlockSize;
|
||||
++newBlockSizeShift;
|
||||
hr = newBlockSize <= freeMemory ?
|
||||
CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
|
||||
}
|
||||
else
|
||||
if (smallerNewBlockSize < size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
newBlockSize = smallerNewBlockSize;
|
||||
++newBlockSizeShift;
|
||||
if (newBlockSize <= freeMemory || canExceedFreeMemory)
|
||||
{
|
||||
hr = CreateBlock(newBlockSize, &newBlockIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9509,6 +9664,8 @@ HRESULT Pool::BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, Defragment
|
||||
// Check for support
|
||||
if (m_Pimpl->GetBlockVector()->GetAlgorithm() & POOL_FLAG_ALGORITHM_LINEAR)
|
||||
return E_NOINTERFACE;
|
||||
if(m_Pimpl->AlwaysCommitted())
|
||||
return E_NOINTERFACE;
|
||||
|
||||
AllocatorPimpl* allocator = m_Pimpl->GetAllocator();
|
||||
*ppContext = D3D12MA_NEW(allocator->GetAllocs(), DefragmentationContext)(allocator, *pDesc, m_Pimpl->GetBlockVector());
|
||||
@@ -9612,7 +9769,7 @@ HRESULT Allocator::CreateResource3(
|
||||
D3D12_BARRIER_LAYOUT InitialLayout,
|
||||
const D3D12_CLEAR_VALUE* pOptimizedClearValue,
|
||||
UINT32 NumCastableFormats,
|
||||
DXGI_FORMAT* pCastableFormats,
|
||||
const DXGI_FORMAT* pCastableFormats,
|
||||
Allocation** ppAllocation,
|
||||
REFIID riidResource,
|
||||
void** ppvResource)
|
||||
@@ -9702,7 +9859,7 @@ HRESULT Allocator::CreateAliasingResource2(
|
||||
D3D12_BARRIER_LAYOUT InitialLayout,
|
||||
const D3D12_CLEAR_VALUE* pOptimizedClearValue,
|
||||
UINT32 NumCastableFormats,
|
||||
DXGI_FORMAT* pCastableFormats,
|
||||
const DXGI_FORMAT* pCastableFormats,
|
||||
REFIID riidResource,
|
||||
void** ppvResource)
|
||||
{
|
||||
@@ -9732,6 +9889,12 @@ HRESULT Allocator::CreatePool(
|
||||
D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreatePool.");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if ((pPoolDesc->Flags & POOL_FLAG_ALWAYS_COMMITTED) != 0 &&
|
||||
(pPoolDesc->BlockSize != 0 || pPoolDesc->MinBlockCount > 0))
|
||||
{
|
||||
D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreatePool while POOL_FLAG_ALWAYS_COMMITTED is specified.");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (!m_Pimpl->HeapFlagsFulfillResourceHeapTier(pPoolDesc->HeapFlags))
|
||||
{
|
||||
D3D12MA_ASSERT(0 && "Invalid pPoolDesc->HeapFlags passed to Allocator::CreatePool. Did you forget to handle ResourceHeapTier=1?");
|
||||
|
||||
1
3rdparty/fast_float/CONTRIBUTORS
vendored
1
3rdparty/fast_float/CONTRIBUTORS
vendored
@@ -8,3 +8,4 @@ Lénárd Szolnoki
|
||||
Jan Pharago
|
||||
Maya Warrier
|
||||
Taha Khokhar
|
||||
Anders Dalvander
|
||||
|
||||
489
3rdparty/fast_float/README.md
vendored
489
3rdparty/fast_float/README.md
vendored
@@ -1,160 +1,233 @@
|
||||
|
||||
## fast_float number parsing library: 4x faster than strtod
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:fast_float)
|
||||
|
||||
[](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml)
|
||||
|
||||
The fast_float library provides fast header-only implementations for the C++ from_chars
|
||||
functions for `float` and `double` types as well as integer types. These functions convert ASCII strings representing decimal values (e.g., `1.3e10`) into binary types. We provide exact rounding (including
|
||||
round to even). In our experience, these `fast_float` functions many times faster than comparable number-parsing functions from existing C++ standard libraries.
|
||||
The fast_float library provides fast header-only implementations for the C++
|
||||
from_chars functions for `float` and `double` types as well as integer types.
|
||||
These functions convert ASCII strings representing decimal values (e.g.,
|
||||
`1.3e10`) into binary types. We provide exact rounding (including round to
|
||||
even). In our experience, these `fast_float` functions many times faster than
|
||||
comparable number-parsing functions from existing C++ standard libraries.
|
||||
|
||||
Specifically, `fast_float` provides the following two functions to parse floating-point numbers with a C++17-like syntax (the library itself only requires C++11):
|
||||
Specifically, `fast_float` provides the following two functions to parse
|
||||
floating-point numbers with a C++17-like syntax (the library itself only
|
||||
requires C++11):
|
||||
|
||||
```C++
|
||||
from_chars_result from_chars(const char* first, const char* last, float& value, ...);
|
||||
from_chars_result from_chars(const char* first, const char* last, double& value, ...);
|
||||
from_chars_result from_chars(char const *first, char const *last, float &value, ...);
|
||||
from_chars_result from_chars(char const *first, char const *last, double &value, ...);
|
||||
```
|
||||
|
||||
You can also parse integer types:
|
||||
|
||||
|
||||
|
||||
```C++
|
||||
from_chars_result from_chars(char const *first, char const *last, int &value, ...);
|
||||
from_chars_result from_chars(char const *first, char const *last, unsigned &value, ...);
|
||||
```
|
||||
|
||||
The return type (`from_chars_result`) is defined as the struct:
|
||||
|
||||
```C++
|
||||
struct from_chars_result {
|
||||
const char* ptr;
|
||||
std::errc ec;
|
||||
char const *ptr;
|
||||
std::errc ec;
|
||||
};
|
||||
```
|
||||
|
||||
It parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
|
||||
a locale-independent format equivalent to the C++17 from_chars function.
|
||||
The resulting floating-point value is the closest floating-point values (using either float or double),
|
||||
using the "round to even" convention for values that would otherwise fall right in-between two values.
|
||||
That is, we provide exact parsing according to the IEEE standard.
|
||||
It parses the character sequence `[first, last)` for a number. It parses
|
||||
floating-point numbers expecting a locale-independent format equivalent to the
|
||||
C++17 from_chars function. The resulting floating-point value is the closest
|
||||
floating-point values (using either `float` or `double`), using the "round to
|
||||
even" convention for values that would otherwise fall right in-between two
|
||||
values. That is, we provide exact parsing according to the IEEE standard.
|
||||
|
||||
Given a successful parse, the pointer (`ptr`) in the returned value is set to
|
||||
point right after the parsed number, and the `value` referenced is set to the
|
||||
parsed value. In case of error, the returned `ec` contains a representative
|
||||
error, otherwise the default (`std::errc()`) value is stored.
|
||||
|
||||
Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
|
||||
parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
|
||||
`ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
|
||||
|
||||
The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
|
||||
The implementation does not throw and does not allocate memory (e.g., with `new`
|
||||
or `malloc`).
|
||||
|
||||
It will parse infinity and nan values.
|
||||
|
||||
Example:
|
||||
|
||||
``` C++
|
||||
```C++
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "3.1416 xyz ";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
std::string input = "3.1416 xyz ";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result);
|
||||
if (answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
You can parse delimited numbers:
|
||||
|
||||
```C++
|
||||
const std::string input = "234532.3426362,7869234.9823,324562.645";
|
||||
std::string input = "234532.3426362,7869234.9823,324562.645";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) {
|
||||
auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result);
|
||||
if (answer.ec != std::errc()) {
|
||||
// check error
|
||||
}
|
||||
// we have result == 234532.3426362.
|
||||
if(answer.ptr[0] != ',') {
|
||||
if (answer.ptr[0] != ',') {
|
||||
// unexpected delimiter
|
||||
}
|
||||
answer = fast_float::from_chars(answer.ptr + 1, input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) {
|
||||
answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), result);
|
||||
if (answer.ec != std::errc()) {
|
||||
// check error
|
||||
}
|
||||
// we have result == 7869234.9823.
|
||||
if(answer.ptr[0] != ',') {
|
||||
if (answer.ptr[0] != ',') {
|
||||
// unexpected delimiter
|
||||
}
|
||||
answer = fast_float::from_chars(answer.ptr + 1, input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) {
|
||||
answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), result);
|
||||
if (answer.ec != std::errc()) {
|
||||
// check error
|
||||
}
|
||||
// we have result == 324562.645.
|
||||
```
|
||||
|
||||
Like the C++17 standard, the `fast_float::from_chars` functions take an optional
|
||||
last argument of the type `fast_float::chars_format`. It is a bitset value: we
|
||||
check whether `fmt & fast_float::chars_format::fixed` and `fmt &
|
||||
fast_float::chars_format::scientific` are set to determine whether we allow the
|
||||
fixed point and scientific notation respectively. The default is
|
||||
`fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
|
||||
The library seeks to follow the C++17 (see
|
||||
[28.2.3.(6.1)](https://eel.is/c++draft/charconv.from.chars#6.1)) specification.
|
||||
|
||||
Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
|
||||
the type `fast_float::chars_format`. It is a bitset value: we check whether
|
||||
`fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
|
||||
to determine whether we allow the fixed point and scientific notation respectively.
|
||||
The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
|
||||
The library seeks to follow the C++17 (see [20.19.3](http://eel.is/c++draft/charconv.from.chars).(7.1)) specification.
|
||||
* The `from_chars` function does not skip leading white-space characters.
|
||||
* [A leading `+` sign](https://en.cppreference.com/w/cpp/utility/from_chars) is forbidden.
|
||||
* It is generally impossible to represent a decimal value exactly as binary floating-point number (`float` and `double` types). We seek the nearest value. We round to an even mantissa when we are in-between two binary floating-point numbers.
|
||||
* The `from_chars` function does not skip leading white-space characters (unless
|
||||
`fast_float::chars_format::skip_white_space` is set).
|
||||
* [A leading `+` sign](https://en.cppreference.com/w/cpp/utility/from_chars) is
|
||||
forbidden (unless `fast_float::chars_format::allow_leading_plus` is set).
|
||||
* It is generally impossible to represent a decimal value exactly as binary
|
||||
floating-point number (`float` and `double` types). We seek the nearest value.
|
||||
We round to an even mantissa when we are in-between two binary floating-point
|
||||
numbers.
|
||||
|
||||
Furthermore, we have the following restrictions:
|
||||
* We only support `float` and `double` types at this time.
|
||||
|
||||
* We support `float` and `double`, but not `long double`. We also support
|
||||
fixed-width floating-point types such as `std::float64_t`, `std::float32_t`,
|
||||
`std::float16_t`, and `std::bfloat16_t`.
|
||||
* We only support the decimal format: we do not support hexadecimal strings.
|
||||
* For values that are either very large or very small (e.g., `1e9999`), we represent it using the infinity or negative infinity value and the returned `ec` is set to `std::errc::result_out_of_range`.
|
||||
* For values that are either very large or very small (e.g., `1e9999`), we
|
||||
represent it using the infinity or negative infinity value and the returned
|
||||
`ec` is set to `std::errc::result_out_of_range`.
|
||||
|
||||
We support Visual Studio, macOS, Linux, freeBSD. We support big and little endian. We support 32-bit and 64-bit systems.
|
||||
|
||||
We assume that the rounding mode is set to nearest (`std::fegetround() == FE_TONEAREST`).
|
||||
We support Visual Studio, macOS, Linux, freeBSD. We support big and little
|
||||
endian. We support 32-bit and 64-bit systems.
|
||||
|
||||
We assume that the rounding mode is set to nearest (`std::fegetround() ==
|
||||
FE_TONEAREST`).
|
||||
|
||||
## Integer types
|
||||
|
||||
You can also parse integer types using different bases (e.g., 2, 10, 16). The following code will
|
||||
print the number 22250738585072012 three times:
|
||||
|
||||
You can also parse integer types using different bases (e.g., 2, 10, 16). The
|
||||
following code will print the number 22250738585072012 three times:
|
||||
|
||||
```C++
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
uint64_t i;
|
||||
const char str[] = "22250738585072012";
|
||||
auto answer = fast_float::from_chars(str, str + strlen(str), i);
|
||||
std::string str = "22250738585072012";
|
||||
auto answer = fast_float::from_chars(str.data(), str.data() + str.size(), i);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "parsing failure\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "parsed the number "<< i << std::endl;
|
||||
std::cout << "parsed the number " << i << std::endl;
|
||||
|
||||
const char binstr[] = "1001111000011001110110111001001010110100111000110001100";
|
||||
std::string binstr = "1001111000011001110110111001001010110100111000110001100";
|
||||
|
||||
answer = fast_float::from_chars(binstr, binstr + strlen(binstr), i, 2);
|
||||
answer = fast_float::from_chars(binstr.data(), binstr.data() + binstr.size(), i, 2);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "parsing failure\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "parsed the number "<< i << std::endl;
|
||||
std::cout << "parsed the number " << i << std::endl;
|
||||
|
||||
std::string hexstr = "4f0cedc95a718c";
|
||||
|
||||
const char hexstr[] = "4f0cedc95a718c";
|
||||
|
||||
answer = fast_float::from_chars(hexstr, hexstr + strlen(hexstr), i, 16);
|
||||
answer = fast_float::from_chars(hexstr.data(), hexstr.data() + hexstr.size(), i, 16);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "parsing failure\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "parsed the number "<< i << std::endl;
|
||||
std::cout << "parsed the number " << i << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
## Behavior of result_out_of_range
|
||||
|
||||
When parsing floating-point values, the numbers can sometimes be too small
|
||||
(e.g., `1e-1000`) or too large (e.g., `1e1000`). The C language established the
|
||||
precedent that these small values are out of range. In such cases, it is
|
||||
customary to parse small values to zero and large values to infinity. That is
|
||||
the behaviour of the C language (e.g., `stdtod`). That is the behaviour followed
|
||||
by the fast_float library.
|
||||
|
||||
Specifically, we follow Jonathan Wakely's interpretation of the standard:
|
||||
|
||||
> In any case, the resulting value is one of at most two floating-point values
|
||||
> closest to the value of the string matching the pattern.
|
||||
|
||||
It is also the approach taken by the [Microsoft C++
|
||||
library](https://github.com/microsoft/STL/blob/62205ab155d093e71dd9588a78f02c5396c3c14b/tests/std/tests/P0067R5_charconv/test.cpp#L943-L946).
|
||||
|
||||
Hence, we have the following examples:
|
||||
|
||||
```cpp
|
||||
double result = -1;
|
||||
std::string str = "3e-1000";
|
||||
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
|
||||
// r.ec == std::errc::result_out_of_range
|
||||
// r.ptr == str.data() + 7
|
||||
// result == 0
|
||||
```
|
||||
|
||||
```cpp
|
||||
double result = -1;
|
||||
std::string str = "3e1000";
|
||||
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
|
||||
// r.ec == std::errc::result_out_of_range
|
||||
// r.ptr == str.data() + 6
|
||||
// result == std::numeric_limits<double>::infinity()
|
||||
```
|
||||
|
||||
Users who wish for the value to be left unmodified given
|
||||
`std::errc::result_out_of_range` may do so by adding two lines of code:
|
||||
|
||||
```cpp
|
||||
double old_result = result; // make copy
|
||||
auto r = fast_float::from_chars(start, end, result);
|
||||
if (r.ec == std::errc::result_out_of_range) { result = old_result; }
|
||||
```
|
||||
|
||||
## C++20: compile-time evaluation (constexpr)
|
||||
|
||||
In C++20, you may use `fast_float::from_chars` to parse strings
|
||||
at compile-time, as in the following example:
|
||||
In C++20, you may use `fast_float::from_chars` to parse strings at compile-time,
|
||||
as in the following example:
|
||||
|
||||
```C++
|
||||
// consteval forces compile-time evaluation of the function in C++20.
|
||||
consteval double parse(std::string_view input) {
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) { return -1.0; }
|
||||
auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result);
|
||||
if (answer.ec != std::errc()) { return -1.0; }
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -167,108 +240,107 @@ constexpr double constexptest() {
|
||||
|
||||
## C++23: Fixed width floating-point types
|
||||
|
||||
The library also supports fixed-width floating-point types such as `std::float32_t` and `std::float64_t`. E.g., you can write:
|
||||
The library also supports fixed-width floating-point types such as
|
||||
`std::float64_t`, `std::float32_t`, `std::float16_t`, and `std::bfloat16_t`.
|
||||
E.g., you can write:
|
||||
|
||||
```C++
|
||||
std::float32_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
``````
|
||||
|
||||
```
|
||||
|
||||
## Non-ASCII Inputs
|
||||
|
||||
We also support UTF-16 and UTF-32 inputs, as well as ASCII/UTF-8, as in the following example:
|
||||
We also support UTF-16 and UTF-32 inputs, as well as ASCII/UTF-8, as in the
|
||||
following example:
|
||||
|
||||
``` C++
|
||||
```C++
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::u16string input = u"3.1416 xyz ";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
std::u16string input = u"3.1416 xyz ";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result);
|
||||
if (answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced options: using commas as decimal separator, JSON and Fortran
|
||||
|
||||
## Advanced options: using commas as decimal separator, JSON and Fortran
|
||||
|
||||
The C++ standard stipulate that `from_chars` has to be locale-independent. In
|
||||
particular, the decimal separator has to be the period (`.`). However,
|
||||
some users still want to use the `fast_float` library with in a locale-dependent
|
||||
manner. Using a separate function called `from_chars_advanced`, we allow the users
|
||||
to pass a `parse_options` instance which contains a custom decimal separator (e.g.,
|
||||
the comma). You may use it as follows.
|
||||
particular, the decimal separator has to be the period (`.`). However, some
|
||||
users still want to use the `fast_float` library with in a locale-dependent
|
||||
manner. Using a separate function called `from_chars_advanced`, we allow the
|
||||
users to pass a `parse_options` instance which contains a custom decimal
|
||||
separator (e.g., the comma). You may use it as follows.
|
||||
|
||||
```C++
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "3,1416 xyz ";
|
||||
double result;
|
||||
fast_float::parse_options options{fast_float::chars_format::general, ','};
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data()+input.size(), result, options);
|
||||
if((answer.ec != std::errc()) || ((result != 3.1416))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
std::string input = "3,1416 xyz ";
|
||||
double result;
|
||||
fast_float::parse_options options{fast_float::chars_format::general, ','};
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options);
|
||||
if ((answer.ec != std::errc()) || ((result != 3.1416))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
You can also parse Fortran-like inputs:
|
||||
### You can also parse Fortran-like inputs
|
||||
|
||||
```C++
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "1d+4";
|
||||
double result;
|
||||
fast_float::parse_options options{ fast_float::chars_format::fortran };
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data()+input.size(), result, options);
|
||||
if((answer.ec != std::errc()) || ((result != 10000))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
std::string input = "1d+4";
|
||||
double result;
|
||||
fast_float::parse_options options{fast_float::chars_format::fortran};
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options);
|
||||
if ((answer.ec != std::errc()) || ((result != 10000))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
You may also enforce the JSON format ([RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-6)):
|
||||
|
||||
### You may also enforce the JSON format ([RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-6))
|
||||
|
||||
```C++
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "+.1"; // not valid
|
||||
double result;
|
||||
fast_float::parse_options options{ fast_float::chars_format::json };
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data()+input.size(), result, options);
|
||||
if(answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; }
|
||||
return EXIT_SUCCESS;
|
||||
std::string input = "+.1"; // not valid
|
||||
double result;
|
||||
fast_float::parse_options options{fast_float::chars_format::json};
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options);
|
||||
if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; }
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
By default the JSON format does not allow `inf`:
|
||||
|
||||
```C++
|
||||
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "inf"; // not valid in JSON
|
||||
double result;
|
||||
fast_float::parse_options options{ fast_float::chars_format::json };
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data()+input.size(), result, options);
|
||||
if(answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; }
|
||||
std::string input = "inf"; // not valid in JSON
|
||||
double result;
|
||||
fast_float::parse_options options{fast_float::chars_format::json};
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options);
|
||||
if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; }
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
You can allow it with a non-standard `json_or_infnan` variant:
|
||||
|
||||
```C++
|
||||
@@ -276,55 +348,77 @@ You can allow it with a non-standard `json_or_infnan` variant:
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::string input = "inf"; // not valid in JSON but we allow it with json_or_infnan
|
||||
double result;
|
||||
fast_float::parse_options options{ fast_float::chars_format::json_or_infnan };
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data()+input.size(), result, options);
|
||||
if(answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; return EXIT_FAILURE; }
|
||||
return EXIT_SUCCESS;
|
||||
std::string input = "inf"; // not valid in JSON but we allow it with json_or_infnan
|
||||
double result;
|
||||
fast_float::parse_options options{fast_float::chars_format::json_or_infnan};
|
||||
auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options);
|
||||
if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; return EXIT_FAILURE; }
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
``````
|
||||
```
|
||||
|
||||
## Relation With Other Work
|
||||
## Users and Related Work
|
||||
|
||||
The fast_float library is part of:
|
||||
|
||||
- GCC (as of version 12): the `from_chars` function in GCC relies on fast_float.
|
||||
- [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's web browser)
|
||||
* GCC (as of version 12): the `from_chars` function in GCC relies on fast_float,
|
||||
* [Chromium](https://github.com/Chromium/Chromium), the engine behind Google
|
||||
Chrome, Microsoft Edge, and Opera,
|
||||
* [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's
|
||||
web browser),
|
||||
* [DuckDB](https://duckdb.org),
|
||||
* [Redis](https://github.com/redis/redis) and [Valkey](https://github.com/valkey-io/valkey),
|
||||
* [Apache Arrow](https://github.com/apache/arrow/pull/8494) where it multiplied
|
||||
the number parsing speed by two or three times,
|
||||
* [Google Jsonnet](https://github.com/google/jsonnet),
|
||||
* [ClickHouse](https://github.com/ClickHouse/ClickHouse).
|
||||
|
||||
The fastfloat algorithm is part of the [LLVM standard
|
||||
libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba).
|
||||
There is a [derived implementation part of
|
||||
AdaCore](https://github.com/AdaCore/VSS).
|
||||
|
||||
The fastfloat algorithm is part of the [LLVM standard libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba).
|
||||
|
||||
There is a [derived implementation part of AdaCore](https://github.com/AdaCore/VSS).
|
||||
|
||||
|
||||
The fast_float library provides a performance similar to that of the [fast_double_parser](https://github.com/lemire/fast_double_parser) library but using an updated algorithm reworked from the ground up, and while offering an API more in line with the expectations of C++ programmers. The fast_double_parser library is part of the [Microsoft LightGBM machine-learning framework](https://github.com/microsoft/LightGBM).
|
||||
The fast_float library provides a performance similar to that of the
|
||||
[fast_double_parser](https://github.com/lemire/fast_double_parser) library but
|
||||
using an updated algorithm reworked from the ground up, and while offering an
|
||||
API more in line with the expectations of C++ programmers. The
|
||||
fast_double_parser library is part of the [Microsoft LightGBM machine-learning
|
||||
framework](https://github.com/microsoft/LightGBM).
|
||||
|
||||
## References
|
||||
|
||||
- Daniel Lemire, [Number Parsing at a Gigabyte per Second](https://arxiv.org/abs/2101.11408), Software: Practice and Experience 51 (8), 2021.
|
||||
- Noble Mushtak, Daniel Lemire, [Fast Number Parsing Without Fallback](https://arxiv.org/abs/2212.06644), Software: Practice and Experience 53 (7), 2023.
|
||||
* Daniel Lemire, [Number Parsing at a Gigabyte per
|
||||
Second](https://arxiv.org/abs/2101.11408), Software: Practice and Experience
|
||||
51 (8), 2021.
|
||||
* Noble Mushtak, Daniel Lemire, [Fast Number Parsing Without
|
||||
Fallback](https://arxiv.org/abs/2212.06644), Software: Practice and Experience
|
||||
53 (7), 2023.
|
||||
|
||||
## Other programming languages
|
||||
|
||||
- [There is an R binding](https://github.com/eddelbuettel/rcppfastfloat) called `rcppfastfloat`.
|
||||
- [There is a Rust port of the fast_float library](https://github.com/aldanor/fast-float-rust/) called `fast-float-rust`.
|
||||
- [There is a Java port of the fast_float library](https://github.com/wrandelshofer/FastDoubleParser) called `FastDoubleParser`. It used for important systems such as [Jackson](https://github.com/FasterXML/jackson-core).
|
||||
- [There is a C# port of the fast_float library](https://github.com/CarlVerret/csFastFloat) called `csFastFloat`.
|
||||
|
||||
|
||||
## Users
|
||||
|
||||
The fast_float library is used by [Apache Arrow](https://github.com/apache/arrow/pull/8494) where it multiplied the number parsing speed by two or three times. It is also used by [ClickHouse](https://github.com/ClickHouse/ClickHouse) and by [Google Jsonnet](https://github.com/google/jsonnet). It is part of GCC (as of GCC 12). It is part of WebKit (Safari).
|
||||
|
||||
* [There is an R binding](https://github.com/eddelbuettel/rcppfastfloat) called
|
||||
`rcppfastfloat`.
|
||||
* [There is a Rust port of the fast_float
|
||||
library](https://github.com/aldanor/fast-float-rust/) called
|
||||
`fast-float-rust`.
|
||||
* [There is a Java port of the fast_float
|
||||
library](https://github.com/wrandelshofer/FastDoubleParser) called
|
||||
`FastDoubleParser`. It used for important systems such as
|
||||
[Jackson](https://github.com/FasterXML/jackson-core).
|
||||
* [There is a C# port of the fast_float
|
||||
library](https://github.com/CarlVerret/csFastFloat) called `csFastFloat`.
|
||||
|
||||
## How fast is it?
|
||||
|
||||
It can parse random floating-point numbers at a speed of 1 GB/s on some systems. We find that it is often twice as fast as the best available competitor, and many times faster than many standard-library implementations.
|
||||
It can parse random floating-point numbers at a speed of 1 GB/s on some systems.
|
||||
We find that it is often twice as fast as the best available competitor, and
|
||||
many times faster than many standard-library implementations.
|
||||
|
||||
<img src="http://lemire.me/blog/wp-content/uploads/2020/11/fastfloat_speed.png" width="400">
|
||||
<img src="https://lemire.me/blog/wp-content/uploads/2020/11/fastfloat_speed.png"
|
||||
width="400" alt="fast_float is many times faster than many standard-library
|
||||
implementations">
|
||||
|
||||
```
|
||||
```bash
|
||||
$ ./build/benchmarks/benchmark
|
||||
# parsing random integers in the range [0,1)
|
||||
volume = 2.09808 MB
|
||||
@@ -335,75 +429,122 @@ abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfl
|
||||
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
||||
```
|
||||
|
||||
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
|
||||
|
||||
See the [Benchmarking](#benchmarking) section for instructions on how to run our benchmarks.
|
||||
|
||||
## Video
|
||||
|
||||
[](http://www.youtube.com/watch?v=AVXgvlMeIm4)<br />
|
||||
[](https://www.youtube.com/watch?v=AVXgvlMeIm4)
|
||||
|
||||
## Using as a CMake dependency
|
||||
|
||||
This library is header-only by design. The CMake file provides the `fast_float` target
|
||||
which is merely a pointer to the `include` directory.
|
||||
This library is header-only by design. The CMake file provides the `fast_float`
|
||||
target which is merely a pointer to the `include` directory.
|
||||
|
||||
If you drop the `fast_float` repository in your CMake project, you should be able to use
|
||||
it in this manner:
|
||||
If you drop the `fast_float` repository in your CMake project, you should be
|
||||
able to use it in this manner:
|
||||
|
||||
```cmake
|
||||
add_subdirectory(fast_float)
|
||||
target_link_libraries(myprogram PUBLIC fast_float)
|
||||
```
|
||||
|
||||
Or you may want to retrieve the dependency automatically if you have a sufficiently recent version of CMake (3.11 or better at least):
|
||||
Or you may want to retrieve the dependency automatically if you have a
|
||||
sufficiently recent version of CMake (3.11 or better at least):
|
||||
|
||||
```cmake
|
||||
FetchContent_Declare(
|
||||
fast_float
|
||||
GIT_REPOSITORY https://github.com/lemire/fast_float.git
|
||||
GIT_TAG tags/v1.1.2
|
||||
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
|
||||
GIT_TAG tags/v8.0.2
|
||||
GIT_SHALLOW TRUE)
|
||||
|
||||
FetchContent_MakeAvailable(fast_float)
|
||||
target_link_libraries(myprogram PUBLIC fast_float)
|
||||
|
||||
```
|
||||
|
||||
You should change the `GIT_TAG` line so that you recover the version you wish to use.
|
||||
You should change the `GIT_TAG` line so that you recover the version you wish to
|
||||
use.
|
||||
|
||||
You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so:
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME fast_float
|
||||
GITHUB_REPOSITORY "fastfloat/fast_float"
|
||||
GIT_TAG v8.0.2)
|
||||
```
|
||||
|
||||
## Using as single header
|
||||
|
||||
The script `script/amalgamate.py` may be used to generate a single header
|
||||
version of the library if so desired.
|
||||
Just run the script from the root directory of this repository.
|
||||
You can customize the license type and output file if desired as described in
|
||||
the command line help.
|
||||
version of the library if so desired. Just run the script from the root
|
||||
directory of this repository. You can customize the license type and output file
|
||||
if desired as described in the command line help.
|
||||
|
||||
You may directly download automatically generated single-header files:
|
||||
|
||||
https://github.com/fastfloat/fast_float/releases/download/v6.1.1/fast_float.h
|
||||
<https://github.com/fastfloat/fast_float/releases/download/v8.0.2/fast_float.h>
|
||||
|
||||
## RFC 7159
|
||||
## Benchmarking
|
||||
|
||||
If you need support for RFC 7159 (JSON standard), you may want to consider using the [fast_double_parser](https://github.com/lemire/fast_double_parser/) library instead.
|
||||
The project has its own benchmarks with realistic data inputs. Under Linux or macOS,
|
||||
you can use it as follows if your system supports C++17:
|
||||
|
||||
```
|
||||
cmake -B build -D FASTFLOAT_BENCHMARKS=ON
|
||||
cmake --build build
|
||||
./build/benchmarks/realbenchmark
|
||||
```
|
||||
|
||||
Importantly, by default, the benchmark is built in Release mode.
|
||||
|
||||
The instructions are similar under Windows.
|
||||
|
||||
Under Linux and macOS, it is recommended to run the benchmarks in a privileged manner to get access
|
||||
to hardware performance counters. You may be able to do so with the `sudo` command
|
||||
in some cases:
|
||||
|
||||
```
|
||||
sudo ./build/benchmarks/realbenchmark
|
||||
```
|
||||
|
||||
If you have a text file containing one number per line (`myfile.txt`), you can run a benchmark over it like so:
|
||||
```
|
||||
cmake -B build -D FASTFLOAT_BENCHMARKS=ON
|
||||
cmake --build build
|
||||
./build/benchmarks/realbenchmark myfile.txt
|
||||
```
|
||||
|
||||
|
||||
## Packages
|
||||
|
||||
* The fast_float library is part of the [Conan package
|
||||
manager](https://conan.io/center/recipes/fast_float).
|
||||
* It is part of the [brew package
|
||||
manager](https://formulae.brew.sh/formula/fast_float).
|
||||
* Some Linux distribution like Fedora include fast_float (e.g., as
|
||||
`fast_float-devel`).
|
||||
|
||||
## Credit
|
||||
|
||||
Though this work is inspired by many different people, this work benefited especially from exchanges with
|
||||
Michael Eisel, who motivated the original research with his key insights, and with Nigel Tao who provided
|
||||
invaluable feedback. Rémy Oudompheng first implemented a fast path we use in the case of long digits.
|
||||
Though this work is inspired by many different people, this work benefited
|
||||
especially from exchanges with Michael Eisel, who motivated the original
|
||||
research with his key insights, and with Nigel Tao who provided invaluable
|
||||
feedback. Rémy Oudompheng first implemented a fast path we use in the case of
|
||||
long digits.
|
||||
|
||||
The library includes code adapted from Google Wuffs (written by Nigel Tao) which was originally published
|
||||
under the Apache 2.0 license.
|
||||
The library includes code adapted from Google Wuffs (written by Nigel Tao) which
|
||||
was originally published under the Apache 2.0 license.
|
||||
|
||||
## License
|
||||
|
||||
<sup>
|
||||
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
||||
2.0</a> or <a href="LICENSE-MIT">MIT license</a> or <a href="LICENSE-BOOST">BOOST license</a> .
|
||||
2.0</a> or <a href="LICENSE-MIT">MIT license</a> or <a
|
||||
href="LICENSE-BOOST">BOOST license</a>.
|
||||
</sup>
|
||||
|
||||
<br>
|
||||
<br/>
|
||||
|
||||
<sub>
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
template <typename UC>
|
||||
fastfloat_really_inline constexpr bool has_simd_opt() {
|
||||
template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() {
|
||||
#ifdef FASTFLOAT_HAS_SIMD
|
||||
return std::is_same<UC, char16_t>::value;
|
||||
#else
|
||||
@@ -37,24 +36,20 @@ fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
|
||||
}
|
||||
|
||||
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
||||
return (val & 0xFF00000000000000) >> 56
|
||||
| (val & 0x00FF000000000000) >> 40
|
||||
| (val & 0x0000FF0000000000) >> 24
|
||||
| (val & 0x000000FF00000000) >> 8
|
||||
| (val & 0x00000000FF000000) << 8
|
||||
| (val & 0x0000000000FF0000) << 24
|
||||
| (val & 0x000000000000FF00) << 40
|
||||
| (val & 0x00000000000000FF) << 56;
|
||||
return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 |
|
||||
(val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 |
|
||||
(val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 |
|
||||
(val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56;
|
||||
}
|
||||
|
||||
// Read 8 UC into a u64. Truncates UC if not char.
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint64_t read8_to_u64(const UC *chars) {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
|
||||
read8_to_u64(UC const *chars) {
|
||||
if (cpp20_and_in_constexpr() || !std::is_same<UC, char>::value) {
|
||||
uint64_t val = 0;
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
val |= uint64_t(uint8_t(*chars)) << (i*8);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
val |= uint64_t(uint8_t(*chars)) << (i * 8);
|
||||
++chars;
|
||||
}
|
||||
return val;
|
||||
@@ -70,44 +65,41 @@ uint64_t read8_to_u64(const UC *chars) {
|
||||
|
||||
#ifdef FASTFLOAT_SSE2
|
||||
|
||||
fastfloat_really_inline
|
||||
uint64_t simd_read8_to_u64(const __m128i data) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
const __m128i packed = _mm_packus_epi16(data, data);
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
__m128i const packed = _mm_packus_epi16(data, data);
|
||||
#ifdef FASTFLOAT_64BIT
|
||||
return uint64_t(_mm_cvtsi128_si64(packed));
|
||||
#else
|
||||
uint64_t value;
|
||||
// Visual Studio + older versions of GCC don't support _mm_storeu_si64
|
||||
_mm_storel_epi64(reinterpret_cast<__m128i*>(&value), packed);
|
||||
_mm_storel_epi64(reinterpret_cast<__m128i *>(&value), packed);
|
||||
return value;
|
||||
#endif
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
}
|
||||
|
||||
fastfloat_really_inline
|
||||
uint64_t simd_read8_to_u64(const char16_t* chars) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
return simd_read8_to_u64(_mm_loadu_si128(reinterpret_cast<const __m128i*>(chars)));
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
return simd_read8_to_u64(
|
||||
_mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)));
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
}
|
||||
|
||||
#elif defined(FASTFLOAT_NEON)
|
||||
|
||||
|
||||
fastfloat_really_inline
|
||||
uint64_t simd_read8_to_u64(const uint16x8_t data) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const data) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
uint8x8_t utf8_packed = vmovn_u16(data);
|
||||
return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0);
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
}
|
||||
|
||||
fastfloat_really_inline
|
||||
uint64_t simd_read8_to_u64(const char16_t* chars) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
return simd_read8_to_u64(vld1q_u16(reinterpret_cast<const uint16_t*>(chars)));
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
return simd_read8_to_u64(
|
||||
vld1q_u16(reinterpret_cast<uint16_t const *>(chars)));
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
}
|
||||
|
||||
#endif // FASTFLOAT_SSE2
|
||||
@@ -119,101 +111,84 @@ template <typename UC>
|
||||
template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
|
||||
#endif
|
||||
// dummy for compile
|
||||
uint64_t simd_read8_to_u64(UC const*) {
|
||||
uint64_t simd_read8_to_u64(UC const *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void write_u64(uint8_t *chars, uint64_t val) {
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
*chars = uint8_t(val);
|
||||
val >>= 8;
|
||||
++chars;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
||||
// Need to read as-if the number was in little-endian order.
|
||||
val = byteswap(val);
|
||||
#endif
|
||||
::memcpy(chars, &val, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
// credit @aqrit
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
||||
const uint64_t mask = 0x000000FF000000FF;
|
||||
const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
|
||||
const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t
|
||||
parse_eight_digits_unrolled(uint64_t val) {
|
||||
uint64_t const mask = 0x000000FF000000FF;
|
||||
uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
|
||||
uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
|
||||
val -= 0x3030303030303030;
|
||||
val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
|
||||
val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
|
||||
return uint32_t(val);
|
||||
}
|
||||
|
||||
|
||||
// Call this if chars are definitely 8 digits.
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint32_t parse_eight_digits_unrolled(UC const * chars) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t
|
||||
parse_eight_digits_unrolled(UC const *chars) noexcept {
|
||||
if (cpp20_and_in_constexpr() || !has_simd_opt<UC>()) {
|
||||
return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay
|
||||
}
|
||||
return parse_eight_digits_unrolled(simd_read8_to_u64(chars));
|
||||
}
|
||||
|
||||
|
||||
// credit @aqrit
|
||||
fastfloat_really_inline constexpr bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
||||
fastfloat_really_inline constexpr bool
|
||||
is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
||||
return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
|
||||
0x8080808080808080));
|
||||
0x8080808080808080));
|
||||
}
|
||||
|
||||
|
||||
#ifdef FASTFLOAT_HAS_SIMD
|
||||
|
||||
// Call this if chars might not be 8 digits.
|
||||
// Using this style (instead of is_made_of_eight_digits_fast() then parse_eight_digits_unrolled())
|
||||
// ensures we don't load SIMD registers twice.
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool simd_parse_if_eight_digits_unrolled(const char16_t* chars, uint64_t& i) noexcept {
|
||||
// Using this style (instead of is_made_of_eight_digits_fast() then
|
||||
// parse_eight_digits_unrolled()) ensures we don't load SIMD registers twice.
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
|
||||
simd_parse_if_eight_digits_unrolled(char16_t const *chars,
|
||||
uint64_t &i) noexcept {
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef FASTFLOAT_SSE2
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
const __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i*>(chars));
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
__m128i const data =
|
||||
_mm_loadu_si128(reinterpret_cast<__m128i const *>(chars));
|
||||
|
||||
// (x - '0') <= 9
|
||||
// http://0x80.pl/articles/simd-parsing-int-sequences.html
|
||||
const __m128i t0 = _mm_add_epi16(data, _mm_set1_epi16(32720));
|
||||
const __m128i t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759));
|
||||
__m128i const t0 = _mm_add_epi16(data, _mm_set1_epi16(32720));
|
||||
__m128i const t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759));
|
||||
|
||||
if (_mm_movemask_epi8(t1) == 0) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
} else
|
||||
return false;
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
#elif defined(FASTFLOAT_NEON)
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
const uint16x8_t data = vld1q_u16(reinterpret_cast<const uint16_t*>(chars));
|
||||
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
uint16x8_t const data = vld1q_u16(reinterpret_cast<uint16_t const *>(chars));
|
||||
|
||||
// (x - '0') <= 9
|
||||
// http://0x80.pl/articles/simd-parsing-int-sequences.html
|
||||
const uint16x8_t t0 = vsubq_u16(data, vmovq_n_u16('0'));
|
||||
const uint16x8_t mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1));
|
||||
uint16x8_t const t0 = vsubq_u16(data, vmovq_n_u16('0'));
|
||||
uint16x8_t const mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1));
|
||||
|
||||
if (vminvq_u16(mask) == 0xFFFF) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
} else
|
||||
return false;
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
#else
|
||||
(void)chars; (void)i;
|
||||
(void)chars;
|
||||
(void)i;
|
||||
return false;
|
||||
#endif // FASTFLOAT_SSE2
|
||||
}
|
||||
@@ -227,79 +202,119 @@ template <typename UC>
|
||||
template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
|
||||
#endif
|
||||
// dummy for compile
|
||||
bool simd_parse_if_eight_digits_unrolled(UC const*, uint64_t&) {
|
||||
bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template <typename UC, FASTFLOAT_ENABLE_IF(!std::is_same<UC, char>::value) = 0>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void loop_parse_if_eight_digits(const UC*& p, const UC* const pend, uint64_t& i) {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
loop_parse_if_eight_digits(UC const *&p, UC const *const pend, uint64_t &i) {
|
||||
if (!has_simd_opt<UC>()) {
|
||||
return;
|
||||
}
|
||||
while ((std::distance(p, pend) >= 8) && simd_parse_if_eight_digits_unrolled(p, i)) { // in rare cases, this will overflow, but that's ok
|
||||
while ((std::distance(p, pend) >= 8) &&
|
||||
simd_parse_if_eight_digits_unrolled(
|
||||
p, i)) { // in rare cases, this will overflow, but that's ok
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void loop_parse_if_eight_digits(const char*& p, const char* const pend, uint64_t& i) {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
loop_parse_if_eight_digits(char const *&p, char const *const pend,
|
||||
uint64_t &i) {
|
||||
// optimizes better than parse_if_eight_digits_unrolled() for UC = char.
|
||||
while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(read8_to_u64(p))) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(read8_to_u64(p)); // in rare cases, this will overflow, but that's ok
|
||||
while ((std::distance(p, pend) >= 8) &&
|
||||
is_made_of_eight_digits_fast(read8_to_u64(p))) {
|
||||
i = i * 100000000 +
|
||||
parse_eight_digits_unrolled(read8_to_u64(
|
||||
p)); // in rare cases, this will overflow, but that's ok
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename UC>
|
||||
struct parsed_number_string_t {
|
||||
enum class parse_error {
|
||||
no_error,
|
||||
// [JSON-only] The minus sign must be followed by an integer.
|
||||
missing_integer_after_sign,
|
||||
// A sign must be followed by an integer or dot.
|
||||
missing_integer_or_dot_after_sign,
|
||||
// [JSON-only] The integer part must not have leading zeros.
|
||||
leading_zeros_in_integer_part,
|
||||
// [JSON-only] The integer part must have at least one digit.
|
||||
no_digits_in_integer_part,
|
||||
// [JSON-only] If there is a decimal point, there must be digits in the
|
||||
// fractional part.
|
||||
no_digits_in_fractional_part,
|
||||
// The mantissa must have at least one digit.
|
||||
no_digits_in_mantissa,
|
||||
// Scientific notation requires an exponential part.
|
||||
missing_exponential_part,
|
||||
};
|
||||
|
||||
template <typename UC> struct parsed_number_string_t {
|
||||
int64_t exponent{0};
|
||||
uint64_t mantissa{0};
|
||||
UC const * lastmatch{nullptr};
|
||||
UC const *lastmatch{nullptr};
|
||||
bool negative{false};
|
||||
bool valid{false};
|
||||
bool too_many_digits{false};
|
||||
// contains the range of the significant digits
|
||||
span<const UC> integer{}; // non-nullable
|
||||
span<const UC> fraction{}; // nullable
|
||||
span<UC const> integer{}; // non-nullable
|
||||
span<UC const> fraction{}; // nullable
|
||||
parse_error error{parse_error::no_error};
|
||||
};
|
||||
|
||||
using byte_span = span<const char>;
|
||||
using byte_span = span<char const>;
|
||||
using parsed_number_string = parsed_number_string_t<char>;
|
||||
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
|
||||
report_parse_error(UC const *p, parse_error error) {
|
||||
parsed_number_string_t<UC> answer;
|
||||
answer.valid = false;
|
||||
answer.lastmatch = p;
|
||||
answer.error = error;
|
||||
return answer;
|
||||
}
|
||||
|
||||
// Assuming that you use no more than 19 digits, this will
|
||||
// parse an ASCII string.
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept {
|
||||
chars_format const fmt = options.format;
|
||||
template <bool basic_json_fmt, typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
|
||||
parse_number_string(UC const *p, UC const *pend,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
UC const decimal_point = options.decimal_point;
|
||||
|
||||
parsed_number_string_t<UC> answer;
|
||||
answer.valid = false;
|
||||
answer.too_many_digits = false;
|
||||
// assume p < pend, so dereference without checks;
|
||||
answer.negative = (*p == UC('-'));
|
||||
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||
if ((*p == UC('-')) || (!(fmt & FASTFLOAT_JSONFMT) && *p == UC('+'))) {
|
||||
#else
|
||||
if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
#endif
|
||||
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
if ((*p == UC('-')) || (uint64_t(fmt & chars_format::allow_leading_plus) &&
|
||||
!basic_json_fmt && *p == UC('+'))) {
|
||||
++p;
|
||||
if (p == pend) {
|
||||
return answer;
|
||||
return report_parse_error<UC>(
|
||||
p, parse_error::missing_integer_or_dot_after_sign);
|
||||
}
|
||||
if (fmt & FASTFLOAT_JSONFMT) {
|
||||
FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
|
||||
if (!is_integer(*p)) { // a sign must be followed by an integer
|
||||
return answer;
|
||||
}
|
||||
} else {
|
||||
if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot
|
||||
return answer;
|
||||
return report_parse_error<UC>(p,
|
||||
parse_error::missing_integer_after_sign);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!is_integer(*p) &&
|
||||
(*p !=
|
||||
decimal_point)) { // a sign must be followed by an integer or the dot
|
||||
return report_parse_error<UC>(
|
||||
p, parse_error::missing_integer_or_dot_after_sign);
|
||||
}
|
||||
}
|
||||
}
|
||||
UC const * const start_digits = p;
|
||||
UC const *const start_digits = p;
|
||||
|
||||
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
||||
|
||||
@@ -307,24 +322,29 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
|
||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
||||
// multiplication
|
||||
i = 10 * i +
|
||||
uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later
|
||||
uint64_t(*p -
|
||||
UC('0')); // might overflow, we will handle the overflow later
|
||||
++p;
|
||||
}
|
||||
UC const * const end_of_integer_part = p;
|
||||
UC const *const end_of_integer_part = p;
|
||||
int64_t digit_count = int64_t(end_of_integer_part - start_digits);
|
||||
answer.integer = span<const UC>(start_digits, size_t(digit_count));
|
||||
if (fmt & FASTFLOAT_JSONFMT) {
|
||||
answer.integer = span<UC const>(start_digits, size_t(digit_count));
|
||||
FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
|
||||
// at least 1 digit in integer part, without leading zeros
|
||||
if (digit_count == 0 || (start_digits[0] == UC('0') && digit_count > 1)) {
|
||||
return answer;
|
||||
if (digit_count == 0) {
|
||||
return report_parse_error<UC>(p, parse_error::no_digits_in_integer_part);
|
||||
}
|
||||
if ((start_digits[0] == UC('0') && digit_count > 1)) {
|
||||
return report_parse_error<UC>(start_digits,
|
||||
parse_error::leading_zeros_in_integer_part);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t exponent = 0;
|
||||
const bool has_decimal_point = (p != pend) && (*p == decimal_point);
|
||||
bool const has_decimal_point = (p != pend) && (*p == decimal_point);
|
||||
if (has_decimal_point) {
|
||||
++p;
|
||||
UC const * before = p;
|
||||
UC const *before = p;
|
||||
// can occur at most twice without overflowing, but let it occur more, since
|
||||
// for integers with many digits, digit parsing is the primary bottleneck.
|
||||
loop_parse_if_eight_digits(p, pend, i);
|
||||
@@ -335,41 +355,45 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
|
||||
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
|
||||
}
|
||||
exponent = before - p;
|
||||
answer.fraction = span<const UC>(before, size_t(p - before));
|
||||
answer.fraction = span<UC const>(before, size_t(p - before));
|
||||
digit_count -= exponent;
|
||||
}
|
||||
if (fmt & FASTFLOAT_JSONFMT) {
|
||||
FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
|
||||
// at least 1 digit in fractional part
|
||||
if (has_decimal_point && exponent == 0) {
|
||||
return answer;
|
||||
return report_parse_error<UC>(p,
|
||||
parse_error::no_digits_in_fractional_part);
|
||||
}
|
||||
}
|
||||
else if (digit_count == 0) { // we must have encountered at least one integer!
|
||||
return answer;
|
||||
}
|
||||
int64_t exp_number = 0; // explicit exponential part
|
||||
if ( ((fmt & chars_format::scientific) &&
|
||||
(p != pend) &&
|
||||
((UC('e') == *p) || (UC('E') == *p)))
|
||||
||
|
||||
((fmt & FASTFLOAT_FORTRANFMT) &&
|
||||
(p != pend) &&
|
||||
((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || (UC('D') == *p)))) {
|
||||
UC const * location_of_e = p;
|
||||
if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || (UC('D') == *p)) {
|
||||
else if (digit_count == 0) { // we must have encountered at least one integer!
|
||||
return report_parse_error<UC>(p, parse_error::no_digits_in_mantissa);
|
||||
}
|
||||
int64_t exp_number = 0; // explicit exponential part
|
||||
if ((uint64_t(fmt & chars_format::scientific) && (p != pend) &&
|
||||
((UC('e') == *p) || (UC('E') == *p))) ||
|
||||
(uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) &&
|
||||
((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) ||
|
||||
(UC('D') == *p)))) {
|
||||
UC const *location_of_e = p;
|
||||
if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) ||
|
||||
(UC('D') == *p)) {
|
||||
++p;
|
||||
}
|
||||
bool neg_exp = false;
|
||||
if ((p != pend) && (UC('-') == *p)) {
|
||||
neg_exp = true;
|
||||
++p;
|
||||
} else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
||||
} else if ((p != pend) &&
|
||||
(UC('+') ==
|
||||
*p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
||||
++p;
|
||||
}
|
||||
if ((p == pend) || !is_integer(*p)) {
|
||||
if(!(fmt & chars_format::fixed)) {
|
||||
// We are in error.
|
||||
return answer;
|
||||
if (!uint64_t(fmt & chars_format::fixed)) {
|
||||
// The exponential part is invalid for scientific notation, so it must
|
||||
// be a trailing token for fixed notation. However, fixed notation is
|
||||
// disabled, so report a scientific notation error.
|
||||
return report_parse_error<UC>(p, parse_error::missing_exponential_part);
|
||||
}
|
||||
// Otherwise, we will be ignoring the 'e'.
|
||||
p = location_of_e;
|
||||
@@ -381,12 +405,17 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
|
||||
}
|
||||
++p;
|
||||
}
|
||||
if(neg_exp) { exp_number = - exp_number; }
|
||||
if (neg_exp) {
|
||||
exp_number = -exp_number;
|
||||
}
|
||||
exponent += exp_number;
|
||||
}
|
||||
} else {
|
||||
// If it scientific and not fixed, we have to bail out.
|
||||
if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }
|
||||
if (uint64_t(fmt & chars_format::scientific) &&
|
||||
!uint64_t(fmt & chars_format::fixed)) {
|
||||
return report_parse_error<UC>(p, parse_error::missing_exponential_part);
|
||||
}
|
||||
}
|
||||
answer.lastmatch = p;
|
||||
answer.valid = true;
|
||||
@@ -401,9 +430,11 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
|
||||
// We have to handle the case where we have 0.0000somenumber.
|
||||
// We need to be mindful of the case where we only have zeroes...
|
||||
// E.g., 0.000000000...000.
|
||||
UC const * start = start_digits;
|
||||
UC const *start = start_digits;
|
||||
while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
|
||||
if(*start == UC('0')) { digit_count --; }
|
||||
if (*start == UC('0')) {
|
||||
digit_count--;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
@@ -414,18 +445,17 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
|
||||
// pre-tokenized spans from above.
|
||||
i = 0;
|
||||
p = answer.integer.ptr;
|
||||
UC const* int_end = p + answer.integer.len();
|
||||
const uint64_t minimal_nineteen_digit_integer{ 1000000000000000000 };
|
||||
UC const *int_end = p + answer.integer.len();
|
||||
uint64_t const minimal_nineteen_digit_integer{1000000000000000000};
|
||||
while ((i < minimal_nineteen_digit_integer) && (p != int_end)) {
|
||||
i = i * 10 + uint64_t(*p - UC('0'));
|
||||
++p;
|
||||
}
|
||||
if (i >= minimal_nineteen_digit_integer) { // We have a big integers
|
||||
exponent = end_of_integer_part - p + exp_number;
|
||||
}
|
||||
else { // We have a value with a fractional component.
|
||||
} else { // We have a value with a fractional component.
|
||||
p = answer.fraction.ptr;
|
||||
UC const* frac_end = p + answer.fraction.len();
|
||||
UC const *frac_end = p + answer.fraction.len();
|
||||
while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
|
||||
i = i * 10 + uint64_t(*p - UC('0'));
|
||||
++p;
|
||||
@@ -441,35 +471,43 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
|
||||
}
|
||||
|
||||
template <typename T, typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value, int base) {
|
||||
from_chars_result_t<UC> answer;
|
||||
|
||||
UC const* const first = p;
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
parse_int_string(UC const *p, UC const *pend, T &value,
|
||||
parse_options_t<UC> options) {
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
int const base = options.base;
|
||||
|
||||
bool negative = (*p == UC('-'));
|
||||
from_chars_result_t<UC> answer;
|
||||
|
||||
UC const *const first = p;
|
||||
|
||||
bool const negative = (*p == UC('-'));
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
if (!std::is_signed<T>::value && negative) {
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||
if ((*p == UC('-')) || (*p == UC('+'))) {
|
||||
#else
|
||||
if (*p == UC('-')) {
|
||||
#endif
|
||||
if ((*p == UC('-')) ||
|
||||
(uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) {
|
||||
++p;
|
||||
}
|
||||
|
||||
UC const* const start_num = p;
|
||||
UC const *const start_num = p;
|
||||
|
||||
while (p!= pend && *p == UC('0')) {
|
||||
++p;
|
||||
while (p != pend && *p == UC('0')) {
|
||||
++p;
|
||||
}
|
||||
|
||||
const bool has_leading_zeros = p > start_num;
|
||||
bool const has_leading_zeros = p > start_num;
|
||||
|
||||
UC const* const start_digits = p;
|
||||
UC const *const start_digits = p;
|
||||
|
||||
uint64_t i = 0;
|
||||
if (base == 10) {
|
||||
@@ -481,9 +519,9 @@ from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value,
|
||||
break;
|
||||
}
|
||||
i = uint64_t(base) * i + digit; // might overflow, check this later
|
||||
p++;
|
||||
p++;
|
||||
}
|
||||
|
||||
|
||||
size_t digit_count = size_t(p - start_digits);
|
||||
|
||||
if (digit_count == 0) {
|
||||
@@ -491,12 +529,11 @@ from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value,
|
||||
value = 0;
|
||||
answer.ec = std::errc();
|
||||
answer.ptr = p;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
}
|
||||
return answer;
|
||||
return answer;
|
||||
}
|
||||
|
||||
answer.ptr = p;
|
||||
@@ -507,7 +544,8 @@ from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value,
|
||||
answer.ec = std::errc::result_out_of_range;
|
||||
return answer;
|
||||
}
|
||||
// this check can be eliminated for all other types, but they will all require a max_digits(base) equivalent
|
||||
// this check can be eliminated for all other types, but they will all require
|
||||
// a max_digits(base) equivalent
|
||||
if (digit_count == max_digits && i < min_safe_u64(base)) {
|
||||
answer.ec = std::errc::result_out_of_range;
|
||||
return answer;
|
||||
@@ -524,18 +562,22 @@ from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value,
|
||||
if (negative) {
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4146)
|
||||
#pragma warning(disable : 4146)
|
||||
#endif
|
||||
// this weird workaround is required because:
|
||||
// - converting unsigned to signed when its value is greater than signed max is UB pre-C++23.
|
||||
// - converting unsigned to signed when its value is greater than signed max
|
||||
// is UB pre-C++23.
|
||||
// - reinterpret_casting (~i + 1) would work, but it is not constexpr
|
||||
// this is always optimized into a neg instruction (note: T is an integer type)
|
||||
value = T(-std::numeric_limits<T>::max() - T(i - uint64_t(std::numeric_limits<T>::max())));
|
||||
// this is always optimized into a neg instruction (note: T is an integer
|
||||
// type)
|
||||
value = T(-std::numeric_limits<T>::max() -
|
||||
T(i - uint64_t(std::numeric_limits<T>::max())));
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
} else {
|
||||
value = T(i);
|
||||
}
|
||||
else { value = T(i); }
|
||||
|
||||
answer.ec = std::errc();
|
||||
return answer;
|
||||
|
||||
223
3rdparty/fast_float/include/fast_float/bigint.h
vendored
223
3rdparty/fast_float/include/fast_float/bigint.h
vendored
@@ -37,15 +37,14 @@ constexpr size_t bigint_limbs = bigint_bits / limb_bits;
|
||||
|
||||
// vector-like type that is allocated on the stack. the entire
|
||||
// buffer is pre-allocated, and only the length changes.
|
||||
template <uint16_t size>
|
||||
struct stackvec {
|
||||
template <uint16_t size> struct stackvec {
|
||||
limb data[size];
|
||||
// we never need more than 150 limbs
|
||||
uint16_t length{0};
|
||||
|
||||
stackvec() = default;
|
||||
stackvec(const stackvec &) = delete;
|
||||
stackvec &operator=(const stackvec &) = delete;
|
||||
stackvec(stackvec const &) = delete;
|
||||
stackvec &operator=(stackvec const &) = delete;
|
||||
stackvec(stackvec &&) = delete;
|
||||
stackvec &operator=(stackvec &&other) = delete;
|
||||
|
||||
@@ -54,16 +53,18 @@ struct stackvec {
|
||||
FASTFLOAT_ASSERT(try_extend(s));
|
||||
}
|
||||
|
||||
FASTFLOAT_CONSTEXPR14 limb& operator[](size_t index) noexcept {
|
||||
FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept {
|
||||
FASTFLOAT_DEBUG_ASSERT(index < length);
|
||||
return data[index];
|
||||
}
|
||||
FASTFLOAT_CONSTEXPR14 const limb& operator[](size_t index) const noexcept {
|
||||
|
||||
FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept {
|
||||
FASTFLOAT_DEBUG_ASSERT(index < length);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
// index from the end of the container
|
||||
FASTFLOAT_CONSTEXPR14 const limb& rindex(size_t index) const noexcept {
|
||||
FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept {
|
||||
FASTFLOAT_DEBUG_ASSERT(index < length);
|
||||
size_t rindex = length - index - 1;
|
||||
return data[rindex];
|
||||
@@ -73,20 +74,19 @@ struct stackvec {
|
||||
FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept {
|
||||
length = uint16_t(len);
|
||||
}
|
||||
constexpr size_t len() const noexcept {
|
||||
return length;
|
||||
}
|
||||
constexpr bool is_empty() const noexcept {
|
||||
return length == 0;
|
||||
}
|
||||
constexpr size_t capacity() const noexcept {
|
||||
return size;
|
||||
}
|
||||
|
||||
constexpr size_t len() const noexcept { return length; }
|
||||
|
||||
constexpr bool is_empty() const noexcept { return length == 0; }
|
||||
|
||||
constexpr size_t capacity() const noexcept { return size; }
|
||||
|
||||
// append item to vector, without bounds checking
|
||||
FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept {
|
||||
data[length] = value;
|
||||
length++;
|
||||
}
|
||||
|
||||
// append item to vector, returning if item was added
|
||||
FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept {
|
||||
if (len() < capacity()) {
|
||||
@@ -96,12 +96,14 @@ struct stackvec {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// add items to the vector, from a span, without bounds checking
|
||||
FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept {
|
||||
limb* ptr = data + length;
|
||||
limb *ptr = data + length;
|
||||
std::copy_n(s.ptr, s.len(), ptr);
|
||||
set_len(len() + s.len());
|
||||
}
|
||||
|
||||
// try to add items to the vector, returning if items were added
|
||||
FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept {
|
||||
if (len() + s.len() <= capacity()) {
|
||||
@@ -111,6 +113,7 @@ struct stackvec {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// resize the vector, without bounds checking
|
||||
// if the new size is longer than the vector, assign value to each
|
||||
// appended item.
|
||||
@@ -118,14 +121,15 @@ struct stackvec {
|
||||
void resize_unchecked(size_t new_len, limb value) noexcept {
|
||||
if (new_len > len()) {
|
||||
size_t count = new_len - len();
|
||||
limb* first = data + len();
|
||||
limb* last = first + count;
|
||||
limb *first = data + len();
|
||||
limb *last = first + count;
|
||||
::std::fill(first, last, value);
|
||||
set_len(new_len);
|
||||
} else {
|
||||
set_len(new_len);
|
||||
}
|
||||
}
|
||||
|
||||
// try to resize the vector, returning if the vector was resized.
|
||||
FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept {
|
||||
if (new_len > capacity()) {
|
||||
@@ -135,6 +139,7 @@ struct stackvec {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// check if any limbs are non-zero after the given index.
|
||||
// this needs to be done in reverse order, since the index
|
||||
// is relative to the most significant limbs.
|
||||
@@ -147,6 +152,7 @@ struct stackvec {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// normalize the big integer, so most-significant zero limbs are removed.
|
||||
FASTFLOAT_CONSTEXPR14 void normalize() noexcept {
|
||||
while (len() > 0 && rindex(0) == 0) {
|
||||
@@ -155,21 +161,21 @@ struct stackvec {
|
||||
}
|
||||
};
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
uint64_t empty_hi64(bool& truncated) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
|
||||
empty_hi64(bool &truncated) noexcept {
|
||||
truncated = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint64_hi64(uint64_t r0, bool& truncated) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
|
||||
uint64_hi64(uint64_t r0, bool &truncated) noexcept {
|
||||
truncated = false;
|
||||
int shl = leading_zeroes(r0);
|
||||
return r0 << shl;
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool& truncated) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
|
||||
uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept {
|
||||
int shl = leading_zeroes(r0);
|
||||
if (shl == 0) {
|
||||
truncated = r1 != 0;
|
||||
@@ -181,20 +187,20 @@ uint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool& truncated) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint32_hi64(uint32_t r0, bool& truncated) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
|
||||
uint32_hi64(uint32_t r0, bool &truncated) noexcept {
|
||||
return uint64_hi64(r0, truncated);
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint32_hi64(uint32_t r0, uint32_t r1, bool& truncated) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
|
||||
uint32_hi64(uint32_t r0, uint32_t r1, bool &truncated) noexcept {
|
||||
uint64_t x0 = r0;
|
||||
uint64_t x1 = r1;
|
||||
return uint64_hi64((x0 << 32) | x1, truncated);
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool& truncated) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
|
||||
uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool &truncated) noexcept {
|
||||
uint64_t x0 = r0;
|
||||
uint64_t x1 = r1;
|
||||
uint64_t x2 = r2;
|
||||
@@ -205,17 +211,17 @@ uint64_t uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool& truncated) noe
|
||||
// we want an efficient operation. for msvc, where
|
||||
// we don't have built-in intrinsics, this is still
|
||||
// pretty fast.
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
limb scalar_add(limb x, limb y, bool& overflow) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
|
||||
scalar_add(limb x, limb y, bool &overflow) noexcept {
|
||||
limb z;
|
||||
// gcc and clang
|
||||
#if defined(__has_builtin)
|
||||
#if __has_builtin(__builtin_add_overflow)
|
||||
if (!cpp20_and_in_constexpr()) {
|
||||
overflow = __builtin_add_overflow(x, y, &z);
|
||||
return z;
|
||||
}
|
||||
#endif
|
||||
#if __has_builtin(__builtin_add_overflow)
|
||||
if (!cpp20_and_in_constexpr()) {
|
||||
overflow = __builtin_add_overflow(x, y, &z);
|
||||
return z;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// generic, this still optimizes correctly on MSVC.
|
||||
@@ -225,24 +231,24 @@ limb scalar_add(limb x, limb y, bool& overflow) noexcept {
|
||||
}
|
||||
|
||||
// multiply two small integers, getting both the high and low bits.
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
limb scalar_mul(limb x, limb y, limb& carry) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
|
||||
scalar_mul(limb x, limb y, limb &carry) noexcept {
|
||||
#ifdef FASTFLOAT_64BIT_LIMB
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
// GCC and clang both define it as an extension.
|
||||
__uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);
|
||||
carry = limb(z >> limb_bits);
|
||||
return limb(z);
|
||||
#else
|
||||
#else
|
||||
// fallback, no native 128-bit integer multiplication with carry.
|
||||
// on msvc, this optimizes identically, somehow.
|
||||
value128 z = full_multiplication(x, y);
|
||||
bool overflow;
|
||||
z.low = scalar_add(z.low, carry, overflow);
|
||||
z.high += uint64_t(overflow); // cannot overflow
|
||||
z.high += uint64_t(overflow); // cannot overflow
|
||||
carry = z.high;
|
||||
return z.low;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);
|
||||
carry = limb(z >> limb_bits);
|
||||
@@ -253,8 +259,8 @@ limb scalar_mul(limb x, limb y, limb& carry) noexcept {
|
||||
// add scalar value to bigint starting from offset.
|
||||
// used in grade school multiplication
|
||||
template <uint16_t size>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
bool small_add_from(stackvec<size>& vec, limb y, size_t start) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec<size> &vec, limb y,
|
||||
size_t start) noexcept {
|
||||
size_t index = start;
|
||||
limb carry = y;
|
||||
bool overflow;
|
||||
@@ -271,15 +277,15 @@ bool small_add_from(stackvec<size>& vec, limb y, size_t start) noexcept {
|
||||
|
||||
// add scalar value to bigint.
|
||||
template <uint16_t size>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool small_add(stackvec<size>& vec, limb y) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
|
||||
small_add(stackvec<size> &vec, limb y) noexcept {
|
||||
return small_add_from(vec, y, 0);
|
||||
}
|
||||
|
||||
// multiply bigint by scalar value.
|
||||
template <uint16_t size>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
bool small_mul(stackvec<size>& vec, limb y) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec<size> &vec,
|
||||
limb y) noexcept {
|
||||
limb carry = 0;
|
||||
for (size_t index = 0; index < vec.len(); index++) {
|
||||
vec[index] = scalar_mul(vec[index], y, carry);
|
||||
@@ -293,12 +299,12 @@ bool small_mul(stackvec<size>& vec, limb y) noexcept {
|
||||
// add bigint to bigint starting from index.
|
||||
// used in grade school multiplication
|
||||
template <uint16_t size>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
bool large_add_from(stackvec<size>& x, limb_span y, size_t start) noexcept {
|
||||
FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec<size> &x, limb_span y,
|
||||
size_t start) noexcept {
|
||||
// the effective x buffer is from `xstart..x.len()`, so exit early
|
||||
// if we can't get that current range.
|
||||
if (x.len() < start || y.len() > x.len() - start) {
|
||||
FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
|
||||
FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
|
||||
}
|
||||
|
||||
bool carry = false;
|
||||
@@ -324,15 +330,14 @@ bool large_add_from(stackvec<size>& x, limb_span y, size_t start) noexcept {
|
||||
|
||||
// add bigint to bigint.
|
||||
template <uint16_t size>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool large_add_from(stackvec<size>& x, limb_span y) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
|
||||
large_add_from(stackvec<size> &x, limb_span y) noexcept {
|
||||
return large_add_from(x, y, 0);
|
||||
}
|
||||
|
||||
// grade-school multiplication algorithm
|
||||
template <uint16_t size>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
bool long_mul(stackvec<size>& x, limb_span y) noexcept {
|
||||
FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec<size> &x, limb_span y) noexcept {
|
||||
limb_span xs = limb_span(x.data, x.len());
|
||||
stackvec<size> z(xs);
|
||||
limb_span zs = limb_span(z.data, z.len());
|
||||
@@ -360,8 +365,7 @@ bool long_mul(stackvec<size>& x, limb_span y) noexcept {
|
||||
|
||||
// grade-school multiplication algorithm
|
||||
template <uint16_t size>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
bool large_mul(stackvec<size>& x, limb_span y) noexcept {
|
||||
FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec<size> &x, limb_span y) noexcept {
|
||||
if (y.len() == 1) {
|
||||
FASTFLOAT_TRY(small_mul(x, y[0]));
|
||||
} else {
|
||||
@@ -370,36 +374,58 @@ bool large_mul(stackvec<size>& x, limb_span y) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename = void>
|
||||
struct pow5_tables {
|
||||
template <typename = void> struct pow5_tables {
|
||||
static constexpr uint32_t large_step = 135;
|
||||
static constexpr uint64_t small_power_of_5[] = {
|
||||
1UL, 5UL, 25UL, 125UL, 625UL, 3125UL, 15625UL, 78125UL, 390625UL,
|
||||
1953125UL, 9765625UL, 48828125UL, 244140625UL, 1220703125UL,
|
||||
6103515625UL, 30517578125UL, 152587890625UL, 762939453125UL,
|
||||
3814697265625UL, 19073486328125UL, 95367431640625UL, 476837158203125UL,
|
||||
2384185791015625UL, 11920928955078125UL, 59604644775390625UL,
|
||||
298023223876953125UL, 1490116119384765625UL, 7450580596923828125UL,
|
||||
1UL,
|
||||
5UL,
|
||||
25UL,
|
||||
125UL,
|
||||
625UL,
|
||||
3125UL,
|
||||
15625UL,
|
||||
78125UL,
|
||||
390625UL,
|
||||
1953125UL,
|
||||
9765625UL,
|
||||
48828125UL,
|
||||
244140625UL,
|
||||
1220703125UL,
|
||||
6103515625UL,
|
||||
30517578125UL,
|
||||
152587890625UL,
|
||||
762939453125UL,
|
||||
3814697265625UL,
|
||||
19073486328125UL,
|
||||
95367431640625UL,
|
||||
476837158203125UL,
|
||||
2384185791015625UL,
|
||||
11920928955078125UL,
|
||||
59604644775390625UL,
|
||||
298023223876953125UL,
|
||||
1490116119384765625UL,
|
||||
7450580596923828125UL,
|
||||
};
|
||||
#ifdef FASTFLOAT_64BIT_LIMB
|
||||
constexpr static limb large_power_of_5[] = {
|
||||
1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
|
||||
10482974169319127550UL, 198276706040285095UL};
|
||||
1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
|
||||
10482974169319127550UL, 198276706040285095UL};
|
||||
#else
|
||||
constexpr static limb large_power_of_5[] = {
|
||||
4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U,
|
||||
1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U};
|
||||
4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U,
|
||||
1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U};
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr uint32_t pow5_tables<T>::large_step;
|
||||
#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
|
||||
|
||||
template <typename T>
|
||||
constexpr uint64_t pow5_tables<T>::small_power_of_5[];
|
||||
template <typename T> constexpr uint32_t pow5_tables<T>::large_step;
|
||||
|
||||
template <typename T>
|
||||
constexpr limb pow5_tables<T>::large_power_of_5[];
|
||||
template <typename T> constexpr uint64_t pow5_tables<T>::small_power_of_5[];
|
||||
|
||||
template <typename T> constexpr limb pow5_tables<T>::large_power_of_5[];
|
||||
|
||||
#endif
|
||||
|
||||
// big integer type. implements a small subset of big integer
|
||||
// arithmetic, using simple algorithms since asymptotically
|
||||
@@ -409,13 +435,14 @@ struct bigint : pow5_tables<> {
|
||||
// storage of the limbs, in little-endian order.
|
||||
stackvec<bigint_limbs> vec;
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 bigint(): vec() {}
|
||||
bigint(const bigint &) = delete;
|
||||
bigint &operator=(const bigint &) = delete;
|
||||
FASTFLOAT_CONSTEXPR20 bigint() : vec() {}
|
||||
|
||||
bigint(bigint const &) = delete;
|
||||
bigint &operator=(bigint const &) = delete;
|
||||
bigint(bigint &&) = delete;
|
||||
bigint &operator=(bigint &&other) = delete;
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 bigint(uint64_t value): vec() {
|
||||
FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() {
|
||||
#ifdef FASTFLOAT_64BIT_LIMB
|
||||
vec.push_unchecked(value);
|
||||
#else
|
||||
@@ -427,7 +454,7 @@ struct bigint : pow5_tables<> {
|
||||
|
||||
// get the high 64 bits from the vector, and if bits were truncated.
|
||||
// this is to get the significant digits for the float.
|
||||
FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool& truncated) const noexcept {
|
||||
FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool &truncated) const noexcept {
|
||||
#ifdef FASTFLOAT_64BIT_LIMB
|
||||
if (vec.len() == 0) {
|
||||
return empty_hi64(truncated);
|
||||
@@ -446,7 +473,8 @@ struct bigint : pow5_tables<> {
|
||||
} else if (vec.len() == 2) {
|
||||
return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated);
|
||||
} else {
|
||||
uint64_t result = uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
|
||||
uint64_t result =
|
||||
uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
|
||||
truncated |= vec.nonzero(3);
|
||||
return result;
|
||||
}
|
||||
@@ -459,7 +487,7 @@ struct bigint : pow5_tables<> {
|
||||
// positive, this is larger, otherwise they are equal.
|
||||
// the limbs are stored in little-endian order, so we
|
||||
// must compare the limbs in ever order.
|
||||
FASTFLOAT_CONSTEXPR20 int compare(const bigint& other) const noexcept {
|
||||
FASTFLOAT_CONSTEXPR20 int compare(bigint const &other) const noexcept {
|
||||
if (vec.len() > other.vec.len()) {
|
||||
return 1;
|
||||
} else if (vec.len() < other.vec.len()) {
|
||||
@@ -512,12 +540,12 @@ struct bigint : pow5_tables<> {
|
||||
return false;
|
||||
} else if (!vec.is_empty()) {
|
||||
// move limbs
|
||||
limb* dst = vec.data + n;
|
||||
const limb* src = vec.data;
|
||||
limb *dst = vec.data + n;
|
||||
limb const *src = vec.data;
|
||||
std::copy_backward(src, src + vec.len(), dst + vec.len());
|
||||
// fill in empty limbs
|
||||
limb* first = vec.data;
|
||||
limb* last = first + n;
|
||||
limb *first = vec.data;
|
||||
limb *last = first + n;
|
||||
::std::fill(first, last, 0);
|
||||
vec.set_len(n + vec.len());
|
||||
return true;
|
||||
@@ -560,18 +588,12 @@ struct bigint : pow5_tables<> {
|
||||
return int(limb_bits * vec.len()) - lz;
|
||||
}
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept {
|
||||
return small_mul(vec, y);
|
||||
}
|
||||
FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); }
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept {
|
||||
return small_add(vec, y);
|
||||
}
|
||||
FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); }
|
||||
|
||||
// multiply as if by 2 raised to a power.
|
||||
FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept {
|
||||
return shl(exp);
|
||||
}
|
||||
FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { return shl(exp); }
|
||||
|
||||
// multiply as if by 5 raised to a power.
|
||||
FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept {
|
||||
@@ -597,9 +619,8 @@ struct bigint : pow5_tables<> {
|
||||
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||
// This is similar to https://github.com/llvm/llvm-project/issues/47746,
|
||||
// except the workaround described there don't work here
|
||||
FASTFLOAT_TRY(
|
||||
small_mul(vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))
|
||||
);
|
||||
FASTFLOAT_TRY(small_mul(
|
||||
vec, limb(((void)small_power_of_5[0], small_power_of_5[exp]))));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
// Testing for https://wg21.link/N3652, adopted in C++14
|
||||
#if __cpp_constexpr >= 201304
|
||||
#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
|
||||
#define FASTFLOAT_CONSTEXPR14 constexpr
|
||||
#else
|
||||
#define FASTFLOAT_CONSTEXPR14
|
||||
@@ -20,16 +20,23 @@
|
||||
#define FASTFLOAT_HAS_BIT_CAST 0
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L
|
||||
#if defined(__cpp_lib_is_constant_evaluated) && \
|
||||
__cpp_lib_is_constant_evaluated >= 201811L
|
||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
||||
#else
|
||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
|
||||
#define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x)
|
||||
#else
|
||||
#define FASTFLOAT_IF_CONSTEXPR17(x) if (x)
|
||||
#endif
|
||||
|
||||
// Testing for relevant C++20 constexpr library features
|
||||
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED \
|
||||
&& FASTFLOAT_HAS_BIT_CAST \
|
||||
&& __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
|
||||
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \
|
||||
defined(__cpp_lib_constexpr_algorithms) && \
|
||||
__cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
|
||||
#define FASTFLOAT_CONSTEXPR20 constexpr
|
||||
#define FASTFLOAT_IS_CONSTEXPR 1
|
||||
#else
|
||||
@@ -37,4 +44,10 @@
|
||||
#define FASTFLOAT_IS_CONSTEXPR 0
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 0
|
||||
#else
|
||||
#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1
|
||||
#endif
|
||||
|
||||
#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
||||
|
||||
@@ -12,27 +12,34 @@
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
// This will compute or rather approximate w * 5**q and return a pair of 64-bit words approximating
|
||||
// the result, with the "high" part corresponding to the most significant bits and the
|
||||
// low part corresponding to the least significant bits.
|
||||
// This will compute or rather approximate w * 5**q and return a pair of 64-bit
|
||||
// words approximating the result, with the "high" part corresponding to the
|
||||
// most significant bits and the low part corresponding to the least significant
|
||||
// bits.
|
||||
//
|
||||
template <int bit_precision>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
||||
const int index = 2 * int(q - powers::smallest_power_of_five);
|
||||
// For small values of q, e.g., q in [0,27], the answer is always exact because
|
||||
// The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
|
||||
// gives the exact answer.
|
||||
value128 firstproduct = full_multiplication(w, powers::power_of_five_128[index]);
|
||||
static_assert((bit_precision >= 0) && (bit_precision <= 64), " precision should be in (0,64]");
|
||||
constexpr uint64_t precision_mask = (bit_precision < 64) ?
|
||||
(uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
|
||||
: uint64_t(0xFFFFFFFFFFFFFFFF);
|
||||
if((firstproduct.high & precision_mask) == precision_mask) { // could further guard with (lower + w < lower)
|
||||
// regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed.
|
||||
value128 secondproduct = full_multiplication(w, powers::power_of_five_128[index + 1]);
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
|
||||
compute_product_approximation(int64_t q, uint64_t w) {
|
||||
int const index = 2 * int(q - powers::smallest_power_of_five);
|
||||
// For small values of q, e.g., q in [0,27], the answer is always exact
|
||||
// because The line value128 firstproduct = full_multiplication(w,
|
||||
// power_of_five_128[index]); gives the exact answer.
|
||||
value128 firstproduct =
|
||||
full_multiplication(w, powers::power_of_five_128[index]);
|
||||
static_assert((bit_precision >= 0) && (bit_precision <= 64),
|
||||
" precision should be in (0,64]");
|
||||
constexpr uint64_t precision_mask =
|
||||
(bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
|
||||
: uint64_t(0xFFFFFFFFFFFFFFFF);
|
||||
if ((firstproduct.high & precision_mask) ==
|
||||
precision_mask) { // could further guard with (lower + w < lower)
|
||||
// regarding the second product, we only need secondproduct.high, but our
|
||||
// expectation is that the compiler will optimize this extra work away if
|
||||
// needed.
|
||||
value128 secondproduct =
|
||||
full_multiplication(w, powers::power_of_five_128[index + 1]);
|
||||
firstproduct.low += secondproduct.high;
|
||||
if(secondproduct.high > firstproduct.low) {
|
||||
if (secondproduct.high > firstproduct.low) {
|
||||
firstproduct.high++;
|
||||
}
|
||||
}
|
||||
@@ -55,43 +62,45 @@ namespace detail {
|
||||
* where
|
||||
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
||||
*/
|
||||
constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept {
|
||||
return (((152170 + 65536) * q) >> 16) + 63;
|
||||
}
|
||||
constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept {
|
||||
return (((152170 + 65536) * q) >> 16) + 63;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
// create an adjusted mantissa, biased by the invalid power2
|
||||
// for significant digits already multiplied by 10 ** q.
|
||||
template <typename binary>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
adjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa
|
||||
compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept {
|
||||
int hilz = int(w >> 63) ^ 1;
|
||||
adjusted_mantissa answer;
|
||||
answer.mantissa = w << hilz;
|
||||
int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent();
|
||||
answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + invalid_am_bias);
|
||||
answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 +
|
||||
invalid_am_bias);
|
||||
return answer;
|
||||
}
|
||||
|
||||
// w * 10 ** q, without rounding the representation up.
|
||||
// the power2 in the exponent will be adjusted by invalid_am_bias.
|
||||
template <typename binary>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
|
||||
compute_error(int64_t q, uint64_t w) noexcept {
|
||||
int lz = leading_zeroes(w);
|
||||
w <<= lz;
|
||||
value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
|
||||
value128 product =
|
||||
compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
|
||||
return compute_error_scaled<binary>(q, product.high, lz);
|
||||
}
|
||||
|
||||
// w * 10 ** q
|
||||
// The returned value should be a valid ieee64 number that simply need to be packed.
|
||||
// However, in some very rare cases, the computation will fail. In such cases, we
|
||||
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
|
||||
// in such cases.
|
||||
// Computers w * 10 ** q.
|
||||
// The returned value should be a valid number that simply needs to be
|
||||
// packed. However, in some very rare cases, the computation will fail. In such
|
||||
// cases, we return an adjusted_mantissa with a negative power of 2: the caller
|
||||
// should recompute in such cases.
|
||||
template <typename binary>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
|
||||
compute_float(int64_t q, uint64_t w) noexcept {
|
||||
adjusted_mantissa answer;
|
||||
if ((w == 0) || (q < binary::smallest_power_of_ten())) {
|
||||
answer.power2 = 0;
|
||||
@@ -105,7 +114,8 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
// At this point in time q is in [powers::smallest_power_of_five, powers::largest_power_of_five].
|
||||
// At this point in time q is in [powers::smallest_power_of_five,
|
||||
// powers::largest_power_of_five].
|
||||
|
||||
// We want the most significant bit of i to be 1. Shift if needed.
|
||||
int lz = leading_zeroes(w);
|
||||
@@ -114,26 +124,32 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
// The required precision is binary::mantissa_explicit_bits() + 3 because
|
||||
// 1. We need the implicit bit
|
||||
// 2. We need an extra bit for rounding purposes
|
||||
// 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift)
|
||||
// 3. We might lose a bit due to the "upperbit" routine (result too small,
|
||||
// requiring a shift)
|
||||
|
||||
value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
|
||||
value128 product =
|
||||
compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
|
||||
// The computed 'product' is always sufficient.
|
||||
// Mathematical proof:
|
||||
// Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to appear)
|
||||
// See script/mushtak_lemire.py
|
||||
// Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to
|
||||
// appear) See script/mushtak_lemire.py
|
||||
|
||||
// The "compute_product_approximation" function can be slightly slower than a branchless approach:
|
||||
// value128 product = compute_product(q, w);
|
||||
// but in practice, we can win big with the compute_product_approximation if its additional branch
|
||||
// is easily predicted. Which is best is data specific.
|
||||
// The "compute_product_approximation" function can be slightly slower than a
|
||||
// branchless approach: value128 product = compute_product(q, w); but in
|
||||
// practice, we can win big with the compute_product_approximation if its
|
||||
// additional branch is easily predicted. Which is best is data specific.
|
||||
int upperbit = int(product.high >> 63);
|
||||
int shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3;
|
||||
|
||||
answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
|
||||
answer.mantissa = product.high >> shift;
|
||||
|
||||
answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz - binary::minimum_exponent());
|
||||
answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz -
|
||||
binary::minimum_exponent());
|
||||
if (answer.power2 <= 0) { // we have a subnormal?
|
||||
// Here have that answer.power2 <= 0 so -answer.power2 >= 0
|
||||
if(-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
|
||||
if (-answer.power2 + 1 >=
|
||||
64) { // if we have more than 64 bits below the minimum exponent, you
|
||||
// have a zero for sure.
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
// result should be zero
|
||||
@@ -142,7 +158,8 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
// next line is safe because -answer.power2 + 1 < 64
|
||||
answer.mantissa >>= -answer.power2 + 1;
|
||||
// Thankfully, we can't have both "round-to-even" and subnormals because
|
||||
// "round-to-even" only occurs for powers close to 0.
|
||||
// "round-to-even" only occurs for powers close to 0 in the 32-bit and
|
||||
// and 64-bit case (with no more than 19 digits).
|
||||
answer.mantissa += (answer.mantissa & 1); // round up
|
||||
answer.mantissa >>= 1;
|
||||
// There is a weird scenario where we don't have a subnormal but just.
|
||||
@@ -152,20 +169,26 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
// up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer
|
||||
// subnormal, but we can only know this after rounding.
|
||||
// So we only declare a subnormal if we are smaller than the threshold.
|
||||
answer.power2 = (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) ? 0 : 1;
|
||||
answer.power2 =
|
||||
(answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits()))
|
||||
? 0
|
||||
: 1;
|
||||
return answer;
|
||||
}
|
||||
|
||||
// usually, we round *up*, but if we fall right in between and and we have an
|
||||
// even basis, we need to round down
|
||||
// We are only concerned with the cases where 5**q fits in single 64-bit word.
|
||||
if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) && (q <= binary::max_exponent_round_to_even()) &&
|
||||
((answer.mantissa & 3) == 1) ) { // we may fall between two floats!
|
||||
if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) &&
|
||||
(q <= binary::max_exponent_round_to_even()) &&
|
||||
((answer.mantissa & 3) == 1)) { // we may fall between two floats!
|
||||
// To be in-between two floats we need that in doing
|
||||
// answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
|
||||
// ... we dropped out only zeroes. But if this happened, then we can go back!!!
|
||||
if((answer.mantissa << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) == product.high) {
|
||||
answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up
|
||||
// answer.mantissa = product.high >> (upperbit + 64 -
|
||||
// binary::mantissa_explicit_bits() - 3);
|
||||
// ... we dropped out only zeroes. But if this happened, then we can go
|
||||
// back!!!
|
||||
if ((answer.mantissa << shift) == product.high) {
|
||||
answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,19 +13,34 @@
|
||||
namespace fast_float {
|
||||
|
||||
// 1e0 to 1e19
|
||||
constexpr static uint64_t powers_of_ten_uint64[] = {
|
||||
1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,
|
||||
1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,
|
||||
100000000000000UL, 1000000000000000UL, 10000000000000000UL, 100000000000000000UL,
|
||||
1000000000000000000UL, 10000000000000000000UL};
|
||||
constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
|
||||
10UL,
|
||||
100UL,
|
||||
1000UL,
|
||||
10000UL,
|
||||
100000UL,
|
||||
1000000UL,
|
||||
10000000UL,
|
||||
100000000UL,
|
||||
1000000000UL,
|
||||
10000000000UL,
|
||||
100000000000UL,
|
||||
1000000000000UL,
|
||||
10000000000000UL,
|
||||
100000000000000UL,
|
||||
1000000000000000UL,
|
||||
10000000000000000UL,
|
||||
100000000000000000UL,
|
||||
1000000000000000000UL,
|
||||
10000000000000000000UL};
|
||||
|
||||
// calculate the exponent, in scientific notation, of the number.
|
||||
// this algorithm is not even close to optimized, but it has no practical
|
||||
// effect on performance: in order to have a faster algorithm, we'd need
|
||||
// to slow down performance for faster algorithms, and this is still fast.
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t
|
||||
scientific_exponent(parsed_number_string_t<UC> &num) noexcept {
|
||||
uint64_t mantissa = num.mantissa;
|
||||
int32_t exponent = int32_t(num.exponent);
|
||||
while (mantissa >= 10000) {
|
||||
@@ -45,15 +60,16 @@ int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept {
|
||||
|
||||
// this converts a native floating-point number to an extended-precision float.
|
||||
template <typename T>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa to_extended(T value) noexcept {
|
||||
using equiv_uint = typename binary_format<T>::equiv_uint;
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
|
||||
to_extended(T value) noexcept {
|
||||
using equiv_uint = equiv_uint_t<T>;
|
||||
constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
|
||||
constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
|
||||
constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
|
||||
|
||||
adjusted_mantissa am;
|
||||
int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
|
||||
int32_t bias = binary_format<T>::mantissa_explicit_bits() -
|
||||
binary_format<T>::minimum_exponent();
|
||||
equiv_uint bits;
|
||||
#if FASTFLOAT_HAS_BIT_CAST
|
||||
bits = std::bit_cast<equiv_uint>(value);
|
||||
@@ -66,7 +82,8 @@ adjusted_mantissa to_extended(T value) noexcept {
|
||||
am.mantissa = bits & mantissa_mask;
|
||||
} else {
|
||||
// normal
|
||||
am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());
|
||||
am.power2 = int32_t((bits & exponent_mask) >>
|
||||
binary_format<T>::mantissa_explicit_bits());
|
||||
am.power2 -= bias;
|
||||
am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
|
||||
}
|
||||
@@ -78,8 +95,8 @@ adjusted_mantissa to_extended(T value) noexcept {
|
||||
// we are given a native float that represents b, so we need to adjust it
|
||||
// halfway between b and b+u.
|
||||
template <typename T>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa to_extended_halfway(T value) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
|
||||
to_extended_halfway(T value) noexcept {
|
||||
adjusted_mantissa am = to_extended(value);
|
||||
am.mantissa <<= 1;
|
||||
am.mantissa += 1;
|
||||
@@ -89,15 +106,18 @@ adjusted_mantissa to_extended_halfway(T value) noexcept {
|
||||
|
||||
// round an extended-precision float to the nearest machine float.
|
||||
template <typename T, typename callback>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
void round(adjusted_mantissa& am, callback cb) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am,
|
||||
callback cb) noexcept {
|
||||
int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1;
|
||||
if (-am.power2 >= mantissa_shift) {
|
||||
// have a denormal float
|
||||
int32_t shift = -am.power2 + 1;
|
||||
cb(am, std::min<int32_t>(shift, 64));
|
||||
// check for round-up: if rounding-nearest carried us to the hidden bit.
|
||||
am.power2 = (am.mantissa < (uint64_t(1) << binary_format<T>::mantissa_explicit_bits())) ? 0 : 1;
|
||||
am.power2 = (am.mantissa <
|
||||
(uint64_t(1) << binary_format<T>::mantissa_explicit_bits()))
|
||||
? 0
|
||||
: 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,7 +125,8 @@ void round(adjusted_mantissa& am, callback cb) noexcept {
|
||||
cb(am, mantissa_shift);
|
||||
|
||||
// check for carry
|
||||
if (am.mantissa >= (uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {
|
||||
if (am.mantissa >=
|
||||
(uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {
|
||||
am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
|
||||
am.power2++;
|
||||
}
|
||||
@@ -119,16 +140,11 @@ void round(adjusted_mantissa& am, callback cb) noexcept {
|
||||
}
|
||||
|
||||
template <typename callback>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
void round_nearest_tie_even(adjusted_mantissa& am, int32_t shift, callback cb) noexcept {
|
||||
const uint64_t mask
|
||||
= (shift == 64)
|
||||
? UINT64_MAX
|
||||
: (uint64_t(1) << shift) - 1;
|
||||
const uint64_t halfway
|
||||
= (shift == 0)
|
||||
? 0
|
||||
: uint64_t(1) << (shift - 1);
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void
|
||||
round_nearest_tie_even(adjusted_mantissa &am, int32_t shift,
|
||||
callback cb) noexcept {
|
||||
uint64_t const mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1;
|
||||
uint64_t const halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1);
|
||||
uint64_t truncated_bits = am.mantissa & mask;
|
||||
bool is_above = truncated_bits > halfway;
|
||||
bool is_halfway = truncated_bits == halfway;
|
||||
@@ -145,8 +161,8 @@ void round_nearest_tie_even(adjusted_mantissa& am, int32_t shift, callback cb) n
|
||||
am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above));
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void
|
||||
round_down(adjusted_mantissa &am, int32_t shift) noexcept {
|
||||
if (shift == 64) {
|
||||
am.mantissa = 0;
|
||||
} else {
|
||||
@@ -154,11 +170,13 @@ void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
|
||||
}
|
||||
am.power2 += shift;
|
||||
}
|
||||
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void skip_zeros(UC const * & first, UC const * last) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
skip_zeros(UC const *&first, UC const *last) noexcept {
|
||||
uint64_t val;
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
while (!cpp20_and_in_constexpr() &&
|
||||
std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != int_cmp_zeros<UC>()) {
|
||||
break;
|
||||
@@ -176,11 +194,12 @@ void skip_zeros(UC const * & first, UC const * last) noexcept {
|
||||
// determine if any non-zero digits were truncated.
|
||||
// all characters must be valid digits.
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(UC const * first, UC const * last) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
|
||||
is_truncated(UC const *first, UC const *last) noexcept {
|
||||
// do 8-bit optimizations, can just compare to 8 literal 0s.
|
||||
uint64_t val;
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
while (!cpp20_and_in_constexpr() &&
|
||||
std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != int_cmp_zeros<UC>()) {
|
||||
return true;
|
||||
@@ -195,16 +214,17 @@ bool is_truncated(UC const * first, UC const * last) noexcept {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(span<const UC> s) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
|
||||
is_truncated(span<UC const> s) noexcept {
|
||||
return is_truncated(s.ptr, s.ptr + s.len());
|
||||
}
|
||||
|
||||
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void parse_eight_digits(const UC*& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
parse_eight_digits(UC const *&p, limb &value, size_t &counter,
|
||||
size_t &count) noexcept {
|
||||
value = value * 100000000 + parse_eight_digits_unrolled(p);
|
||||
p += 8;
|
||||
counter += 8;
|
||||
@@ -212,22 +232,23 @@ void parse_eight_digits(const UC*& p, limb& value, size_t& counter, size_t& coun
|
||||
}
|
||||
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
void parse_one_digit(UC const *& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void
|
||||
parse_one_digit(UC const *&p, limb &value, size_t &counter,
|
||||
size_t &count) noexcept {
|
||||
value = value * 10 + limb(*p - UC('0'));
|
||||
p++;
|
||||
counter++;
|
||||
count++;
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void add_native(bigint& big, limb power, limb value) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
add_native(bigint &big, limb power, limb value) noexcept {
|
||||
big.mul(power);
|
||||
big.add(value);
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void round_up_bigint(bigint& big, size_t& count) noexcept {
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
round_up_bigint(bigint &big, size_t &count) noexcept {
|
||||
// need to round-up the digits, but need to avoid rounding
|
||||
// ....9999 to ...10000, which could cause a false halfway point.
|
||||
add_native(big, 10, 1);
|
||||
@@ -236,8 +257,9 @@ void round_up_bigint(bigint& big, size_t& count) noexcept {
|
||||
|
||||
// parse the significant digits into a big integer
|
||||
template <typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
void parse_mantissa(bigint& result, parsed_number_string_t<UC>& num, size_t max_digits, size_t& digits) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20 void
|
||||
parse_mantissa(bigint &result, parsed_number_string_t<UC> &num,
|
||||
size_t max_digits, size_t &digits) noexcept {
|
||||
// try to minimize the number of big integer and scalar multiplication.
|
||||
// therefore, try to parse 8 digits at a time, and multiply by the largest
|
||||
// scalar value (9 or 19 digits) for each step.
|
||||
@@ -251,12 +273,13 @@ void parse_mantissa(bigint& result, parsed_number_string_t<UC>& num, size_t max_
|
||||
#endif
|
||||
|
||||
// process all integer digits.
|
||||
UC const * p = num.integer.ptr;
|
||||
UC const * pend = p + num.integer.len();
|
||||
UC const *p = num.integer.ptr;
|
||||
UC const *pend = p + num.integer.len();
|
||||
skip_zeros(p, pend);
|
||||
// process all digits, in increments of step per loop
|
||||
while (p != pend) {
|
||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) &&
|
||||
(max_digits - digits >= 8)) {
|
||||
parse_eight_digits(p, value, counter, digits);
|
||||
}
|
||||
while (counter < step && p != pend && digits < max_digits) {
|
||||
@@ -289,7 +312,8 @@ void parse_mantissa(bigint& result, parsed_number_string_t<UC>& num, size_t max_
|
||||
}
|
||||
// process all digits, in increments of step per loop
|
||||
while (p != pend) {
|
||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) &&
|
||||
(max_digits - digits >= 8)) {
|
||||
parse_eight_digits(p, value, counter, digits);
|
||||
}
|
||||
while (counter < step && p != pend && digits < max_digits) {
|
||||
@@ -317,19 +341,23 @@ void parse_mantissa(bigint& result, parsed_number_string_t<UC>& num, size_t max_
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
|
||||
positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept {
|
||||
FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));
|
||||
adjusted_mantissa answer;
|
||||
bool truncated;
|
||||
answer.mantissa = bigmant.hi64(truncated);
|
||||
int bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
|
||||
int bias = binary_format<T>::mantissa_explicit_bits() -
|
||||
binary_format<T>::minimum_exponent();
|
||||
answer.power2 = bigmant.bit_length() - 64 + bias;
|
||||
|
||||
round<T>(answer, [truncated](adjusted_mantissa& a, int32_t shift) {
|
||||
round_nearest_tie_even(a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool {
|
||||
return is_above || (is_halfway && truncated) || (is_odd && is_halfway);
|
||||
});
|
||||
round<T>(answer, [truncated](adjusted_mantissa &a, int32_t shift) {
|
||||
round_nearest_tie_even(
|
||||
a, shift,
|
||||
[truncated](bool is_odd, bool is_halfway, bool is_above) -> bool {
|
||||
return is_above || (is_halfway && truncated) ||
|
||||
(is_odd && is_halfway);
|
||||
});
|
||||
});
|
||||
|
||||
return answer;
|
||||
@@ -341,15 +369,17 @@ adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcep
|
||||
// we then need to scale by `2^(f- e)`, and then the two significant digits
|
||||
// are of the same magnitude.
|
||||
template <typename T>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
|
||||
bigint& real_digits = bigmant;
|
||||
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
|
||||
bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
|
||||
bigint &real_digits = bigmant;
|
||||
int32_t real_exp = exponent;
|
||||
|
||||
// get the value of `b`, rounded down, and get a bigint representation of b+h
|
||||
adjusted_mantissa am_b = am;
|
||||
// gcc7 buf: use a lambda to remove the noexcept qualifier bug with -Wnoexcept-type.
|
||||
round<T>(am_b, [](adjusted_mantissa&a, int32_t shift) { round_down(a, shift); });
|
||||
// gcc7 buf: use a lambda to remove the noexcept qualifier bug with
|
||||
// -Wnoexcept-type.
|
||||
round<T>(am_b,
|
||||
[](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); });
|
||||
T b;
|
||||
to_float(false, am_b, b);
|
||||
adjusted_mantissa theor = to_extended_halfway(b);
|
||||
@@ -371,18 +401,19 @@ adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int
|
||||
// compare digits, and use it to director rounding
|
||||
int ord = real_digits.compare(theor_digits);
|
||||
adjusted_mantissa answer = am;
|
||||
round<T>(answer, [ord](adjusted_mantissa& a, int32_t shift) {
|
||||
round_nearest_tie_even(a, shift, [ord](bool is_odd, bool _, bool __) -> bool {
|
||||
(void)_; // not needed, since we've done our comparison
|
||||
(void)__; // not needed, since we've done our comparison
|
||||
if (ord > 0) {
|
||||
return true;
|
||||
} else if (ord < 0) {
|
||||
return false;
|
||||
} else {
|
||||
return is_odd;
|
||||
}
|
||||
});
|
||||
round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
|
||||
round_nearest_tie_even(
|
||||
a, shift, [ord](bool is_odd, bool _, bool __) -> bool {
|
||||
(void)_; // not needed, since we've done our comparison
|
||||
(void)__; // not needed, since we've done our comparison
|
||||
if (ord > 0) {
|
||||
return true;
|
||||
} else if (ord < 0) {
|
||||
return false;
|
||||
} else {
|
||||
return is_odd;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return answer;
|
||||
@@ -402,8 +433,8 @@ adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int
|
||||
// the actual digits. we then compare the big integer representations
|
||||
// of both, and use that to direct rounding.
|
||||
template <typename T, typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa digit_comp(parsed_number_string_t<UC>& num, adjusted_mantissa am) noexcept {
|
||||
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
|
||||
digit_comp(parsed_number_string_t<UC> &num, adjusted_mantissa am) noexcept {
|
||||
// remove the invalid exponent bias
|
||||
am.power2 -= invalid_am_bias;
|
||||
|
||||
|
||||
@@ -6,43 +6,54 @@
|
||||
|
||||
namespace fast_float {
|
||||
/**
|
||||
* This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
|
||||
* a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale.
|
||||
* The resulting floating-point value is the closest floating-point values (using either float or double),
|
||||
* using the "round to even" convention for values that would otherwise fall right in-between two values.
|
||||
* That is, we provide exact parsing according to the IEEE standard.
|
||||
* This function parses the character sequence [first,last) for a number. It
|
||||
* parses floating-point numbers expecting a locale-indepent format equivalent
|
||||
* to what is used by std::strtod in the default ("C") locale. The resulting
|
||||
* floating-point value is the closest floating-point values (using either float
|
||||
* or double), using the "round to even" convention for values that would
|
||||
* otherwise fall right in-between two values. That is, we provide exact parsing
|
||||
* according to the IEEE standard.
|
||||
*
|
||||
* Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
|
||||
* parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
|
||||
* `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
|
||||
* Given a successful parse, the pointer (`ptr`) in the returned value is set to
|
||||
* point right after the parsed number, and the `value` referenced is set to the
|
||||
* parsed value. In case of error, the returned `ec` contains a representative
|
||||
* error, otherwise the default (`std::errc()`) value is stored.
|
||||
*
|
||||
* The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
|
||||
* The implementation does not throw and does not allocate memory (e.g., with
|
||||
* `new` or `malloc`).
|
||||
*
|
||||
* Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
|
||||
* the type `fast_float::chars_format`. It is a bitset value: we check whether
|
||||
* `fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
|
||||
* to determine whether we allow the fixed point and scientific notation respectively.
|
||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
* Like the C++17 standard, the `fast_float::from_chars` functions take an
|
||||
* optional last argument of the type `fast_float::chars_format`. It is a bitset
|
||||
* value: we check whether `fmt & fast_float::chars_format::fixed` and `fmt &
|
||||
* fast_float::chars_format::scientific` are set to determine whether we allow
|
||||
* the fixed point and scientific notation respectively. The default is
|
||||
* `fast_float::chars_format::general` which allows both `fixed` and
|
||||
* `scientific`.
|
||||
*/
|
||||
template<typename T, typename UC = char, typename = FASTFLOAT_ENABLE_IF(is_supported_float_type<T>())>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||
template <typename T, typename UC = char,
|
||||
typename = FASTFLOAT_ENABLE_IF(is_supported_float_type<T>::value)>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars(UC const *first, UC const *last, T &value,
|
||||
chars_format fmt = chars_format::general) noexcept;
|
||||
|
||||
/**
|
||||
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||
* Both for floating-point types and integer types.
|
||||
*/
|
||||
template<typename T, typename UC = char>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
T &value, parse_options_t<UC> options) noexcept;
|
||||
template <typename T, typename UC = char>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept;
|
||||
|
||||
/**
|
||||
* from_chars for integer types.
|
||||
*/
|
||||
template <typename T, typename UC = char, typename = FASTFLOAT_ENABLE_IF(!is_supported_float_type<T>())>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars(UC const * first, UC const * last, T& value, int base = 10) noexcept;
|
||||
* from_chars for integer types.
|
||||
*/
|
||||
template <typename T, typename UC = char,
|
||||
typename = FASTFLOAT_ENABLE_IF(is_supported_integer_type<T>::value)>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept;
|
||||
|
||||
} // namespace fast_float
|
||||
|
||||
#include "parse_number.h"
|
||||
#endif // FASTFLOAT_FAST_FLOAT_H
|
||||
|
||||
1326
3rdparty/fast_float/include/fast_float/fast_table.h
vendored
1326
3rdparty/fast_float/include/fast_float/fast_table.h
vendored
File diff suppressed because it is too large
Load Diff
1147
3rdparty/fast_float/include/fast_float/float_common.h
vendored
1147
3rdparty/fast_float/include/fast_float/float_common.h
vendored
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,8 @@
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <system_error>
|
||||
namespace fast_float {
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
namespace detail {
|
||||
/**
|
||||
@@ -20,45 +20,49 @@ namespace detail {
|
||||
* strings a null-free and fixed.
|
||||
**/
|
||||
template <typename T, typename UC>
|
||||
from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14
|
||||
parse_infnan(UC const * first, UC const * last, T &value) noexcept {
|
||||
from_chars_result_t<UC>
|
||||
FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last,
|
||||
T &value, chars_format fmt) noexcept {
|
||||
from_chars_result_t<UC> answer{};
|
||||
answer.ptr = first;
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
bool minusSign = false;
|
||||
if (*first == UC('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
|
||||
minusSign = true;
|
||||
++first;
|
||||
// assume first < last, so dereference without checks;
|
||||
bool const minusSign = (*first == UC('-'));
|
||||
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
if ((*first == UC('-')) ||
|
||||
(uint64_t(fmt & chars_format::allow_leading_plus) &&
|
||||
(*first == UC('+')))) {
|
||||
++first;
|
||||
}
|
||||
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||
if (*first == UC('+')) {
|
||||
++first;
|
||||
}
|
||||
#endif
|
||||
if (last - first >= 3) {
|
||||
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
|
||||
answer.ptr = (first += 3);
|
||||
value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
|
||||
// Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
|
||||
if(first != last && *first == UC('(')) {
|
||||
for(UC const * ptr = first + 1; ptr != last; ++ptr) {
|
||||
value = minusSign ? -std::numeric_limits<T>::quiet_NaN()
|
||||
: std::numeric_limits<T>::quiet_NaN();
|
||||
// Check for possible nan(n-char-seq-opt), C++17 20.19.3.7,
|
||||
// C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
|
||||
if (first != last && *first == UC('(')) {
|
||||
for (UC const *ptr = first + 1; ptr != last; ++ptr) {
|
||||
if (*ptr == UC(')')) {
|
||||
answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
|
||||
break;
|
||||
}
|
||||
else if(!((UC('a') <= *ptr && *ptr <= UC('z')) || (UC('A') <= *ptr && *ptr <= UC('Z')) || (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
|
||||
} else if (!((UC('a') <= *ptr && *ptr <= UC('z')) ||
|
||||
(UC('A') <= *ptr && *ptr <= UC('Z')) ||
|
||||
(UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
|
||||
break; // forbidden char, not nan(n-char-seq-opt)
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
|
||||
if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
|
||||
if ((last - first >= 8) &&
|
||||
fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
|
||||
answer.ptr = first + 8;
|
||||
} else {
|
||||
answer.ptr = first + 3;
|
||||
}
|
||||
value = minusSign ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity();
|
||||
value = minusSign ? -std::numeric_limits<T>::infinity()
|
||||
: std::numeric_limits<T>::infinity();
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
@@ -86,73 +90,71 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
||||
// However, it is expected to be much faster than the fegetround()
|
||||
// function call.
|
||||
//
|
||||
// The volatile keywoard prevents the compiler from computing the function
|
||||
// The volatile keyword prevents the compiler from computing the function
|
||||
// at compile-time.
|
||||
// There might be other ways to prevent compile-time optimizations (e.g., asm).
|
||||
// The value does not need to be std::numeric_limits<float>::min(), any small
|
||||
// value so that 1 + x should round to 1 would do (after accounting for excess
|
||||
// precision, as in 387 instructions).
|
||||
static volatile float fmin = std::numeric_limits<float>::min();
|
||||
// There might be other ways to prevent compile-time optimizations (e.g.,
|
||||
// asm). The value does not need to be std::numeric_limits<float>::min(), any
|
||||
// small value so that 1 + x should round to 1 would do (after accounting for
|
||||
// excess precision, as in 387 instructions).
|
||||
static float volatile fmin = std::numeric_limits<float>::min();
|
||||
float fmini = fmin; // we copy it so that it gets loaded at most once.
|
||||
//
|
||||
// Explanation:
|
||||
// Only when fegetround() == FE_TONEAREST do we have that
|
||||
// fmin + 1.0f == 1.0f - fmin.
|
||||
//
|
||||
// FE_UPWARD:
|
||||
// fmin + 1.0f > 1
|
||||
// 1.0f - fmin == 1
|
||||
//
|
||||
// FE_DOWNWARD or FE_TOWARDZERO:
|
||||
// fmin + 1.0f == 1
|
||||
// 1.0f - fmin < 1
|
||||
//
|
||||
// Note: This may fail to be accurate if fast-math has been
|
||||
// enabled, as rounding conventions may not apply.
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
# pragma warning(push)
|
||||
// todo: is there a VS warning?
|
||||
// see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
//
|
||||
// Explanation:
|
||||
// Only when fegetround() == FE_TONEAREST do we have that
|
||||
// fmin + 1.0f == 1.0f - fmin.
|
||||
//
|
||||
// FE_UPWARD:
|
||||
// fmin + 1.0f > 1
|
||||
// 1.0f - fmin == 1
|
||||
//
|
||||
// FE_DOWNWARD or FE_TOWARDZERO:
|
||||
// fmin + 1.0f == 1
|
||||
// 1.0f - fmin < 1
|
||||
//
|
||||
// Note: This may fail to be accurate if fast-math has been
|
||||
// enabled, as rounding conventions may not apply.
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(push)
|
||||
// todo: is there a VS warning?
|
||||
// see
|
||||
// https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
return (fmini + 1.0f == 1.0f - fmini);
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
# pragma warning(pop)
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(pop)
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
struct from_chars_caller
|
||||
{
|
||||
template <typename T> struct from_chars_caller {
|
||||
template <typename UC>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
static from_chars_result_t<UC> call(UC const * first, UC const * last,
|
||||
T &value, parse_options_t<UC> options) noexcept {
|
||||
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
|
||||
call(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
return from_chars_advanced(first, last, value, options);
|
||||
}
|
||||
};
|
||||
|
||||
#if __STDCPP_FLOAT32_T__ == 1
|
||||
template <>
|
||||
struct from_chars_caller<std::float32_t>
|
||||
{
|
||||
#ifdef __STDCPP_FLOAT32_T__
|
||||
template <> struct from_chars_caller<std::float32_t> {
|
||||
template <typename UC>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
static from_chars_result_t<UC> call(UC const * first, UC const * last,
|
||||
std::float32_t &value, parse_options_t<UC> options) noexcept{
|
||||
// if std::float32_t is defined, and we are in C++23 mode; macro set for float32;
|
||||
// set value to float due to equivalence between float and float32_t
|
||||
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
|
||||
call(UC const *first, UC const *last, std::float32_t &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
// if std::float32_t is defined, and we are in C++23 mode; macro set for
|
||||
// float32; set value to float due to equivalence between float and
|
||||
// float32_t
|
||||
float val;
|
||||
auto ret = from_chars_advanced(first, last, val, options);
|
||||
value = val;
|
||||
@@ -161,16 +163,15 @@ struct from_chars_caller<std::float32_t>
|
||||
};
|
||||
#endif
|
||||
|
||||
#if __STDCPP_FLOAT64_T__ == 1
|
||||
template <>
|
||||
struct from_chars_caller<std::float64_t>
|
||||
{
|
||||
#ifdef __STDCPP_FLOAT64_T__
|
||||
template <> struct from_chars_caller<std::float64_t> {
|
||||
template <typename UC>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
static from_chars_result_t<UC> call(UC const * first, UC const * last,
|
||||
std::float64_t &value, parse_options_t<UC> options) noexcept{
|
||||
// if std::float64_t is defined, and we are in C++23 mode; macro set for float64;
|
||||
// set value as double due to equivalence between double and float64_t
|
||||
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
|
||||
call(UC const *first, UC const *last, std::float64_t &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
// if std::float64_t is defined, and we are in C++23 mode; macro set for
|
||||
// float64; set value as double due to equivalence between double and
|
||||
// float64_t
|
||||
double val;
|
||||
auto ret = from_chars_advanced(first, last, val, options);
|
||||
value = val;
|
||||
@@ -179,52 +180,40 @@ struct from_chars_caller<std::float64_t>
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T, typename UC, typename>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||
return from_chars_caller<T>::call(first, last, value, parse_options_t<UC>(fmt));
|
||||
template <typename T, typename UC, typename>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars(UC const *first, UC const *last, T &value,
|
||||
chars_format fmt /*= chars_format::general*/) noexcept {
|
||||
return from_chars_caller<T>::call(first, last, value,
|
||||
parse_options_t<UC>(fmt));
|
||||
}
|
||||
|
||||
template<typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
T &value, parse_options_t<UC> options) noexcept {
|
||||
/**
|
||||
* This function overload takes parsed_number_string_t structure that is created
|
||||
* and populated either by from_chars_advanced function taking chars range and
|
||||
* parsing options or other parsing custom function implemented by user.
|
||||
*/
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
||||
|
||||
static_assert (is_supported_float_type<T>(), "only some floating-point types are supported");
|
||||
static_assert (is_supported_char_type<UC>(), "only char, wchar_t, char16_t and char32_t are supported");
|
||||
static_assert(is_supported_float_type<T>::value,
|
||||
"only some floating-point types are supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
|
||||
first++;
|
||||
}
|
||||
#endif
|
||||
if (first == last) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options);
|
||||
if (!pns.valid) {
|
||||
if (options.format & chars_format::no_infnan) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
} else {
|
||||
return detail::parse_infnan(first, last, value);
|
||||
}
|
||||
}
|
||||
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
answer.ptr = pns.lastmatch;
|
||||
// The implementation of the Clinger's fast path is convoluted because
|
||||
// we want round-to-nearest in all cases, irrespective of the rounding mode
|
||||
// selected on the thread.
|
||||
// We proceed optimistically, assuming that detail::rounds_to_nearest() returns
|
||||
// true.
|
||||
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && !pns.too_many_digits) {
|
||||
// We proceed optimistically, assuming that detail::rounds_to_nearest()
|
||||
// returns true.
|
||||
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
|
||||
pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
|
||||
!pns.too_many_digits) {
|
||||
// Unfortunately, the conventional Clinger's fast path is only possible
|
||||
// when the system rounds to the nearest float.
|
||||
//
|
||||
@@ -232,68 +221,179 @@ from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
// We could check it first (before the previous branch), but
|
||||
// there might be performance advantages at having the check
|
||||
// be last.
|
||||
if(!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
||||
if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
||||
// We have that fegetround() == FE_TONEAREST.
|
||||
// Next is Clinger's fast path.
|
||||
if (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
||||
if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
|
||||
value = T(pns.mantissa);
|
||||
if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
|
||||
else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
|
||||
if (pns.negative) { value = -value; }
|
||||
if (pns.exponent < 0) {
|
||||
value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
|
||||
} else {
|
||||
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
|
||||
}
|
||||
if (pns.negative) {
|
||||
value = -value;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
} else {
|
||||
// We do not have that fegetround() == FE_TONEAREST.
|
||||
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's proposal
|
||||
if (pns.exponent >= 0 && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
|
||||
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
|
||||
// proposal
|
||||
if (pns.exponent >= 0 &&
|
||||
pns.mantissa <=
|
||||
binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
|
||||
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
|
||||
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
||||
if(pns.mantissa == 0) {
|
||||
if (pns.mantissa == 0) {
|
||||
value = pns.negative ? T(-0.) : T(0.);
|
||||
return answer;
|
||||
}
|
||||
#endif
|
||||
value = T(pns.mantissa) * binary_format<T>::exact_power_of_ten(pns.exponent);
|
||||
if (pns.negative) { value = -value; }
|
||||
value = T(pns.mantissa) *
|
||||
binary_format<T>::exact_power_of_ten(pns.exponent);
|
||||
if (pns.negative) {
|
||||
value = -value;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
}
|
||||
adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||
if(pns.too_many_digits && am.power2 >= 0) {
|
||||
if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
|
||||
adjusted_mantissa am =
|
||||
compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||
if (pns.too_many_digits && am.power2 >= 0) {
|
||||
if (am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
|
||||
am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||
}
|
||||
}
|
||||
// If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa) and we have an invalid power (am.power2 < 0),
|
||||
// then we need to go the long way around again. This is very uncommon.
|
||||
if(am.power2 < 0) { am = digit_comp<T>(pns, am); }
|
||||
// If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa)
|
||||
// and we have an invalid power (am.power2 < 0), then we need to go the long
|
||||
// way around again. This is very uncommon.
|
||||
if (am.power2 < 0) {
|
||||
am = digit_comp<T>(pns, am);
|
||||
}
|
||||
to_float(pns.negative, am, value);
|
||||
// Test for over/underflow.
|
||||
if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || am.power2 == binary_format<T>::infinite_power()) {
|
||||
if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) ||
|
||||
am.power2 == binary_format<T>::infinite_power()) {
|
||||
answer.ec = std::errc::result_out_of_range;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_float_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
|
||||
template <typename T, typename UC, typename>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars(UC const* first, UC const* last, T& value, int base) noexcept {
|
||||
static_assert (is_supported_char_type<UC>(), "only char, wchar_t, char16_t and char32_t are supported");
|
||||
static_assert(is_supported_float_type<T>::value,
|
||||
"only some floating-point types are supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
|
||||
first++;
|
||||
if (uint64_t(fmt & chars_format::skip_white_space)) {
|
||||
while ((first != last) && fast_float::is_space(*first)) {
|
||||
first++;
|
||||
}
|
||||
}
|
||||
if (first == last) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
parsed_number_string_t<UC> pns =
|
||||
uint64_t(fmt & detail::basic_json_fmt)
|
||||
? parse_number_string<true, UC>(first, last, options)
|
||||
: parse_number_string<false, UC>(first, last, options);
|
||||
if (!pns.valid) {
|
||||
if (uint64_t(fmt & chars_format::no_infnan)) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
} else {
|
||||
return detail::parse_infnan(first, last, value, fmt);
|
||||
}
|
||||
}
|
||||
|
||||
// call overload that takes parsed_number_string_t directly.
|
||||
return from_chars_advanced(pns, value);
|
||||
}
|
||||
|
||||
template <typename T, typename UC, typename>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
|
||||
|
||||
static_assert(is_supported_integer_type<T>::value,
|
||||
"only integer types are supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
parse_options_t<UC> options;
|
||||
options.base = base;
|
||||
return from_chars_advanced(first, last, value, options);
|
||||
}
|
||||
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_int_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
|
||||
static_assert(is_supported_integer_type<T>::value,
|
||||
"only integer types are supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
int const base = options.base;
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
if (uint64_t(fmt & chars_format::skip_white_space)) {
|
||||
while ((first != last) && fast_float::is_space(*first)) {
|
||||
first++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (first == last || base < 2 || base > 36) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
return parse_int_string(first, last, value, base);
|
||||
|
||||
return parse_int_string(first, last, value, options);
|
||||
}
|
||||
|
||||
template <size_t TypeIx> struct from_chars_advanced_caller {
|
||||
static_assert(TypeIx > 0, "unsupported type");
|
||||
};
|
||||
|
||||
template <> struct from_chars_advanced_caller<1> {
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
|
||||
call(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
return from_chars_float_advanced(first, last, value, options);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct from_chars_advanced_caller<2> {
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
|
||||
call(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
return from_chars_int_advanced(first, last, value, options);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
return from_chars_advanced_caller<
|
||||
size_t(is_supported_float_type<T>::value) +
|
||||
2 * size_t(is_supported_integer_type<T>::value)>::call(first, last, value,
|
||||
options);
|
||||
}
|
||||
|
||||
} // namespace fast_float
|
||||
|
||||
8
3rdparty/googletest/README.md
vendored
8
3rdparty/googletest/README.md
vendored
@@ -9,7 +9,7 @@ GoogleTest now follows the
|
||||
We recommend
|
||||
[updating to the latest commit in the `main` branch as often as possible](https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#what-is-live-at-head-and-how-do-i-do-it).
|
||||
We do publish occasional semantic versions, tagged with
|
||||
`v${major}.${minor}.${patch}` (e.g. `v1.15.0`).
|
||||
`v${major}.${minor}.${patch}` (e.g. `v1.16.0`).
|
||||
|
||||
#### Documentation Updates
|
||||
|
||||
@@ -17,12 +17,12 @@ Our documentation is now live on GitHub Pages at
|
||||
https://google.github.io/googletest/. We recommend browsing the documentation on
|
||||
GitHub Pages rather than directly in the repository.
|
||||
|
||||
#### Release 1.15.0
|
||||
#### Release 1.16.0
|
||||
|
||||
[Release 1.15.0](https://github.com/google/googletest/releases/tag/v1.15.0) is
|
||||
[Release 1.16.0](https://github.com/google/googletest/releases/tag/v1.16.0) is
|
||||
now available.
|
||||
|
||||
The 1.15.x branch requires at least C++14.
|
||||
The 1.16.x branch requires at least C++14.
|
||||
|
||||
#### Continuous Integration
|
||||
|
||||
|
||||
@@ -1493,6 +1493,7 @@ class DoAllAction<FinalAction> {
|
||||
// providing a call operator because even with a particular set of arguments
|
||||
// they don't have a fixed return type.
|
||||
|
||||
// We support conversion to OnceAction whenever the sub-action does.
|
||||
template <typename R, typename... Args,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<FinalAction, OnceAction<R(Args...)>>::value,
|
||||
@@ -1501,6 +1502,21 @@ class DoAllAction<FinalAction> {
|
||||
return std::move(final_action_);
|
||||
}
|
||||
|
||||
// We also support conversion to OnceAction whenever the sub-action supports
|
||||
// conversion to Action (since any Action can also be a OnceAction).
|
||||
template <
|
||||
typename R, typename... Args,
|
||||
typename std::enable_if<
|
||||
conjunction<
|
||||
negation<
|
||||
std::is_convertible<FinalAction, OnceAction<R(Args...)>>>,
|
||||
std::is_convertible<FinalAction, Action<R(Args...)>>>::value,
|
||||
int>::type = 0>
|
||||
operator OnceAction<R(Args...)>() && { // NOLINT
|
||||
return Action<R(Args...)>(std::move(final_action_));
|
||||
}
|
||||
|
||||
// We support conversion to Action whenever the sub-action does.
|
||||
template <
|
||||
typename R, typename... Args,
|
||||
typename std::enable_if<
|
||||
@@ -1580,16 +1596,16 @@ class DoAllAction<InitialAction, OtherActions...>
|
||||
: Base({}, std::forward<U>(other_actions)...),
|
||||
initial_action_(std::forward<T>(initial_action)) {}
|
||||
|
||||
template <typename R, typename... Args,
|
||||
typename std::enable_if<
|
||||
conjunction<
|
||||
// Both the initial action and the rest must support
|
||||
// conversion to OnceAction.
|
||||
std::is_convertible<
|
||||
InitialAction,
|
||||
OnceAction<void(InitialActionArgType<Args>...)>>,
|
||||
std::is_convertible<Base, OnceAction<R(Args...)>>>::value,
|
||||
int>::type = 0>
|
||||
// We support conversion to OnceAction whenever both the initial action and
|
||||
// the rest support conversion to OnceAction.
|
||||
template <
|
||||
typename R, typename... Args,
|
||||
typename std::enable_if<
|
||||
conjunction<std::is_convertible<
|
||||
InitialAction,
|
||||
OnceAction<void(InitialActionArgType<Args>...)>>,
|
||||
std::is_convertible<Base, OnceAction<R(Args...)>>>::value,
|
||||
int>::type = 0>
|
||||
operator OnceAction<R(Args...)>() && { // NOLINT
|
||||
// Return an action that first calls the initial action with arguments
|
||||
// filtered through InitialActionArgType, then forwards arguments directly
|
||||
@@ -1612,12 +1628,34 @@ class DoAllAction<InitialAction, OtherActions...>
|
||||
};
|
||||
}
|
||||
|
||||
// We also support conversion to OnceAction whenever the initial action
|
||||
// supports conversion to Action (since any Action can also be a OnceAction).
|
||||
//
|
||||
// The remaining sub-actions must also be compatible, but we don't need to
|
||||
// special case them because the base class deals with them.
|
||||
template <
|
||||
typename R, typename... Args,
|
||||
typename std::enable_if<
|
||||
conjunction<
|
||||
negation<std::is_convertible<
|
||||
InitialAction,
|
||||
OnceAction<void(InitialActionArgType<Args>...)>>>,
|
||||
std::is_convertible<InitialAction,
|
||||
Action<void(InitialActionArgType<Args>...)>>,
|
||||
std::is_convertible<Base, OnceAction<R(Args...)>>>::value,
|
||||
int>::type = 0>
|
||||
operator OnceAction<R(Args...)>() && { // NOLINT
|
||||
return DoAll(
|
||||
Action<void(InitialActionArgType<Args>...)>(std::move(initial_action_)),
|
||||
std::move(static_cast<Base&>(*this)));
|
||||
}
|
||||
|
||||
// We support conversion to Action whenever both the initial action and the
|
||||
// rest support conversion to Action.
|
||||
template <
|
||||
typename R, typename... Args,
|
||||
typename std::enable_if<
|
||||
conjunction<
|
||||
// Both the initial action and the rest must support conversion to
|
||||
// Action.
|
||||
std::is_convertible<const InitialAction&,
|
||||
Action<void(InitialActionArgType<Args>...)>>,
|
||||
std::is_convertible<const Base&, Action<R(Args...)>>>::value,
|
||||
@@ -1665,8 +1703,9 @@ template <size_t k>
|
||||
struct ReturnArgAction {
|
||||
template <typename... Args,
|
||||
typename = typename std::enable_if<(k < sizeof...(Args))>::type>
|
||||
auto operator()(Args&&... args) const -> decltype(std::get<k>(
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))) {
|
||||
auto operator()(Args&&... args) const
|
||||
-> decltype(std::get<k>(
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))) {
|
||||
return std::get<k>(std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -408,13 +408,22 @@ class MatcherCastImpl<T, Matcher<U>> {
|
||||
}
|
||||
|
||||
private:
|
||||
class Impl : public MatcherInterface<T> {
|
||||
// If it's possible to implicitly convert a `const T&` to U, then `Impl` can
|
||||
// take that as input to avoid a copy. Otherwise, such as when `T` is a
|
||||
// non-const reference type or a type explicitly constructible only from a
|
||||
// non-const reference, then `Impl` must use `T` as-is (potentially copying).
|
||||
using ImplArgT =
|
||||
typename std::conditional<std::is_convertible<const T&, const U&>::value,
|
||||
const T&, T>::type;
|
||||
|
||||
class Impl : public MatcherInterface<ImplArgT> {
|
||||
public:
|
||||
explicit Impl(const Matcher<U>& source_matcher)
|
||||
: source_matcher_(source_matcher) {}
|
||||
|
||||
// We delegate the matching logic to the source matcher.
|
||||
bool MatchAndExplain(T x, MatchResultListener* listener) const override {
|
||||
bool MatchAndExplain(ImplArgT x,
|
||||
MatchResultListener* listener) const override {
|
||||
using FromType = typename std::remove_cv<typename std::remove_pointer<
|
||||
typename std::remove_reference<T>::type>::type>::type;
|
||||
using ToType = typename std::remove_cv<typename std::remove_pointer<
|
||||
@@ -431,9 +440,8 @@ class MatcherCastImpl<T, Matcher<U>> {
|
||||
|
||||
// Do the cast to `U` explicitly if necessary.
|
||||
// Otherwise, let implicit conversions do the trick.
|
||||
using CastType =
|
||||
typename std::conditional<std::is_convertible<T&, const U&>::value,
|
||||
T&, U>::type;
|
||||
using CastType = typename std::conditional<
|
||||
std::is_convertible<ImplArgT&, const U&>::value, ImplArgT&, U>::type;
|
||||
|
||||
return source_matcher_.MatchAndExplain(static_cast<CastType>(x),
|
||||
listener);
|
||||
@@ -528,18 +536,16 @@ inline Matcher<T> SafeMatcherCast(const M& polymorphic_matcher_or_value) {
|
||||
// safely convert a Matcher<U> to a Matcher<T> (i.e. Matcher is
|
||||
// contravariant): just keep a copy of the original Matcher<U>, convert the
|
||||
// argument from type T to U, and then pass it to the underlying Matcher<U>.
|
||||
// The only exception is when U is a reference and T is not, as the
|
||||
// The only exception is when U is a non-const reference and T is not, as the
|
||||
// underlying Matcher<U> may be interested in the argument's address, which
|
||||
// is not preserved in the conversion from T to U.
|
||||
// cannot be preserved in the conversion from T to U (since a copy of the input
|
||||
// T argument would be required to provide a non-const reference U).
|
||||
template <typename T, typename U>
|
||||
inline Matcher<T> SafeMatcherCast(const Matcher<U>& matcher) {
|
||||
// Enforce that T can be implicitly converted to U.
|
||||
static_assert(std::is_convertible<const T&, const U&>::value,
|
||||
"T must be implicitly convertible to U");
|
||||
// Enforce that we are not converting a non-reference type T to a reference
|
||||
// type U.
|
||||
static_assert(std::is_reference<T>::value || !std::is_reference<U>::value,
|
||||
"cannot convert non reference arg to reference");
|
||||
"T must be implicitly convertible to U (and T must be a "
|
||||
"non-const reference if U is a non-const reference)");
|
||||
// In case both T and U are arithmetic types, enforce that the
|
||||
// conversion is not lossy.
|
||||
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT;
|
||||
@@ -561,6 +567,11 @@ Matcher<T> A();
|
||||
// and MUST NOT BE USED IN USER CODE!!!
|
||||
namespace internal {
|
||||
|
||||
// Used per go/ranked-overloads for dispatching.
|
||||
struct Rank0 {};
|
||||
struct Rank1 : Rank0 {};
|
||||
using HighestRank = Rank1;
|
||||
|
||||
// If the explanation is not empty, prints it to the ostream.
|
||||
inline void PrintIfNotEmpty(const std::string& explanation,
|
||||
::std::ostream* os) {
|
||||
@@ -1300,34 +1311,48 @@ class AllOfMatcherImpl : public MatcherInterface<const T&> {
|
||||
|
||||
bool MatchAndExplain(const T& x,
|
||||
MatchResultListener* listener) const override {
|
||||
// If either matcher1_ or matcher2_ doesn't match x, we only need
|
||||
// to explain why one of them fails.
|
||||
// This method uses matcher's explanation when explaining the result.
|
||||
// However, if matcher doesn't provide one, this method uses matcher's
|
||||
// description.
|
||||
std::string all_match_result;
|
||||
|
||||
for (size_t i = 0; i < matchers_.size(); ++i) {
|
||||
for (const Matcher<T>& matcher : matchers_) {
|
||||
StringMatchResultListener slistener;
|
||||
if (matchers_[i].MatchAndExplain(x, &slistener)) {
|
||||
if (all_match_result.empty()) {
|
||||
all_match_result = slistener.str();
|
||||
// Return explanation for first failed matcher.
|
||||
if (!matcher.MatchAndExplain(x, &slistener)) {
|
||||
const std::string explanation = slistener.str();
|
||||
if (!explanation.empty()) {
|
||||
*listener << explanation;
|
||||
} else {
|
||||
std::string result = slistener.str();
|
||||
if (!result.empty()) {
|
||||
all_match_result += ", and ";
|
||||
all_match_result += result;
|
||||
}
|
||||
*listener << "which doesn't match (" << Describe(matcher) << ")";
|
||||
}
|
||||
} else {
|
||||
*listener << slistener.str();
|
||||
return false;
|
||||
}
|
||||
// Keep track of explanations in case all matchers succeed.
|
||||
std::string explanation = slistener.str();
|
||||
if (explanation.empty()) {
|
||||
explanation = Describe(matcher);
|
||||
}
|
||||
if (all_match_result.empty()) {
|
||||
all_match_result = explanation;
|
||||
} else {
|
||||
if (!explanation.empty()) {
|
||||
all_match_result += ", and ";
|
||||
all_match_result += explanation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we need to explain why *both* of them match.
|
||||
*listener << all_match_result;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Returns matcher description as a string.
|
||||
std::string Describe(const Matcher<T>& matcher) const {
|
||||
StringMatchResultListener listener;
|
||||
matcher.DescribeTo(listener.stream());
|
||||
return listener.str();
|
||||
}
|
||||
const std::vector<Matcher<T>> matchers_;
|
||||
};
|
||||
|
||||
@@ -1405,34 +1430,55 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> {
|
||||
|
||||
bool MatchAndExplain(const T& x,
|
||||
MatchResultListener* listener) const override {
|
||||
// This method uses matcher's explanation when explaining the result.
|
||||
// However, if matcher doesn't provide one, this method uses matcher's
|
||||
// description.
|
||||
std::string no_match_result;
|
||||
|
||||
// If either matcher1_ or matcher2_ matches x, we just need to
|
||||
// explain why *one* of them matches.
|
||||
for (size_t i = 0; i < matchers_.size(); ++i) {
|
||||
for (const Matcher<T>& matcher : matchers_) {
|
||||
StringMatchResultListener slistener;
|
||||
if (matchers_[i].MatchAndExplain(x, &slistener)) {
|
||||
*listener << slistener.str();
|
||||
return true;
|
||||
} else {
|
||||
if (no_match_result.empty()) {
|
||||
no_match_result = slistener.str();
|
||||
// Return explanation for first match.
|
||||
if (matcher.MatchAndExplain(x, &slistener)) {
|
||||
const std::string explanation = slistener.str();
|
||||
if (!explanation.empty()) {
|
||||
*listener << explanation;
|
||||
} else {
|
||||
std::string result = slistener.str();
|
||||
if (!result.empty()) {
|
||||
no_match_result += ", and ";
|
||||
no_match_result += result;
|
||||
}
|
||||
*listener << "which matches (" << Describe(matcher) << ")";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Keep track of explanations in case there is no match.
|
||||
std::string explanation = slistener.str();
|
||||
if (explanation.empty()) {
|
||||
explanation = DescribeNegation(matcher);
|
||||
}
|
||||
if (no_match_result.empty()) {
|
||||
no_match_result = explanation;
|
||||
} else {
|
||||
if (!explanation.empty()) {
|
||||
no_match_result += ", and ";
|
||||
no_match_result += explanation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we need to explain why *both* of them fail.
|
||||
*listener << no_match_result;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
// Returns matcher description as a string.
|
||||
std::string Describe(const Matcher<T>& matcher) const {
|
||||
StringMatchResultListener listener;
|
||||
matcher.DescribeTo(listener.stream());
|
||||
return listener.str();
|
||||
}
|
||||
|
||||
std::string DescribeNegation(const Matcher<T>& matcher) const {
|
||||
StringMatchResultListener listener;
|
||||
matcher.DescribeNegationTo(listener.stream());
|
||||
return listener.str();
|
||||
}
|
||||
|
||||
const std::vector<Matcher<T>> matchers_;
|
||||
};
|
||||
|
||||
@@ -1483,7 +1529,7 @@ class SomeOfArrayMatcher {
|
||||
}
|
||||
|
||||
private:
|
||||
const ::std::vector<T> matchers_;
|
||||
const std::vector<std::remove_const_t<T>> matchers_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -2235,6 +2281,9 @@ class ResultOfMatcher {
|
||||
class Impl : public MatcherInterface<T> {
|
||||
using ResultType = decltype(CallableTraits<Callable>::template Invoke<T>(
|
||||
std::declval<CallableStorageType>(), std::declval<T>()));
|
||||
using InnerType = std::conditional_t<
|
||||
std::is_lvalue_reference<ResultType>::value,
|
||||
const typename std::remove_reference<ResultType>::type&, ResultType>;
|
||||
|
||||
public:
|
||||
template <typename M>
|
||||
@@ -2242,7 +2291,7 @@ class ResultOfMatcher {
|
||||
const CallableStorageType& callable, const M& matcher)
|
||||
: result_description_(result_description),
|
||||
callable_(callable),
|
||||
matcher_(MatcherCast<ResultType>(matcher)) {}
|
||||
matcher_(MatcherCast<InnerType>(matcher)) {}
|
||||
|
||||
void DescribeTo(::std::ostream* os) const override {
|
||||
if (result_description_.empty()) {
|
||||
@@ -2272,7 +2321,7 @@ class ResultOfMatcher {
|
||||
// takes a non-const reference as argument.
|
||||
// Also, specifying template argument explicitly is needed because T could
|
||||
// be a non-const reference (e.g. Matcher<Uncopyable&>).
|
||||
ResultType result =
|
||||
InnerType result =
|
||||
CallableTraits<Callable>::template Invoke<T>(callable_, obj);
|
||||
return MatchPrintAndExplain(result, matcher_, listener);
|
||||
}
|
||||
@@ -2285,7 +2334,7 @@ class ResultOfMatcher {
|
||||
// use stateful callables with ResultOf(), which doesn't guarantee
|
||||
// how many times the callable will be invoked.
|
||||
mutable CallableStorageType callable_;
|
||||
const Matcher<ResultType> matcher_;
|
||||
const Matcher<InnerType> matcher_;
|
||||
}; // class Impl
|
||||
|
||||
const std::string result_description_;
|
||||
@@ -2920,10 +2969,6 @@ class EachMatcher {
|
||||
const M inner_matcher_;
|
||||
};
|
||||
|
||||
// Use go/ranked-overloads for dispatching.
|
||||
struct Rank0 {};
|
||||
struct Rank1 : Rank0 {};
|
||||
|
||||
namespace pair_getters {
|
||||
using std::get;
|
||||
template <typename T>
|
||||
@@ -3255,6 +3300,11 @@ auto UnpackStructImpl(const T& t, std::make_index_sequence<19>, char) {
|
||||
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s] = t;
|
||||
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s);
|
||||
}
|
||||
template <typename T>
|
||||
auto UnpackStructImpl(const T& u, std::make_index_sequence<20>, char) {
|
||||
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t] = u;
|
||||
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t);
|
||||
}
|
||||
#endif // defined(__cpp_structured_bindings)
|
||||
|
||||
template <size_t I, typename T>
|
||||
@@ -3769,7 +3819,7 @@ class UnorderedElementsAreArrayMatcher {
|
||||
|
||||
private:
|
||||
UnorderedMatcherRequire::Flags match_flags_;
|
||||
::std::vector<T> matchers_;
|
||||
std::vector<std::remove_const_t<T>> matchers_;
|
||||
};
|
||||
|
||||
// Implements ElementsAreArray().
|
||||
@@ -3790,7 +3840,7 @@ class ElementsAreArrayMatcher {
|
||||
}
|
||||
|
||||
private:
|
||||
const ::std::vector<T> matchers_;
|
||||
const std::vector<std::remove_const_t<T>> matchers_;
|
||||
};
|
||||
|
||||
// Given a 2-tuple matcher tm of type Tuple2Matcher and a value second
|
||||
@@ -3877,6 +3927,21 @@ GTEST_API_ std::string FormatMatcherDescription(
|
||||
bool negation, const char* matcher_name,
|
||||
const std::vector<const char*>& param_names, const Strings& param_values);
|
||||
|
||||
// Overloads to support `OptionalMatcher` being used with a type that either
|
||||
// supports implicit conversion to bool or a `has_value()` method.
|
||||
template <typename Optional>
|
||||
auto IsOptionalEngaged(const Optional& optional,
|
||||
Rank1) -> decltype(!!optional) {
|
||||
// The use of double-negation here is to preserve historical behavior where
|
||||
// the matcher used `operator!` rather than directly using `operator bool`.
|
||||
return !static_cast<bool>(!optional);
|
||||
}
|
||||
template <typename Optional>
|
||||
auto IsOptionalEngaged(const Optional& optional,
|
||||
Rank0) -> decltype(!optional.has_value()) {
|
||||
return optional.has_value();
|
||||
}
|
||||
|
||||
// Implements a matcher that checks the value of a optional<> type variable.
|
||||
template <typename ValueMatcher>
|
||||
class OptionalMatcher {
|
||||
@@ -3909,7 +3974,7 @@ class OptionalMatcher {
|
||||
|
||||
bool MatchAndExplain(Optional optional,
|
||||
MatchResultListener* listener) const override {
|
||||
if (!optional) {
|
||||
if (!IsOptionalEngaged(optional, HighestRank())) {
|
||||
*listener << "which is not engaged";
|
||||
return false;
|
||||
}
|
||||
@@ -4742,9 +4807,10 @@ Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) {
|
||||
|
||||
// Supports the Pointwise(m, {a, b, c}) syntax.
|
||||
template <typename TupleMatcher, typename T>
|
||||
inline internal::PointwiseMatcher<TupleMatcher, std::vector<T>> Pointwise(
|
||||
const TupleMatcher& tuple_matcher, std::initializer_list<T> rhs) {
|
||||
return Pointwise(tuple_matcher, std::vector<T>(rhs));
|
||||
inline internal::PointwiseMatcher<TupleMatcher,
|
||||
std::vector<std::remove_const_t<T>>>
|
||||
Pointwise(const TupleMatcher& tuple_matcher, std::initializer_list<T> rhs) {
|
||||
return Pointwise(tuple_matcher, std::vector<std::remove_const_t<T>>(rhs));
|
||||
}
|
||||
|
||||
// UnorderedPointwise(pair_matcher, rhs) matches an STL-style
|
||||
@@ -4906,7 +4972,7 @@ inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf(
|
||||
// - {1} matches IsSubsetOf({Gt(0), Lt(0)}), as 1 matches Gt(0).
|
||||
// - {1, -1} matches IsSubsetOf({Lt(0), Gt(0)}), as 1 matches Gt(0) and -1
|
||||
// matches Lt(0).
|
||||
// - {1, 2} doesn't matches IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both
|
||||
// - {1, 2} doesn't match IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both
|
||||
// match Gt(0). The reason is that different matchers must be used for
|
||||
// elements in different slots of the container.
|
||||
//
|
||||
@@ -5231,9 +5297,10 @@ inline InnerMatcher AllArgs(const InnerMatcher& matcher) {
|
||||
}
|
||||
|
||||
// Returns a matcher that matches the value of an optional<> type variable.
|
||||
// The matcher implementation only uses '!arg' and requires that the optional<>
|
||||
// type has a 'value_type' member type and that '*arg' is of type 'value_type'
|
||||
// and is printable using 'PrintToString'. It is compatible with
|
||||
// The matcher implementation only uses '!arg' (or 'arg.has_value()' if '!arg`
|
||||
// isn't a valid expression) and requires that the optional<> type has a
|
||||
// 'value_type' member type and that '*arg' is of type 'value_type' and is
|
||||
// printable using 'PrintToString'. It is compatible with
|
||||
// std::optional/std::experimental::optional.
|
||||
// Note that to compare an optional type variable against nullopt you should
|
||||
// use Eq(nullopt) and not Eq(Optional(nullopt)). The latter implies that the
|
||||
|
||||
@@ -601,9 +601,10 @@ template <std::size_t index, typename... Params>
|
||||
struct InvokeArgumentAction {
|
||||
template <typename... Args,
|
||||
typename = typename std::enable_if<(index < sizeof...(Args))>::type>
|
||||
auto operator()(Args &&...args) const -> decltype(internal::InvokeArgument(
|
||||
std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...)),
|
||||
std::declval<const Params &>()...)) {
|
||||
auto operator()(Args &&...args) const
|
||||
-> decltype(internal::InvokeArgument(
|
||||
std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...)),
|
||||
std::declval<const Params &>()...)) {
|
||||
internal::FlatTuple<Args &&...> args_tuple(FlatTupleConstructTag{},
|
||||
std::forward<Args>(args)...);
|
||||
return params.Apply([&](const Params &...unpacked_params) {
|
||||
|
||||
@@ -868,7 +868,7 @@ class GTEST_API_ ExpectationBase {
|
||||
Clause last_clause_;
|
||||
mutable bool action_count_checked_; // Under mutex_.
|
||||
mutable Mutex mutex_; // Protects action_count_checked_.
|
||||
}; // class ExpectationBase
|
||||
}; // class ExpectationBase
|
||||
|
||||
template <typename F>
|
||||
class TypedExpectation;
|
||||
@@ -1838,9 +1838,8 @@ R FunctionMocker<R(Args...)>::InvokeWith(ArgumentTuple&& args)
|
||||
// Doing so slows down compilation dramatically because the *constructor* of
|
||||
// std::function<T> is re-instantiated with different template
|
||||
// parameters each time.
|
||||
const UninterestingCallCleanupHandler report_uninteresting_call = {
|
||||
reaction, ss
|
||||
};
|
||||
const UninterestingCallCleanupHandler report_uninteresting_call = {reaction,
|
||||
ss};
|
||||
|
||||
return PerformActionAndPrintResult(nullptr, std::move(args), ss.str(), ss);
|
||||
}
|
||||
@@ -1890,8 +1889,7 @@ R FunctionMocker<R(Args...)>::InvokeWith(ArgumentTuple&& args)
|
||||
// std::function<T> is re-instantiated with different template
|
||||
// parameters each time.
|
||||
const FailureCleanupHandler handle_failures = {
|
||||
ss, why, loc, untyped_expectation, found, is_excessive
|
||||
};
|
||||
ss, why, loc, untyped_expectation, found, is_excessive};
|
||||
|
||||
return PerformActionAndPrintResult(untyped_action, std::move(args), ss.str(),
|
||||
ss);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
@@ -53,12 +53,12 @@ class BetweenCardinalityImpl : public CardinalityInterface {
|
||||
: min_(min >= 0 ? min : 0), max_(max >= min_ ? max : min_) {
|
||||
std::stringstream ss;
|
||||
if (min < 0) {
|
||||
ss << "The invocation lower bound must be >= 0, "
|
||||
<< "but is actually " << min << ".";
|
||||
ss << "The invocation lower bound must be >= 0, " << "but is actually "
|
||||
<< min << ".";
|
||||
internal::Expect(false, __FILE__, __LINE__, ss.str());
|
||||
} else if (max < 0) {
|
||||
ss << "The invocation upper bound must be >= 0, "
|
||||
<< "but is actually " << max << ".";
|
||||
ss << "The invocation upper bound must be >= 0, " << "but is actually "
|
||||
<< max << ".";
|
||||
internal::Expect(false, __FILE__, __LINE__, ss.str());
|
||||
} else if (min > max) {
|
||||
ss << "The invocation upper bound (" << max
|
||||
|
||||
2
3rdparty/googletest/googletest/README.md
vendored
2
3rdparty/googletest/googletest/README.md
vendored
@@ -25,7 +25,7 @@ When building GoogleTest as a standalone project, the typical workflow starts
|
||||
with
|
||||
|
||||
```
|
||||
git clone https://github.com/google/googletest.git -b v1.15.0
|
||||
git clone https://github.com/google/googletest.git -b v1.16.0
|
||||
cd googletest # Main directory of the cloned repository.
|
||||
mkdir build # Create a directory to hold the build output.
|
||||
cd build
|
||||
|
||||
@@ -67,10 +67,10 @@ namespace testing {
|
||||
// To implement a matcher Foo for type T, define:
|
||||
// 1. a class FooMatcherMatcher that implements the matcher interface:
|
||||
// using is_gtest_matcher = void;
|
||||
// bool MatchAndExplain(const T&, std::ostream*);
|
||||
// bool MatchAndExplain(const T&, std::ostream*) const;
|
||||
// (MatchResultListener* can also be used instead of std::ostream*)
|
||||
// void DescribeTo(std::ostream*);
|
||||
// void DescribeNegationTo(std::ostream*);
|
||||
// void DescribeTo(std::ostream*) const;
|
||||
// void DescribeNegationTo(std::ostream*) const;
|
||||
//
|
||||
// 2. a factory function that creates a Matcher<T> object from a
|
||||
// FooMatcherMatcher.
|
||||
|
||||
@@ -126,6 +126,10 @@
|
||||
#include <span> // NOLINT
|
||||
#endif // GTEST_INTERNAL_HAS_STD_SPAN
|
||||
|
||||
#if GTEST_INTERNAL_HAS_COMPARE_LIB
|
||||
#include <compare> // NOLINT
|
||||
#endif // GTEST_INTERNAL_HAS_COMPARE_LIB
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Definitions in the internal* namespaces are subject to change without notice.
|
||||
@@ -782,6 +786,41 @@ void PrintTo(const std::shared_ptr<T>& ptr, std::ostream* os) {
|
||||
(PrintSmartPointer<T>)(ptr, os, 0);
|
||||
}
|
||||
|
||||
#if GTEST_INTERNAL_HAS_COMPARE_LIB
|
||||
template <typename T>
|
||||
void PrintOrderingHelper(T ordering, std::ostream* os) {
|
||||
if (ordering == T::less) {
|
||||
*os << "(less)";
|
||||
} else if (ordering == T::greater) {
|
||||
*os << "(greater)";
|
||||
} else if (ordering == T::equivalent) {
|
||||
*os << "(equivalent)";
|
||||
} else {
|
||||
*os << "(unknown ordering)";
|
||||
}
|
||||
}
|
||||
|
||||
inline void PrintTo(std::strong_ordering ordering, std::ostream* os) {
|
||||
if (ordering == std::strong_ordering::equal) {
|
||||
*os << "(equal)";
|
||||
} else {
|
||||
PrintOrderingHelper(ordering, os);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PrintTo(std::partial_ordering ordering, std::ostream* os) {
|
||||
if (ordering == std::partial_ordering::unordered) {
|
||||
*os << "(unordered)";
|
||||
} else {
|
||||
PrintOrderingHelper(ordering, os);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PrintTo(std::weak_ordering ordering, std::ostream* os) {
|
||||
PrintOrderingHelper(ordering, os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Helper function for printing a tuple. T must be instantiated with
|
||||
// a tuple type.
|
||||
template <typename T>
|
||||
|
||||
@@ -2533,4 +2533,12 @@ using Variant = ::std::variant<T...>;
|
||||
#define GTEST_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1
|
||||
#endif
|
||||
|
||||
#if (defined(__cpp_lib_three_way_comparison) || \
|
||||
(GTEST_INTERNAL_HAS_INCLUDE(<compare>) && \
|
||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L))
|
||||
#define GTEST_INTERNAL_HAS_COMPARE_LIB 1
|
||||
#else
|
||||
#define GTEST_INTERNAL_HAS_COMPARE_LIB 0
|
||||
#endif
|
||||
|
||||
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
|
||||
|
||||
105
3rdparty/googletest/googletest/src/gtest.cc
vendored
105
3rdparty/googletest/googletest/src/gtest.cc
vendored
@@ -1660,10 +1660,25 @@ std::string GetBoolAssertionFailureMessage(
|
||||
return msg.GetString();
|
||||
}
|
||||
|
||||
// Helper function for implementing ASSERT_NEAR.
|
||||
// Helper function for implementing ASSERT_NEAR. Treats infinity as a specific
|
||||
// value, such that comparing infinity to infinity is equal, the distance
|
||||
// between -infinity and +infinity is infinity, and infinity <= infinity is
|
||||
// true.
|
||||
AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2,
|
||||
const char* abs_error_expr, double val1,
|
||||
double val2, double abs_error) {
|
||||
// We want to return success when the two values are infinity and at least
|
||||
// one of the following is true:
|
||||
// * The values are the same-signed infinity.
|
||||
// * The error limit itself is infinity.
|
||||
// This is done here so that we don't end up with a NaN when calculating the
|
||||
// difference in values.
|
||||
if (std::isinf(val1) && std::isinf(val2) &&
|
||||
(std::signbit(val1) == std::signbit(val2) ||
|
||||
(abs_error > 0.0 && std::isinf(abs_error)))) {
|
||||
return AssertionSuccess();
|
||||
}
|
||||
|
||||
const double diff = fabs(val1 - val2);
|
||||
if (diff <= abs_error) return AssertionSuccess();
|
||||
|
||||
@@ -3974,6 +3989,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
|
||||
static void OutputXmlTestSuiteForTestResult(::std::ostream* stream,
|
||||
const TestResult& result);
|
||||
|
||||
// Streams a test case XML stanza containing the given test result.
|
||||
//
|
||||
// Requires: result.Failed()
|
||||
static void OutputXmlTestCaseForTestResult(::std::ostream* stream,
|
||||
const TestResult& result);
|
||||
|
||||
// Streams an XML representation of a TestResult object.
|
||||
static void OutputXmlTestResult(::std::ostream* stream,
|
||||
const TestResult& result);
|
||||
@@ -3991,16 +4012,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
|
||||
static void PrintXmlUnitTest(::std::ostream* stream,
|
||||
const UnitTest& unit_test);
|
||||
|
||||
// Produces a string representing the test properties in a result as space
|
||||
// delimited XML attributes based on the property key="value" pairs.
|
||||
// When the std::string is not empty, it includes a space at the beginning,
|
||||
// to delimit this attribute from prior attributes.
|
||||
static std::string TestPropertiesAsXmlAttributes(const TestResult& result);
|
||||
|
||||
// Streams an XML representation of the test properties of a TestResult
|
||||
// object.
|
||||
static void OutputXmlTestProperties(std::ostream* stream,
|
||||
const TestResult& result);
|
||||
const TestResult& result,
|
||||
const std::string& indent);
|
||||
|
||||
// The output file.
|
||||
const std::string output_file_;
|
||||
@@ -4221,6 +4237,15 @@ void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult(
|
||||
FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
|
||||
*stream << ">";
|
||||
|
||||
OutputXmlTestCaseForTestResult(stream, result);
|
||||
|
||||
// Complete the test suite.
|
||||
*stream << " </testsuite>\n";
|
||||
}
|
||||
|
||||
// Streams a test case XML stanza containing the given test result.
|
||||
void XmlUnitTestResultPrinter::OutputXmlTestCaseForTestResult(
|
||||
::std::ostream* stream, const TestResult& result) {
|
||||
// Output the boilerplate for a minimal test case with a single test.
|
||||
*stream << " <testcase";
|
||||
OutputXmlAttribute(stream, "testcase", "name", "");
|
||||
@@ -4235,9 +4260,6 @@ void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult(
|
||||
|
||||
// Output the actual test result.
|
||||
OutputXmlTestResult(stream, result);
|
||||
|
||||
// Complete the test suite.
|
||||
*stream << " </testsuite>\n";
|
||||
}
|
||||
|
||||
// Prints an XML representation of a TestInfo object.
|
||||
@@ -4328,7 +4350,7 @@ void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream,
|
||||
if (failures == 0 && skips == 0) {
|
||||
*stream << ">\n";
|
||||
}
|
||||
OutputXmlTestProperties(stream, result);
|
||||
OutputXmlTestProperties(stream, result, /*indent=*/" ");
|
||||
*stream << " </testcase>\n";
|
||||
}
|
||||
}
|
||||
@@ -4357,13 +4379,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream,
|
||||
OutputXmlAttribute(
|
||||
stream, kTestsuite, "timestamp",
|
||||
FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp()));
|
||||
*stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result());
|
||||
}
|
||||
*stream << ">\n";
|
||||
OutputXmlTestProperties(stream, test_suite.ad_hoc_test_result(),
|
||||
/*indent=*/" ");
|
||||
for (int i = 0; i < test_suite.total_test_count(); ++i) {
|
||||
if (test_suite.GetTestInfo(i)->is_reportable())
|
||||
OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
|
||||
}
|
||||
if (test_suite.ad_hoc_test_result().Failed()) {
|
||||
OutputXmlTestCaseForTestResult(stream, test_suite.ad_hoc_test_result());
|
||||
}
|
||||
|
||||
*stream << " </" << kTestsuite << ">\n";
|
||||
}
|
||||
|
||||
@@ -4393,11 +4420,12 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
|
||||
OutputXmlAttribute(stream, kTestsuites, "random_seed",
|
||||
StreamableToString(unit_test.random_seed()));
|
||||
}
|
||||
*stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
|
||||
|
||||
OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
|
||||
*stream << ">\n";
|
||||
|
||||
OutputXmlTestProperties(stream, unit_test.ad_hoc_test_result(),
|
||||
/*indent=*/" ");
|
||||
for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
|
||||
if (unit_test.GetTestSuite(i)->reportable_test_count() > 0)
|
||||
PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i));
|
||||
@@ -4434,21 +4462,8 @@ void XmlUnitTestResultPrinter::PrintXmlTestsList(
|
||||
*stream << "</" << kTestsuites << ">\n";
|
||||
}
|
||||
|
||||
// Produces a string representing the test properties in a result as space
|
||||
// delimited XML attributes based on the property key="value" pairs.
|
||||
std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
|
||||
const TestResult& result) {
|
||||
Message attributes;
|
||||
for (int i = 0; i < result.test_property_count(); ++i) {
|
||||
const TestProperty& property = result.GetTestProperty(i);
|
||||
attributes << " " << property.key() << "=" << "\""
|
||||
<< EscapeXmlAttribute(property.value()) << "\"";
|
||||
}
|
||||
return attributes.GetString();
|
||||
}
|
||||
|
||||
void XmlUnitTestResultPrinter::OutputXmlTestProperties(
|
||||
std::ostream* stream, const TestResult& result) {
|
||||
std::ostream* stream, const TestResult& result, const std::string& indent) {
|
||||
const std::string kProperties = "properties";
|
||||
const std::string kProperty = "property";
|
||||
|
||||
@@ -4456,15 +4471,15 @@ void XmlUnitTestResultPrinter::OutputXmlTestProperties(
|
||||
return;
|
||||
}
|
||||
|
||||
*stream << " <" << kProperties << ">\n";
|
||||
*stream << indent << "<" << kProperties << ">\n";
|
||||
for (int i = 0; i < result.test_property_count(); ++i) {
|
||||
const TestProperty& property = result.GetTestProperty(i);
|
||||
*stream << " <" << kProperty;
|
||||
*stream << indent << " <" << kProperty;
|
||||
*stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\"";
|
||||
*stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\"";
|
||||
*stream << "/>\n";
|
||||
}
|
||||
*stream << " </" << kProperties << ">\n";
|
||||
*stream << indent << "</" << kProperties << ">\n";
|
||||
}
|
||||
|
||||
// End XmlUnitTestResultPrinter
|
||||
@@ -4503,6 +4518,12 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener {
|
||||
static void OutputJsonTestSuiteForTestResult(::std::ostream* stream,
|
||||
const TestResult& result);
|
||||
|
||||
// Streams a test case JSON stanza containing the given test result.
|
||||
//
|
||||
// Requires: result.Failed()
|
||||
static void OutputJsonTestCaseForTestResult(::std::ostream* stream,
|
||||
const TestResult& result);
|
||||
|
||||
// Streams a JSON representation of a TestResult object.
|
||||
static void OutputJsonTestResult(::std::ostream* stream,
|
||||
const TestResult& result);
|
||||
@@ -4673,6 +4694,15 @@ void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult(
|
||||
}
|
||||
*stream << Indent(6) << "\"testsuite\": [\n";
|
||||
|
||||
OutputJsonTestCaseForTestResult(stream, result);
|
||||
|
||||
// Finish the test suite.
|
||||
*stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}";
|
||||
}
|
||||
|
||||
// Streams a test case JSON stanza containing the given test result.
|
||||
void JsonUnitTestResultPrinter::OutputJsonTestCaseForTestResult(
|
||||
::std::ostream* stream, const TestResult& result) {
|
||||
// Output the boilerplate for a new test case.
|
||||
*stream << Indent(8) << "{\n";
|
||||
OutputJsonKey(stream, "testcase", "name", "", Indent(10));
|
||||
@@ -4689,9 +4719,6 @@ void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult(
|
||||
|
||||
// Output the actual test result.
|
||||
OutputJsonTestResult(stream, result);
|
||||
|
||||
// Finish the test suite.
|
||||
*stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}";
|
||||
}
|
||||
|
||||
// Prints a JSON representation of a TestInfo object.
|
||||
@@ -4836,6 +4863,16 @@ void JsonUnitTestResultPrinter::PrintJsonTestSuite(
|
||||
OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
|
||||
}
|
||||
}
|
||||
|
||||
// If there was a failure in the test suite setup or teardown include that in
|
||||
// the output.
|
||||
if (test_suite.ad_hoc_test_result().Failed()) {
|
||||
if (comma) {
|
||||
*stream << ",\n";
|
||||
}
|
||||
OutputJsonTestCaseForTestResult(stream, test_suite.ad_hoc_test_result());
|
||||
}
|
||||
|
||||
*stream << "\n" << kIndent << "]\n" << Indent(4) << "}";
|
||||
}
|
||||
|
||||
|
||||
1
3rdparty/imgui/CMakeLists.txt
vendored
1
3rdparty/imgui/CMakeLists.txt
vendored
@@ -19,6 +19,7 @@ add_library(imgui
|
||||
target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_include_directories(imgui PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype)
|
||||
target_link_libraries(imgui PUBLIC plutosvg::plutosvg)
|
||||
|
||||
# Needed for macOS compile.
|
||||
set_property(TARGET imgui PROPERTY CXX_STANDARD 17)
|
||||
|
||||
2
3rdparty/imgui/imgui.vcxproj
vendored
2
3rdparty/imgui/imgui.vcxproj
vendored
@@ -33,7 +33,7 @@
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;$(SolutionDir)deps\include\freetype2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;$(SolutionDir)deps\include\freetype2;$(SolutionDir)deps\include\plutovg;$(SolutionDir)deps\include\plutosvg;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
5
3rdparty/imgui/include/imconfig.h
vendored
5
3rdparty/imgui/include/imconfig.h
vendored
@@ -88,8 +88,7 @@
|
||||
|
||||
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg.
|
||||
// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions.
|
||||
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
|
||||
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||
@@ -111,7 +110,7 @@
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
|
||||
119
3rdparty/imgui/include/imgui.h
vendored
119
3rdparty/imgui/include/imgui.h
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91.9b
|
||||
// (headers)
|
||||
|
||||
// Help:
|
||||
@@ -28,8 +28,8 @@
|
||||
|
||||
// Library Version
|
||||
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
|
||||
#define IMGUI_VERSION "1.91.8"
|
||||
#define IMGUI_VERSION_NUM 19180
|
||||
#define IMGUI_VERSION "1.91.9b"
|
||||
#define IMGUI_VERSION_NUM 19191
|
||||
#define IMGUI_HAS_TABLE
|
||||
|
||||
/*
|
||||
@@ -37,6 +37,7 @@
|
||||
Index of this file:
|
||||
// [SECTION] Header mess
|
||||
// [SECTION] Forward declarations and basic types
|
||||
// [SECTION] Texture identifier (ImTextureID)
|
||||
// [SECTION] Dear ImGui end-user API functions
|
||||
// [SECTION] Flags & Enumerations
|
||||
// [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs)
|
||||
@@ -250,22 +251,6 @@ typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: f
|
||||
typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport
|
||||
typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild()
|
||||
|
||||
// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type]
|
||||
// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file.
|
||||
// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details.
|
||||
// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators.
|
||||
// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings)
|
||||
#ifndef ImTextureID
|
||||
typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that)
|
||||
#endif
|
||||
|
||||
// ImDrawIdx: vertex index. [Compile-time configurable type]
|
||||
// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).
|
||||
// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.
|
||||
#ifndef ImDrawIdx
|
||||
typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)
|
||||
#endif
|
||||
|
||||
// Character types
|
||||
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
|
||||
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
|
||||
@@ -315,6 +300,19 @@ struct ImVec4
|
||||
};
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Texture identifier (ImTextureID)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type]
|
||||
// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file.
|
||||
// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details.
|
||||
// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators.
|
||||
// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings)
|
||||
#ifndef ImTextureID
|
||||
typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Dear ImGui end-user API functions
|
||||
// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!)
|
||||
@@ -544,7 +542,7 @@ namespace ImGui
|
||||
IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2);
|
||||
IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text()
|
||||
IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1);
|
||||
IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line
|
||||
IMGUI_API void SeparatorText(const char* label); // currently: formatted text with a horizontal line
|
||||
|
||||
// Widgets: Main
|
||||
// - Most widgets return true when the value has been changed or when pressed/selected
|
||||
@@ -566,9 +564,10 @@ namespace ImGui
|
||||
// Widgets: Images
|
||||
// - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
|
||||
// - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above.
|
||||
// - Note that Image() may add +2.0f to provided size if a border is visible, ImageButton() adds style.FramePadding*2.0f to provided size.
|
||||
// - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side.
|
||||
// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified.
|
||||
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0));
|
||||
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1));
|
||||
IMGUI_API void ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1));
|
||||
IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1));
|
||||
|
||||
// Widgets: Combo Box (Dropdown)
|
||||
@@ -906,7 +905,7 @@ namespace ImGui
|
||||
IMGUI_API void PopClipRect();
|
||||
|
||||
// Focus, Activation
|
||||
IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of of a newly appearing window.
|
||||
IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a newly appearing window.
|
||||
IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget.
|
||||
|
||||
// Keyboard/Gamepad Navigation
|
||||
@@ -974,7 +973,7 @@ namespace ImGui
|
||||
IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)?
|
||||
IMGUI_API bool IsKeyChordPressed(ImGuiKeyChord key_chord); // was key chord (mods + key) pressed, e.g. you can pass 'ImGuiMod_Ctrl | ImGuiKey_S' as a key-chord. This doesn't do any routing or focus check, please consider using Shortcut() function instead.
|
||||
IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate
|
||||
IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared.
|
||||
IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names are provided for debugging purpose and are not meant to be saved persistently nor compared.
|
||||
IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call.
|
||||
|
||||
// Inputs Utilities: Shortcut Testing & Routing [BETA]
|
||||
@@ -1177,7 +1176,7 @@ enum ImGuiInputTextFlags_
|
||||
ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
|
||||
|
||||
// Elide display / Alignment
|
||||
ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only!
|
||||
ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only!
|
||||
|
||||
// Callback features
|
||||
ImGuiInputTextFlags_CallbackCompletion = 1 << 18, // Callback on pressing TAB (for completion handling)
|
||||
@@ -1492,6 +1491,7 @@ enum ImGuiKey : int
|
||||
ImGuiKey_KeypadEqual,
|
||||
ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back"
|
||||
ImGuiKey_AppForward,
|
||||
ImGuiKey_Oem102, // Non-US backslash.
|
||||
|
||||
// Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION
|
||||
// (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets)
|
||||
@@ -1714,6 +1714,7 @@ enum ImGuiStyleVar_
|
||||
ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding
|
||||
ImGuiStyleVar_GrabMinSize, // float GrabMinSize
|
||||
ImGuiStyleVar_GrabRounding, // float GrabRounding
|
||||
ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize
|
||||
ImGuiStyleVar_TabRounding, // float TabRounding
|
||||
ImGuiStyleVar_TabBorderSize, // float TabBorderSize
|
||||
ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize
|
||||
@@ -1833,6 +1834,8 @@ enum ImGuiMouseCursor_
|
||||
ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window
|
||||
ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window
|
||||
ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks)
|
||||
ImGuiMouseCursor_Wait, // When waiting for something to process/load.
|
||||
ImGuiMouseCursor_Progress, // When waiting for something to process/load, but application is still interactive.
|
||||
ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle.
|
||||
ImGuiMouseCursor_COUNT
|
||||
};
|
||||
@@ -2146,6 +2149,7 @@ struct ImGuiStyle
|
||||
ImVec2 WindowPadding; // Padding within a window.
|
||||
float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
|
||||
float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
|
||||
float WindowBorderHoverPadding; // Hit-testing extent outside/inside resizing border. Also extend determination of hovered window. Generally meaningfully larger than WindowBorderSize to make it easy to reach borders.
|
||||
ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints().
|
||||
ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.
|
||||
ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left.
|
||||
@@ -2167,9 +2171,11 @@ struct ImGuiStyle
|
||||
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
|
||||
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
|
||||
float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
|
||||
float ImageBorderSize; // Thickness of border around Image() calls.
|
||||
float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
|
||||
float TabBorderSize; // Thickness of border around tabs.
|
||||
float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
|
||||
float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width.
|
||||
float TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected.
|
||||
float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
|
||||
float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar.
|
||||
float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees).
|
||||
@@ -2188,6 +2194,8 @@ struct ImGuiStyle
|
||||
bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).
|
||||
float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
|
||||
float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
|
||||
|
||||
// Colors
|
||||
ImVec4 Colors[ImGuiCol_COUNT];
|
||||
|
||||
// Behaviors
|
||||
@@ -2200,6 +2208,11 @@ struct ImGuiStyle
|
||||
|
||||
IMGUI_API ImGuiStyle();
|
||||
IMGUI_API void ScaleAllSizes(float scale_factor);
|
||||
|
||||
// Obsolete names
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
// TabMinWidthForCloseButton = TabCloseButtonMinWidthUnselected // Renamed in 1.91.9.
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -2310,7 +2323,8 @@ struct ImGuiIO
|
||||
// - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers.
|
||||
// - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead!
|
||||
// - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
|
||||
bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message when multiple items have conflicting identifiers.
|
||||
bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message popup when multiple items have conflicting identifiers.
|
||||
bool ConfigDebugHighlightIdConflictsShowItemPicker;//=true // Show "Item Picker" button in aforementioned popup.
|
||||
|
||||
// Tools to test correct Begin/End and BeginChild/EndChild behaviors.
|
||||
// - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX()
|
||||
@@ -2420,7 +2434,7 @@ struct ImGuiIO
|
||||
bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.
|
||||
bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window.
|
||||
bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system.
|
||||
bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a ctrl-click that spawned a simulated right click
|
||||
bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a Ctrl+click that spawned a simulated right click
|
||||
float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
|
||||
float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
|
||||
float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds)
|
||||
@@ -2585,10 +2599,11 @@ struct ImGuiTextBuffer
|
||||
ImGuiTextBuffer() { }
|
||||
inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }
|
||||
const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; }
|
||||
const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator
|
||||
const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator
|
||||
int size() const { return Buf.Size ? Buf.Size - 1 : 0; }
|
||||
bool empty() const { return Buf.Size <= 1; }
|
||||
void clear() { Buf.clear(); }
|
||||
void resize(int size) { if (Buf.Size > size) Buf.Data[size] = 0; Buf.resize(size ? size + 1 : 0, 0); } // Similar to resize(0) on ImVector: empty string but don't free buffer.
|
||||
void reserve(int capacity) { Buf.reserve(capacity); }
|
||||
const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; }
|
||||
IMGUI_API void append(const char* str, const char* str_end = NULL);
|
||||
@@ -2940,6 +2955,13 @@ struct ImGuiSelectionExternalStorage
|
||||
#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32)
|
||||
#endif
|
||||
|
||||
// ImDrawIdx: vertex index. [Compile-time configurable type]
|
||||
// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).
|
||||
// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.
|
||||
#ifndef ImDrawIdx
|
||||
typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)
|
||||
#endif
|
||||
|
||||
// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h]
|
||||
// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering,
|
||||
// you can poke into the draw list for that! Draw callback may be useful for example to:
|
||||
@@ -3131,7 +3153,7 @@ struct ImDrawList
|
||||
|
||||
// General polygon
|
||||
// - Only simple polygons are supported by filling functions (no self-intersections, no holes).
|
||||
// - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience fo user but not used by main library.
|
||||
// - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library.
|
||||
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
|
||||
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col);
|
||||
IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col);
|
||||
@@ -3257,11 +3279,12 @@ struct ImFontConfig
|
||||
int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
|
||||
int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis.
|
||||
float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height).
|
||||
ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now.
|
||||
//ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED IN 1.91.9: use GlyphExtraAdvanceX)
|
||||
ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input.
|
||||
const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list).
|
||||
float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
|
||||
float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs
|
||||
float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this.
|
||||
unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure.
|
||||
float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future.
|
||||
float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered.
|
||||
@@ -3281,7 +3304,7 @@ struct ImFontGlyph
|
||||
unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops)
|
||||
unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering.
|
||||
unsigned int Codepoint : 30; // 0x0000..0x10FFFF
|
||||
float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in)
|
||||
float AdvanceX; // Horizontal distance to advance layout with
|
||||
float X0, Y0, X1, Y1; // Glyph corners
|
||||
float U0, V0, U1, V1; // Texture coordinates
|
||||
};
|
||||
@@ -3405,12 +3428,12 @@ struct ImFontAtlas
|
||||
|
||||
// [Internal]
|
||||
IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const;
|
||||
IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
|
||||
|
||||
//-------------------------------------------
|
||||
// Members
|
||||
//-------------------------------------------
|
||||
|
||||
// Input
|
||||
ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_)
|
||||
ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.
|
||||
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
|
||||
@@ -3430,7 +3453,7 @@ struct ImFontAtlas
|
||||
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel
|
||||
ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.
|
||||
ImVector<ImFontAtlasCustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas.
|
||||
ImVector<ImFontConfig> ConfigData; // Configuration data
|
||||
ImVector<ImFontConfig> Sources; // Source/configuration data
|
||||
ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines
|
||||
|
||||
// [Internal] Font builder
|
||||
@@ -3442,8 +3465,8 @@ struct ImFontAtlas
|
||||
int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines
|
||||
|
||||
// [Obsolete]
|
||||
//typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+
|
||||
//typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
|
||||
//typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+
|
||||
//typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
|
||||
};
|
||||
|
||||
// Font runtime data and rendering
|
||||
@@ -3458,13 +3481,13 @@ struct ImFont
|
||||
// [Internal] Members: Hot ~28/40 bytes (for RenderText loop)
|
||||
ImVector<ImU16> IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point.
|
||||
ImVector<ImFontGlyph> Glyphs; // 12-16 // out // All glyphs.
|
||||
const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar)
|
||||
ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar)
|
||||
|
||||
// [Internal] Members: Cold ~32/40 bytes
|
||||
// Conceptually ConfigData[] is the list of font sources merged to create this font.
|
||||
// Conceptually Sources[] is the list of font sources merged to create this font.
|
||||
ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into
|
||||
const ImFontConfig* ConfigData; // 4-8 // in // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances
|
||||
short ConfigDataCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont.
|
||||
ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances
|
||||
short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont.
|
||||
short EllipsisCharCount; // 1 // out // 1 or 3
|
||||
ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...').
|
||||
ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?')
|
||||
@@ -3479,12 +3502,13 @@ struct ImFont
|
||||
// Methods
|
||||
IMGUI_API ImFont();
|
||||
IMGUI_API ~ImFont();
|
||||
IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c);
|
||||
IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c);
|
||||
IMGUI_API ImFontGlyph* FindGlyph(ImWchar c);
|
||||
IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c);
|
||||
float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }
|
||||
bool IsLoaded() const { return ContainerAtlas != NULL; }
|
||||
const char* GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; }
|
||||
const char* GetDebugName() const { return Sources ? Sources->Name : "<unknown>"; }
|
||||
|
||||
// [Internal] Don't use!
|
||||
// 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
|
||||
// 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.
|
||||
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8
|
||||
@@ -3498,7 +3522,6 @@ struct ImFont
|
||||
IMGUI_API void GrowIndex(int new_size);
|
||||
IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
|
||||
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
|
||||
IMGUI_API void SetGlyphVisible(ImWchar c, bool visible);
|
||||
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
|
||||
};
|
||||
|
||||
@@ -3552,7 +3575,7 @@ struct ImGuiPlatformIO
|
||||
IMGUI_API ImGuiPlatformIO();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Interface with OS and Platform backend
|
||||
// Input - Interface with OS and Platform backend (most common stuff)
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Optional: Access OS clipboard
|
||||
@@ -3562,7 +3585,7 @@ struct ImGuiPlatformIO
|
||||
void* Platform_ClipboardUserData;
|
||||
|
||||
// Optional: Open link/folder/file in OS Shell
|
||||
// (default to use ShellExecuteA() on Windows, system() on Linux/Mac)
|
||||
// (default to use ShellExecuteW() on Windows, system() on Linux/Mac)
|
||||
bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path);
|
||||
void* Platform_OpenInShellUserData;
|
||||
|
||||
@@ -3577,7 +3600,7 @@ struct ImGuiPlatformIO
|
||||
ImWchar Platform_LocaleDecimalPoint; // '.'
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Interface with Renderer Backend
|
||||
// Input - Interface with Renderer Backend
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure.
|
||||
@@ -3603,6 +3626,8 @@ struct ImGuiPlatformImeData
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
namespace ImGui
|
||||
{
|
||||
// OBSOLETED in 1.91.9 (from February 2025)
|
||||
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- border_col was removed in favor of ImGuiCol_ImageBorder.
|
||||
// OBSOLETED in 1.91.0 (from July 2024)
|
||||
static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); }
|
||||
static inline void PopButtonRepeat() { PopItemFlag(); }
|
||||
|
||||
116
3rdparty/imgui/include/imgui_internal.h
vendored
116
3rdparty/imgui/include/imgui_internal.h
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91.9b
|
||||
// (internal structures/api)
|
||||
|
||||
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
|
||||
@@ -14,6 +14,7 @@ Index of this file:
|
||||
// [SECTION] Macros
|
||||
// [SECTION] Generic helpers
|
||||
// [SECTION] ImDrawList support
|
||||
// [SECTION] Style support
|
||||
// [SECTION] Data types support
|
||||
// [SECTION] Widgets support: flags, enums, data structures
|
||||
// [SECTION] Popup support
|
||||
@@ -145,7 +146,6 @@ struct ImGuiBoxSelectState; // Box-selection state (currently used by mu
|
||||
struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiContext; // Main Dear ImGui context
|
||||
struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
|
||||
struct ImGuiDataVarInfo; // Variable information (e.g. to access style variables from an enum)
|
||||
struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
|
||||
struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function.
|
||||
struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery
|
||||
@@ -166,6 +166,7 @@ struct ImGuiOldColumns; // Storage data for a columns set for legacy
|
||||
struct ImGuiPopupData; // Storage for current popup stack
|
||||
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
|
||||
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
|
||||
struct ImGuiStyleVarInfo; // Style variable information (e.g. to access style variables from an enum)
|
||||
struct ImGuiTabBar; // Storage for a tab bar
|
||||
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
|
||||
struct ImGuiTable; // Storage for a table
|
||||
@@ -366,11 +367,14 @@ static inline void ImQsort(void* base, size_t count, size_t size_of_element
|
||||
IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
|
||||
|
||||
// Helpers: Bit manipulation
|
||||
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
|
||||
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
|
||||
static inline unsigned int ImCountSetBits(unsigned int v) { unsigned int count = 0; while (v > 0) { v = v & (v - 1); count++; } return count; }
|
||||
|
||||
// Helpers: String
|
||||
#define ImStrlen strlen
|
||||
#define ImMemchr memchr
|
||||
IMGUI_API int ImStricmp(const char* str1, const char* str2); // Case insensitive compare.
|
||||
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); // Case insensitive compare to a certain count.
|
||||
IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); // Copy to a certain count and always zero terminate (strncpy doesn't).
|
||||
@@ -786,8 +790,9 @@ struct IMGUI_API ImDrawListSharedData
|
||||
float FontScale; // Current/default font scale (== FontSize / Font->FontSize)
|
||||
float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo()
|
||||
float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc
|
||||
ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
|
||||
float InitialFringeScale; // Initial scale to apply to AA fringe
|
||||
ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
|
||||
ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
|
||||
ImVector<ImVec2> TempBuffer; // Temporary write buffer
|
||||
|
||||
// Lookup tables
|
||||
@@ -808,17 +813,38 @@ struct ImDrawDataBuilder
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Data types support
|
||||
// [SECTION] Style support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiDataVarInfo
|
||||
struct ImGuiStyleVarInfo
|
||||
{
|
||||
ImGuiDataType Type;
|
||||
ImU32 Count; // 1+
|
||||
ImU32 Offset; // Offset in parent structure
|
||||
ImU32 Count : 8; // 1+
|
||||
ImGuiDataType DataType : 8;
|
||||
ImU32 Offset : 16; // Offset in parent structure
|
||||
void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); }
|
||||
};
|
||||
|
||||
// Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiColorMod
|
||||
{
|
||||
ImGuiCol Col;
|
||||
ImVec4 BackupValue;
|
||||
};
|
||||
|
||||
// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
|
||||
struct ImGuiStyleMod
|
||||
{
|
||||
ImGuiStyleVar VarIdx;
|
||||
union { int BackupInt[2]; float BackupFloat[2]; };
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Data types support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiDataTypeStorage
|
||||
{
|
||||
ImU8 Data[8]; // Opaque storage to fit any data up to ImGuiDataType_COUNT
|
||||
@@ -836,7 +862,7 @@ struct ImGuiDataTypeInfo
|
||||
// Extend ImGuiDataType_
|
||||
enum ImGuiDataTypePrivate_
|
||||
{
|
||||
ImGuiDataType_Pointer = ImGuiDataType_COUNT + 1,
|
||||
ImGuiDataType_Pointer = ImGuiDataType_COUNT,
|
||||
ImGuiDataType_ID,
|
||||
};
|
||||
|
||||
@@ -1037,23 +1063,6 @@ enum ImGuiPlotType
|
||||
ImGuiPlotType_Histogram,
|
||||
};
|
||||
|
||||
// Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiColorMod
|
||||
{
|
||||
ImGuiCol Col;
|
||||
ImVec4 BackupValue;
|
||||
};
|
||||
|
||||
// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
|
||||
struct ImGuiStyleMod
|
||||
{
|
||||
ImGuiStyleVar VarIdx;
|
||||
union { int BackupInt[2]; float BackupFloat[2]; };
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; }
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }
|
||||
};
|
||||
|
||||
// Storage data for BeginComboPreview()/EndComboPreview()
|
||||
struct IMGUI_API ImGuiComboPreviewData
|
||||
{
|
||||
@@ -1194,14 +1203,17 @@ enum ImGuiNextWindowDataFlags_
|
||||
ImGuiNextWindowDataFlags_HasFocus = 1 << 5,
|
||||
ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6,
|
||||
ImGuiNextWindowDataFlags_HasScroll = 1 << 7,
|
||||
ImGuiNextWindowDataFlags_HasChildFlags = 1 << 8,
|
||||
ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 9,
|
||||
ImGuiNextWindowDataFlags_HasWindowFlags = 1 << 8,
|
||||
ImGuiNextWindowDataFlags_HasChildFlags = 1 << 9,
|
||||
ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 10,
|
||||
};
|
||||
|
||||
// Storage for SetNexWindow** functions
|
||||
struct ImGuiNextWindowData
|
||||
{
|
||||
ImGuiNextWindowDataFlags Flags;
|
||||
ImGuiNextWindowDataFlags HasFlags;
|
||||
|
||||
// Members below are NOT cleared. Always rely on HasFlags.
|
||||
ImGuiCond PosCond;
|
||||
ImGuiCond SizeCond;
|
||||
ImGuiCond CollapsedCond;
|
||||
@@ -1210,6 +1222,7 @@ struct ImGuiNextWindowData
|
||||
ImVec2 SizeVal;
|
||||
ImVec2 ContentSizeVal;
|
||||
ImVec2 ScrollVal;
|
||||
ImGuiWindowFlags WindowFlags; // Only honored by BeginTable()
|
||||
ImGuiChildFlags ChildFlags;
|
||||
bool CollapsedVal;
|
||||
ImRect SizeConstraintRect;
|
||||
@@ -1220,7 +1233,7 @@ struct ImGuiNextWindowData
|
||||
ImGuiWindowRefreshFlags RefreshFlagsVal;
|
||||
|
||||
ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
|
||||
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
|
||||
inline void ClearFlags() { HasFlags = ImGuiNextWindowDataFlags_None; }
|
||||
};
|
||||
|
||||
enum ImGuiNextItemDataFlags_
|
||||
@@ -1237,7 +1250,8 @@ struct ImGuiNextItemData
|
||||
{
|
||||
ImGuiNextItemDataFlags HasFlags; // Called HasFlags instead of Flags to avoid mistaking this
|
||||
ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap and ImGuiItemFlags_HasSelectionUserData.
|
||||
// Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem()
|
||||
|
||||
// Members below are NOT cleared by ItemAdd() meaning they are still valid during e.g. NavProcessItem(). Always rely on HasFlags.
|
||||
ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData()
|
||||
ImGuiSelectionUserData SelectionUserData; // Set by SetNextItemSelectionUserData() (note that NULL/0 is a valid value, we use -1 == ImGuiSelectionUserData_Invalid to mark invalid values)
|
||||
float Width; // Set by SetNextItemWidth()
|
||||
@@ -1305,6 +1319,7 @@ struct ImGuiWindowStackData
|
||||
ImGuiLastItemData ParentLastItemDataBackup;
|
||||
ImGuiErrorRecoveryState StackSizesInBegin; // Store size of various stacks for asserting
|
||||
bool DisabledOverrideReenable; // Non-child window override disabled flag
|
||||
float DisabledOverrideReenableAlphaBackup;
|
||||
};
|
||||
|
||||
struct ImGuiShrinkWidthItem
|
||||
@@ -1992,7 +2007,6 @@ struct ImGuiMetricsConfig
|
||||
bool ShowDrawCmdMesh = true;
|
||||
bool ShowDrawCmdBoundingBoxes = true;
|
||||
bool ShowTextEncodingViewer = false;
|
||||
bool ShowAtlasTintedWithTextColor = false;
|
||||
int ShowWindowsRectsType = -1;
|
||||
int ShowTablesRectsType = -1;
|
||||
int HighlightMonitorIdx = -1;
|
||||
@@ -2019,6 +2033,7 @@ struct ImGuiIDStackTool
|
||||
ImVector<ImGuiStackLevelInfo> Results;
|
||||
bool CopyToClipboardOnCtrlC;
|
||||
float CopyToClipboardLastTime;
|
||||
ImGuiTextBuffer ResultPathBuf;
|
||||
|
||||
ImGuiIDStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; }
|
||||
};
|
||||
@@ -2083,7 +2098,7 @@ struct ImGuiContext
|
||||
ImVector<ImGuiWindowStackData> CurrentWindowStack;
|
||||
ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow*
|
||||
int WindowsActiveCount; // Number of unique windows submitted by frame
|
||||
ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING).
|
||||
float WindowsBorderHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, style.WindowBorderHoverPadding). This isn't so multi-dpi friendly.
|
||||
ImGuiID DebugBreakInWindow; // Set to break in Begin() call.
|
||||
ImGuiWindow* CurrentWindow; // Window being drawn into
|
||||
ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
|
||||
@@ -2500,6 +2515,8 @@ struct IMGUI_API ImGuiWindow
|
||||
ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold
|
||||
ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar.
|
||||
bool ScrollbarX, ScrollbarY; // Are scrollbars visible?
|
||||
bool ScrollbarXStabilizeEnabled; // Was ScrollbarX previously auto-stabilized?
|
||||
ImU8 ScrollbarXStabilizeToggledHistory; // Used to stabilize scrollbar visibility in case of feedback loops
|
||||
bool Active; // Set to true on Begin(), unless Collapsed
|
||||
bool WasActive;
|
||||
bool WriteAccessed; // Set to true when any widget access the current window
|
||||
@@ -2787,7 +2804,7 @@ struct IMGUI_API ImGuiTable
|
||||
{
|
||||
ImGuiID ID;
|
||||
ImGuiTableFlags Flags;
|
||||
void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[]
|
||||
void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[], and RowCellData[]
|
||||
ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[]
|
||||
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
|
||||
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
|
||||
@@ -2801,7 +2818,7 @@ struct IMGUI_API ImGuiTable
|
||||
int ColumnsCount; // Number of columns declared in BeginTable()
|
||||
int CurrentRow;
|
||||
int CurrentColumn;
|
||||
ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched.
|
||||
ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple tables with the same ID are multiple tables, they are just synced.
|
||||
ImS16 InstanceInteracted; // Mark which instance (generally 0) of the same ID is being interacted with
|
||||
float RowPosY1;
|
||||
float RowPosY2;
|
||||
@@ -2833,7 +2850,7 @@ struct IMGUI_API ImGuiTable
|
||||
float AngledHeadersHeight; // Set by TableAngledHeadersRow(), used in TableUpdateLayout()
|
||||
float AngledHeadersSlope; // Set by TableAngledHeadersRow(), used in TableUpdateLayout()
|
||||
ImRect OuterRect; // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
|
||||
ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is
|
||||
ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is "
|
||||
ImRect WorkRect;
|
||||
ImRect InnerClipRect;
|
||||
ImRect BgClipRect; // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries
|
||||
@@ -2930,7 +2947,7 @@ struct IMGUI_API ImGuiTableTempData
|
||||
ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; }
|
||||
};
|
||||
|
||||
// sizeof() ~ 12
|
||||
// sizeof() ~ 16
|
||||
struct ImGuiTableColumnSettings
|
||||
{
|
||||
float WidthOrWeight;
|
||||
@@ -2939,7 +2956,7 @@ struct ImGuiTableColumnSettings
|
||||
ImGuiTableColumnIdx DisplayOrder;
|
||||
ImGuiTableColumnIdx SortOrder;
|
||||
ImU8 SortDirection : 2;
|
||||
ImU8 IsEnabled : 1; // "Visible" in ini file
|
||||
ImS8 IsEnabled : 2; // "Visible" in ini file
|
||||
ImU8 IsStretch : 1;
|
||||
|
||||
ImGuiTableColumnSettings()
|
||||
@@ -2949,7 +2966,7 @@ struct ImGuiTableColumnSettings
|
||||
Index = -1;
|
||||
DisplayOrder = SortOrder = -1;
|
||||
SortDirection = ImGuiSortDirection_None;
|
||||
IsEnabled = 1;
|
||||
IsEnabled = -1;
|
||||
IsStretch = 0;
|
||||
}
|
||||
};
|
||||
@@ -2980,7 +2997,8 @@ namespace ImGui
|
||||
// If this ever crashes because g.CurrentWindow is NULL, it means that either:
|
||||
// - ImGui::NewFrame() has never been called, which is illegal.
|
||||
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
|
||||
IMGUI_API ImGuiIO& GetIOEx(ImGuiContext* ctx);
|
||||
IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx);
|
||||
IMGUI_API ImGuiPlatformIO& GetPlatformIO(ImGuiContext* ctx);
|
||||
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
|
||||
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
|
||||
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
|
||||
@@ -3108,7 +3126,7 @@ namespace ImGui
|
||||
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
|
||||
|
||||
// Parameter stacks (shared)
|
||||
IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
|
||||
IMGUI_API const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
|
||||
IMGUI_API void BeginDisabledOverrideReenable();
|
||||
IMGUI_API void EndDisabledOverrideReenable();
|
||||
|
||||
@@ -3123,6 +3141,7 @@ namespace ImGui
|
||||
|
||||
// Popups, Modals
|
||||
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags);
|
||||
IMGUI_API bool BeginPopupMenuEx(ImGuiID id, const char* label, ImGuiWindowFlags extra_window_flags);
|
||||
IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None);
|
||||
IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup);
|
||||
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup);
|
||||
@@ -3474,6 +3493,7 @@ namespace ImGui
|
||||
inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); }
|
||||
inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active
|
||||
IMGUI_API void SetNextItemRefVal(ImGuiDataType data_type, void* p_data);
|
||||
inline bool IsItemActiveAsInputText() { ImGuiContext& g = *GImGui; return g.ActiveId != 0 && g.ActiveId == g.LastItemData.ID && g.InputTextState.ID == g.LastItemData.ID; } // This may be useful to apply workaround that a based on distinguish whenever an item is active as a text input field.
|
||||
|
||||
// Color
|
||||
IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags);
|
||||
@@ -3569,16 +3589,18 @@ struct ImFontBuilderIO
|
||||
#ifdef IMGUI_ENABLE_STB_TRUETYPE
|
||||
IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype();
|
||||
#endif
|
||||
IMGUI_API void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
|
||||
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, float ascent, float descent);
|
||||
IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);
|
||||
IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas);
|
||||
IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value);
|
||||
IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value);
|
||||
IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
|
||||
IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
|
||||
IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v);
|
||||
IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, int* out_oversample_h, int* out_oversample_v);
|
||||
|
||||
IMGUI_API bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Test Engine specific hooks (imgui_test_engine)
|
||||
|
||||
511
3rdparty/imgui/src/imgui.cpp
vendored
511
3rdparty/imgui/src/imgui.cpp
vendored
File diff suppressed because it is too large
Load Diff
3112
3rdparty/imgui/src/imgui_demo.cpp
vendored
3112
3rdparty/imgui/src/imgui_demo.cpp
vendored
File diff suppressed because it is too large
Load Diff
188
3rdparty/imgui/src/imgui_draw.cpp
vendored
188
3rdparty/imgui/src/imgui_draw.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91.9b
|
||||
// (drawing and font code)
|
||||
|
||||
/*
|
||||
@@ -68,6 +68,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
|
||||
#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier
|
||||
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||
@@ -143,6 +144,7 @@ namespace IMGUI_STB_NAMESPACE
|
||||
#define STBTT_fabs(x) ImFabs(x)
|
||||
#define STBTT_ifloor(x) ((int)ImFloor(x))
|
||||
#define STBTT_iceil(x) ((int)ImCeil(x))
|
||||
#define STBTT_strlen(x) ImStrlen(x)
|
||||
#define STBTT_STATIC
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#else
|
||||
@@ -374,6 +376,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
||||
ImDrawListSharedData::ImDrawListSharedData()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
InitialFringeScale = 1.0f;
|
||||
for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)
|
||||
{
|
||||
const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);
|
||||
@@ -433,7 +436,7 @@ void ImDrawList::_ResetForNewFrame()
|
||||
_Path.resize(0);
|
||||
_Splitter.Clear();
|
||||
CmdBuffer.push_back(ImDrawCmd());
|
||||
_FringeScale = 1.0f;
|
||||
_FringeScale = _Data->InitialFringeScale;
|
||||
}
|
||||
|
||||
void ImDrawList::_ClearFreeMemory()
|
||||
@@ -2401,13 +2404,13 @@ ImFontConfig::ImFontConfig()
|
||||
// - ImFontAtlas::AddCustomRectRegular()
|
||||
// - ImFontAtlas::AddCustomRectFontGlyph()
|
||||
// - ImFontAtlas::CalcCustomRectUV()
|
||||
// - ImFontAtlas::GetMouseCursorTexData()
|
||||
// - ImFontAtlasGetMouseCursorTexData()
|
||||
// - ImFontAtlas::Build()
|
||||
// - ImFontAtlasBuildMultiplyCalcLookupTable()
|
||||
// - ImFontAtlasBuildMultiplyRectAlpha8()
|
||||
// - ImFontAtlasBuildWithStbTruetype()
|
||||
// - ImFontAtlasGetBuilderForStbTruetype()
|
||||
// - ImFontAtlasUpdateConfigDataPointers()
|
||||
// - ImFontAtlasUpdateSourcesPointers()
|
||||
// - ImFontAtlasBuildSetupFont()
|
||||
// - ImFontAtlasBuildPackCustomRects()
|
||||
// - ImFontAtlasBuildRender8bppRectFromString()
|
||||
@@ -2465,6 +2468,8 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3
|
||||
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
|
||||
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
|
||||
{ ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
|
||||
{ ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Wait // Arrow + custom code in ImGui::RenderMouseCursor()
|
||||
{ ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Progress // Arrow + custom code in ImGui::RenderMouseCursor()
|
||||
{ ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
|
||||
};
|
||||
|
||||
@@ -2484,7 +2489,7 @@ ImFontAtlas::~ImFontAtlas()
|
||||
void ImFontAtlas::ClearInputData()
|
||||
{
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
for (ImFontConfig& font_cfg : ConfigData)
|
||||
for (ImFontConfig& font_cfg : Sources)
|
||||
if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)
|
||||
{
|
||||
IM_FREE(font_cfg.FontData);
|
||||
@@ -2493,12 +2498,12 @@ void ImFontAtlas::ClearInputData()
|
||||
|
||||
// When clearing this we lose access to the font name and other information used to build the font.
|
||||
for (ImFont* font : Fonts)
|
||||
if (font->ConfigData >= ConfigData.Data && font->ConfigData < ConfigData.Data + ConfigData.Size)
|
||||
if (font->Sources >= Sources.Data && font->Sources < Sources.Data + Sources.Size)
|
||||
{
|
||||
font->ConfigData = NULL;
|
||||
font->ConfigDataCount = 0;
|
||||
font->Sources = NULL;
|
||||
font->SourcesCount = 0;
|
||||
}
|
||||
ConfigData.clear();
|
||||
Sources.clear();
|
||||
CustomRects.clear();
|
||||
PackIdMouseCursors = PackIdLines = -1;
|
||||
// Important: we leave TexReady untouched
|
||||
@@ -2581,8 +2586,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||
else
|
||||
IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
|
||||
|
||||
ConfigData.push_back(*font_cfg);
|
||||
ImFontConfig& new_font_cfg = ConfigData.back();
|
||||
Sources.push_back(*font_cfg);
|
||||
ImFontConfig& new_font_cfg = Sources.back();
|
||||
if (new_font_cfg.DstFont == NULL)
|
||||
new_font_cfg.DstFont = Fonts.back();
|
||||
if (!new_font_cfg.FontDataOwnedByAtlas)
|
||||
@@ -2598,8 +2603,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||
// - We may support it better later and remove this rounding.
|
||||
new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels);
|
||||
|
||||
// Pointers to ConfigData and BuilderData are otherwise dangling
|
||||
ImFontAtlasUpdateConfigDataPointers(this);
|
||||
// Pointers to Sources data are otherwise dangling
|
||||
ImFontAtlasUpdateSourcesPointers(this);
|
||||
|
||||
// Invalidate texture
|
||||
TexReady = false;
|
||||
@@ -2669,7 +2674,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
|
||||
{
|
||||
// Store a short copy of filename into into the font name for convenience
|
||||
const char* p;
|
||||
for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
|
||||
for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
|
||||
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
|
||||
}
|
||||
return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
|
||||
@@ -2704,7 +2709,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_d
|
||||
|
||||
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
|
||||
{
|
||||
int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
|
||||
int compressed_ttf_size = (((int)ImStrlen(compressed_ttf_data_base85) + 4) / 5) * 4;
|
||||
void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
|
||||
Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
|
||||
ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
|
||||
@@ -2751,24 +2756,24 @@ void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* ou
|
||||
*out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);
|
||||
}
|
||||
|
||||
bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
|
||||
bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
|
||||
{
|
||||
if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
|
||||
return false;
|
||||
if (Flags & ImFontAtlasFlags_NoMouseCursors)
|
||||
if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors)
|
||||
return false;
|
||||
|
||||
IM_ASSERT(PackIdMouseCursors != -1);
|
||||
ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors);
|
||||
IM_ASSERT(atlas->PackIdMouseCursors != -1);
|
||||
ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors);
|
||||
ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y);
|
||||
ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
|
||||
*out_size = size;
|
||||
*out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
|
||||
out_uv_border[0] = (pos) * TexUvScale;
|
||||
out_uv_border[1] = (pos + size) * TexUvScale;
|
||||
out_uv_border[0] = (pos) * atlas->TexUvScale;
|
||||
out_uv_border[1] = (pos + size) * atlas->TexUvScale;
|
||||
pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
|
||||
out_uv_fill[0] = (pos) * TexUvScale;
|
||||
out_uv_fill[1] = (pos + size) * TexUvScale;
|
||||
out_uv_fill[0] = (pos) * atlas->TexUvScale;
|
||||
out_uv_fill[1] = (pos + size) * atlas->TexUvScale;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2777,7 +2782,7 @@ bool ImFontAtlas::Build()
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
|
||||
// Default font is none are specified
|
||||
if (ConfigData.Size == 0)
|
||||
if (Sources.Size == 0)
|
||||
AddFontDefault();
|
||||
|
||||
// Select builder
|
||||
@@ -2819,11 +2824,11 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig
|
||||
*data = table[*data];
|
||||
}
|
||||
|
||||
void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v)
|
||||
void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, int* out_oversample_h, int* out_oversample_v)
|
||||
{
|
||||
// Automatically disable horizontal oversampling over size 36
|
||||
*out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 36.0f || cfg->PixelSnapH) ? 1 : 2;
|
||||
*out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1;
|
||||
*out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (src->SizePixels * src->RasterizerDensity > 36.0f || src->PixelSnapH) ? 1 : 2;
|
||||
*out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1;
|
||||
}
|
||||
|
||||
#ifdef IMGUI_ENABLE_STB_TRUETYPE
|
||||
@@ -2866,7 +2871,7 @@ static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector<int>*
|
||||
|
||||
static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
{
|
||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||
IM_ASSERT(atlas->Sources.Size > 0);
|
||||
|
||||
ImFontAtlasBuildInit(atlas);
|
||||
|
||||
@@ -2880,32 +2885,32 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
// Temporary storage for building
|
||||
ImVector<ImFontBuildSrcData> src_tmp_array;
|
||||
ImVector<ImFontBuildDstData> dst_tmp_array;
|
||||
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||
src_tmp_array.resize(atlas->Sources.Size);
|
||||
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||
memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||
memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||
|
||||
// 1. Initialize font loading structure, check font data validity
|
||||
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||
for (int src_i = 0; src_i < atlas->Sources.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas));
|
||||
|
||||
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
// Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
src_tmp.DstIndex = -1;
|
||||
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||
if (src.DstFont == atlas->Fonts[output_i])
|
||||
src_tmp.DstIndex = output_i;
|
||||
if (src_tmp.DstIndex == -1)
|
||||
{
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array?
|
||||
return false;
|
||||
}
|
||||
// Initialize helper structure for font loading and verify that the TTF/OTF data is correct
|
||||
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
|
||||
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src.FontData, src.FontNo);
|
||||
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
|
||||
if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
|
||||
if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)src.FontData, font_offset))
|
||||
{
|
||||
IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.");
|
||||
return false;
|
||||
@@ -2913,7 +2918,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
|
||||
// Measure highest codepoints
|
||||
ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
{
|
||||
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||
@@ -2992,12 +2997,12 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
buf_packedchars_out_n += src_tmp.GlyphsCount;
|
||||
|
||||
// Automatic selection of oversampling parameters
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
int oversample_h, oversample_v;
|
||||
ImFontAtlasBuildGetOversampleFactors(&cfg, &oversample_h, &oversample_v);
|
||||
ImFontAtlasBuildGetOversampleFactors(&src, &oversample_h, &oversample_v);
|
||||
|
||||
// Convert our ranges in the format stb_truetype wants
|
||||
src_tmp.PackRange.font_size = cfg.SizePixels * cfg.RasterizerDensity;
|
||||
src_tmp.PackRange.font_size = src.SizePixels * src.RasterizerDensity;
|
||||
src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
|
||||
src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
|
||||
src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
|
||||
@@ -3006,7 +3011,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
src_tmp.PackRange.v_oversample = (unsigned char)oversample_v;
|
||||
|
||||
// Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
|
||||
const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity);
|
||||
const float scale = (src.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels * src.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -src.SizePixels * src.RasterizerDensity);
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||
{
|
||||
int x0, y0, x1, y1;
|
||||
@@ -3066,7 +3071,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
// 8. Render/rasterize font characters into the texture
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
@@ -3074,10 +3079,10 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
|
||||
|
||||
// Apply multiply operator
|
||||
if (cfg.RasterizerMultiply != 1.0f)
|
||||
if (src.RasterizerMultiply != 1.0f)
|
||||
{
|
||||
unsigned char multiply_table[256];
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply);
|
||||
stbrp_rect* r = &src_tmp.Rects[0];
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
|
||||
if (r->was_packed)
|
||||
@@ -3095,22 +3100,22 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
{
|
||||
// When merging fonts with MergeMode=true:
|
||||
// - We can have multiple input fonts writing into a same destination font.
|
||||
// - dst_font->ConfigData is != from cfg which is our source configuration.
|
||||
// - dst_font->Sources is != from src which is our source configuration.
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFont* dst_font = cfg.DstFont;
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
ImFont* dst_font = src.DstFont;
|
||||
|
||||
const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
|
||||
const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels);
|
||||
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
|
||||
stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
||||
|
||||
const float ascent = ImCeil(unscaled_ascent * font_scale);
|
||||
const float descent = ImFloor(unscaled_descent * font_scale);
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
const float font_off_x = cfg.GlyphOffset.x;
|
||||
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent);
|
||||
const float font_off_x = src.GlyphOffset.x;
|
||||
const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
|
||||
const float inv_rasterization_scale = 1.0f / cfg.RasterizerDensity;
|
||||
const float inv_rasterization_scale = 1.0f / src.RasterizerDensity;
|
||||
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||
{
|
||||
@@ -3124,7 +3129,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
float y0 = q.y0 * inv_rasterization_scale + font_off_y;
|
||||
float x1 = q.x1 * inv_rasterization_scale + font_off_x;
|
||||
float y1 = q.y1 * inv_rasterization_scale + font_off_y;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale);
|
||||
dst_font->AddGlyph(&src, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3144,17 +3149,17 @@ const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype()
|
||||
|
||||
#endif // IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas)
|
||||
void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas)
|
||||
{
|
||||
for (ImFontConfig& font_cfg : atlas->ConfigData)
|
||||
for (ImFontConfig& src : atlas->Sources)
|
||||
{
|
||||
ImFont* font = font_cfg.DstFont;
|
||||
if (!font_cfg.MergeMode)
|
||||
ImFont* font = src.DstFont;
|
||||
if (!src.MergeMode)
|
||||
{
|
||||
font->ConfigData = &font_cfg;
|
||||
font->ConfigDataCount = 0;
|
||||
font->Sources = &src;
|
||||
font->SourcesCount = 0;
|
||||
}
|
||||
font->ConfigDataCount++;
|
||||
font->SourcesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3164,7 +3169,7 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f
|
||||
{
|
||||
font->ClearOutputData();
|
||||
font->FontSize = font_config->SizePixels;
|
||||
IM_ASSERT(font->ConfigData == font_config);
|
||||
IM_ASSERT(font->Sources == font_config);
|
||||
font->ContainerAtlas = atlas;
|
||||
font->Ascent = ascent;
|
||||
font->Descent = descent;
|
||||
@@ -3349,7 +3354,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
|
||||
if (r->Font == NULL || r->GlyphID == 0)
|
||||
continue;
|
||||
|
||||
// Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH
|
||||
// Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, PixelSnapH
|
||||
IM_ASSERT(r->Font->ContainerAtlas == atlas);
|
||||
ImVec2 uv0, uv1;
|
||||
atlas->CalcCustomRectUV(r, &uv0, &uv1);
|
||||
@@ -3685,21 +3690,8 @@ void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
||||
|
||||
ImFont::ImFont()
|
||||
{
|
||||
FontSize = 0.0f;
|
||||
FallbackAdvanceX = 0.0f;
|
||||
FallbackChar = 0;
|
||||
EllipsisChar = 0;
|
||||
EllipsisWidth = EllipsisCharStep = 0.0f;
|
||||
EllipsisCharCount = 0;
|
||||
FallbackGlyph = NULL;
|
||||
ContainerAtlas = NULL;
|
||||
ConfigData = NULL;
|
||||
ConfigDataCount = 0;
|
||||
DirtyLookupTables = false;
|
||||
memset(this, 0, sizeof(*this));
|
||||
Scale = 1.0f;
|
||||
Ascent = Descent = 0.0f;
|
||||
MetricsTotalSurface = 0;
|
||||
memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
|
||||
}
|
||||
|
||||
ImFont::~ImFont()
|
||||
@@ -3770,8 +3762,10 @@ void ImFont::BuildLookupTable()
|
||||
}
|
||||
|
||||
// Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)
|
||||
SetGlyphVisible((ImWchar)' ', false);
|
||||
SetGlyphVisible((ImWchar)'\t', false);
|
||||
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)' '))
|
||||
glyph->Visible = false;
|
||||
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)'\t'))
|
||||
glyph->Visible = false;
|
||||
|
||||
// Setup Fallback character
|
||||
const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
|
||||
@@ -3794,7 +3788,7 @@ void ImFont::BuildLookupTable()
|
||||
// Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
||||
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
||||
// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
|
||||
const ImWchar ellipsis_chars[] = { ConfigData->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
const ImWchar ellipsis_chars[] = { Sources->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
|
||||
if (EllipsisChar == 0)
|
||||
EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
|
||||
@@ -3827,12 +3821,6 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImFont::SetGlyphVisible(ImWchar c, bool visible)
|
||||
{
|
||||
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))
|
||||
glyph->Visible = visible ? 1 : 0;
|
||||
}
|
||||
|
||||
void ImFont::GrowIndex(int new_size)
|
||||
{
|
||||
IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
|
||||
@@ -3844,27 +3832,27 @@ void ImFont::GrowIndex(int new_size)
|
||||
|
||||
// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
|
||||
// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).
|
||||
// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font.
|
||||
void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
|
||||
// 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font.
|
||||
void ImFont::AddGlyph(const ImFontConfig* src, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
|
||||
{
|
||||
if (cfg != NULL)
|
||||
if (src != NULL)
|
||||
{
|
||||
// Clamp & recenter if needed
|
||||
const float advance_x_original = advance_x;
|
||||
advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX);
|
||||
advance_x = ImClamp(advance_x, src->GlyphMinAdvanceX, src->GlyphMaxAdvanceX);
|
||||
if (advance_x != advance_x_original)
|
||||
{
|
||||
float char_off_x = cfg->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
|
||||
float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
|
||||
x0 += char_off_x;
|
||||
x1 += char_off_x;
|
||||
}
|
||||
|
||||
// Snap to pixel
|
||||
if (cfg->PixelSnapH)
|
||||
if (src->PixelSnapH)
|
||||
advance_x = IM_ROUND(advance_x);
|
||||
|
||||
// Bake spacing
|
||||
advance_x += cfg->GlyphExtraSpacing.x;
|
||||
// Bake extra spacing
|
||||
advance_x += src->GlyphExtraAdvanceX;
|
||||
}
|
||||
|
||||
int glyph_idx = Glyphs.Size;
|
||||
@@ -3907,7 +3895,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
|
||||
}
|
||||
|
||||
// Find glyph, return fallback if missing
|
||||
const ImFontGlyph* ImFont::FindGlyph(ImWchar c)
|
||||
ImFontGlyph* ImFont::FindGlyph(ImWchar c)
|
||||
{
|
||||
if (c >= (size_t)IndexLookup.Size)
|
||||
return FallbackGlyph;
|
||||
@@ -3917,7 +3905,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c)
|
||||
return &Glyphs.Data[i];
|
||||
}
|
||||
|
||||
const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c)
|
||||
ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c)
|
||||
{
|
||||
if (c >= (size_t)IndexLookup.Size)
|
||||
return NULL;
|
||||
@@ -4043,7 +4031,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
|
||||
ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining)
|
||||
{
|
||||
if (!text_end)
|
||||
text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
|
||||
text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this.
|
||||
|
||||
const float line_height = size;
|
||||
const float scale = size / FontSize;
|
||||
@@ -4143,7 +4131,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
return;
|
||||
|
||||
if (!text_end)
|
||||
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
||||
text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
||||
|
||||
const float scale = size / FontSize;
|
||||
const float line_height = FontSize * scale;
|
||||
@@ -4155,7 +4143,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
if (y + line_height < clip_rect.y)
|
||||
while (y + line_height < clip_rect.y && s < text_end)
|
||||
{
|
||||
const char* line_end = (const char*)memchr(s, '\n', text_end - s);
|
||||
const char* line_end = (const char*)ImMemchr(s, '\n', text_end - s);
|
||||
if (word_wrap_enabled)
|
||||
{
|
||||
// FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA().
|
||||
@@ -4179,7 +4167,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
float y_end = y;
|
||||
while (y_end < clip_rect.w && s_end < text_end)
|
||||
{
|
||||
s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
|
||||
s_end = (const char*)ImMemchr(s_end, '\n', text_end - s_end);
|
||||
s_end = s_end ? s_end + 1 : text_end;
|
||||
y_end += line_height;
|
||||
}
|
||||
|
||||
64
3rdparty/imgui/src/imgui_freetype.cpp
vendored
64
3rdparty/imgui/src/imgui_freetype.cpp
vendored
@@ -166,7 +166,7 @@ namespace
|
||||
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
||||
struct FreeTypeFont
|
||||
{
|
||||
bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||
bool InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||
void CloseFont();
|
||||
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
||||
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
|
||||
@@ -185,9 +185,9 @@ namespace
|
||||
float InvRasterizationDensity;
|
||||
};
|
||||
|
||||
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags)
|
||||
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_font_builder_flags)
|
||||
{
|
||||
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
|
||||
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src.FontData, (uint32_t)src.FontDataSize, (uint32_t)src.FontNo, &Face);
|
||||
if (error != 0)
|
||||
return false;
|
||||
error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
|
||||
@@ -195,7 +195,7 @@ namespace
|
||||
return false;
|
||||
|
||||
// Convert to FreeType flags (NB: Bold and Oblique are processed separately)
|
||||
UserFlags = cfg.FontBuilderFlags | extra_font_builder_flags;
|
||||
UserFlags = src.FontBuilderFlags | extra_font_builder_flags;
|
||||
|
||||
LoadFlags = 0;
|
||||
if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0)
|
||||
@@ -222,11 +222,11 @@ namespace
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor)
|
||||
LoadFlags |= FT_LOAD_COLOR;
|
||||
|
||||
RasterizationDensity = cfg.RasterizerDensity;
|
||||
RasterizationDensity = src.RasterizerDensity;
|
||||
InvRasterizationDensity = 1.0f / RasterizationDensity;
|
||||
|
||||
memset(&Info, 0, sizeof(Info));
|
||||
SetPixelHeight((uint32_t)cfg.SizePixels);
|
||||
SetPixelHeight((uint32_t)src.SizePixels);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -269,11 +269,11 @@ namespace
|
||||
if (glyph_index == 0)
|
||||
return nullptr;
|
||||
|
||||
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
|
||||
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
|
||||
// - https://github.com/ocornut/imgui/issues/4567
|
||||
// - https://github.com/ocornut/imgui/issues/4566
|
||||
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
|
||||
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
|
||||
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
|
||||
// - https://github.com/ocornut/imgui/issues/4567
|
||||
// - https://github.com/ocornut/imgui/issues/4566
|
||||
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
|
||||
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
|
||||
if (error)
|
||||
return nullptr;
|
||||
@@ -443,7 +443,7 @@ struct ImFontBuildDstDataFT
|
||||
|
||||
bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
|
||||
{
|
||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||
IM_ASSERT(atlas->Sources.Size > 0);
|
||||
|
||||
ImFontAtlasBuildInit(atlas);
|
||||
|
||||
@@ -458,36 +458,36 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
bool src_load_color = false;
|
||||
ImVector<ImFontBuildSrcDataFT> src_tmp_array;
|
||||
ImVector<ImFontBuildDstDataFT> dst_tmp_array;
|
||||
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||
src_tmp_array.resize(atlas->Sources.Size);
|
||||
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||
memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||
memset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||
|
||||
// 1. Initialize font loading structure, check font data validity
|
||||
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||
for (int src_i = 0; src_i < atlas->Sources.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
FreeTypeFont& font_face = src_tmp.Font;
|
||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||
IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas));
|
||||
|
||||
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
// Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
src_tmp.DstIndex = -1;
|
||||
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||
if (src.DstFont == atlas->Fonts[output_i])
|
||||
src_tmp.DstIndex = output_i;
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array?
|
||||
if (src_tmp.DstIndex == -1)
|
||||
return false;
|
||||
|
||||
// Load font
|
||||
if (!font_face.InitFont(ft_library, cfg, extra_flags))
|
||||
if (!font_face.InitFont(ft_library, src, extra_flags))
|
||||
return false;
|
||||
|
||||
// Measure highest codepoints
|
||||
src_load_color |= (cfg.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
||||
src_load_color |= (src.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
||||
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
{
|
||||
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||
@@ -577,7 +577,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
|
||||
@@ -585,10 +585,10 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||
|
||||
// Compute multiply table if requested
|
||||
const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
|
||||
const bool multiply_enabled = (src.RasterizerMultiply != 1.0f);
|
||||
unsigned char multiply_table[256];
|
||||
if (multiply_enabled)
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply);
|
||||
|
||||
// Gather the sizes of all rectangles we will need to pack
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||
@@ -687,18 +687,18 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
|
||||
// When merging fonts with MergeMode=true:
|
||||
// - We can have multiple input fonts writing into a same destination font.
|
||||
// - dst_font->ConfigData is != from cfg which is our source configuration.
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFont* dst_font = cfg.DstFont;
|
||||
// - dst_font->Sources is != from src which is our source configuration.
|
||||
ImFontConfig& src = atlas->Sources[src_i];
|
||||
ImFont* dst_font = src.DstFont;
|
||||
|
||||
const float ascent = src_tmp.Font.Info.Ascender;
|
||||
const float descent = src_tmp.Font.Info.Descender;
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent);
|
||||
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
const float font_off_x = cfg.GlyphOffset.x;
|
||||
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
const float font_off_x = src.GlyphOffset.x;
|
||||
const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
|
||||
const int padding = atlas->TexGlyphPadding;
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||
@@ -724,7 +724,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
float v0 = (ty) / (float)atlas->TexHeight;
|
||||
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
||||
dst_font->AddGlyph(&src, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
||||
|
||||
ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
||||
IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
||||
|
||||
94
3rdparty/imgui/src/imgui_tables.cpp
vendored
94
3rdparty/imgui/src/imgui_tables.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91b
|
||||
// (tables and columns code)
|
||||
|
||||
/*
|
||||
@@ -221,6 +221,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
|
||||
#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
|
||||
@@ -230,6 +231,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
|
||||
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
|
||||
@@ -340,6 +342,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
{
|
||||
ItemSize(outer_rect);
|
||||
ItemAdd(outer_rect, id);
|
||||
g.NextWindowData.ClearFlags();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -415,12 +418,15 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
|
||||
// Reset scroll if we are reactivating it
|
||||
if ((previous_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0)
|
||||
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) == 0)
|
||||
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasScroll) == 0)
|
||||
SetNextWindowScroll(ImVec2(0.0f, 0.0f));
|
||||
|
||||
// Create scrolling region (without border and zero window padding)
|
||||
ImGuiWindowFlags child_window_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), ImGuiChildFlags_None, child_window_flags);
|
||||
ImGuiChildFlags child_child_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : ImGuiChildFlags_None;
|
||||
ImGuiWindowFlags child_window_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) ? g.NextWindowData.WindowFlags : ImGuiWindowFlags_None;
|
||||
if (flags & ImGuiTableFlags_ScrollX)
|
||||
child_window_flags |= ImGuiWindowFlags_HorizontalScrollbar;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), child_child_flags, child_window_flags);
|
||||
table->InnerWindow = g.CurrentWindow;
|
||||
table->WorkRect = table->InnerWindow->WorkRect;
|
||||
table->OuterRect = table->InnerWindow->Rect();
|
||||
@@ -573,6 +579,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
// Initialize
|
||||
table->SettingsOffset = -1;
|
||||
table->IsSortSpecsDirty = true;
|
||||
table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934)
|
||||
table->InstanceInteracted = -1;
|
||||
table->ContextPopupColumn = -1;
|
||||
table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;
|
||||
@@ -972,7 +979,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
// [Part 4] Apply final widths based on requested widths
|
||||
const ImRect work_rect = table->WorkRect;
|
||||
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
||||
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920)
|
||||
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synced tables with mismatching scrollbar state (#5920)
|
||||
const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed);
|
||||
const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests;
|
||||
float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
|
||||
@@ -1385,7 +1392,7 @@ void ImGui::EndTable()
|
||||
|
||||
// Setup inner scrolling range
|
||||
// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,
|
||||
// but since the later is likely to be impossible to do we'd rather update both axises together.
|
||||
// but since the later is likely to be impossible to do we'd rather update both axes together.
|
||||
if (table->Flags & ImGuiTableFlags_ScrollX)
|
||||
{
|
||||
const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;
|
||||
@@ -1560,6 +1567,31 @@ void ImGui::EndTable()
|
||||
NavUpdateCurrentWindowIsScrollPushableX();
|
||||
}
|
||||
|
||||
// Called in TableSetupColumn() when initializing and in TableLoadSettings() for defaults before applying stored settings.
|
||||
// 'init_mask' specify which fields to initialize.
|
||||
static void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask)
|
||||
{
|
||||
ImGuiTableColumnFlags flags = column->Flags;
|
||||
if (init_mask & ImGuiTableFlags_Resizable)
|
||||
{
|
||||
float init_width_or_weight = column->InitStretchWeightOrWidth;
|
||||
column->WidthRequest = ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
|
||||
column->StretchWeight = (init_width_or_weight > 0.0f && (flags & ImGuiTableColumnFlags_WidthStretch)) ? init_width_or_weight : -1.0f;
|
||||
if (init_width_or_weight > 0.0f) // Disable auto-fit if an explicit width/weight has been specified
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
if (init_mask & ImGuiTableFlags_Reorderable)
|
||||
column->DisplayOrder = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(column);
|
||||
if (init_mask & ImGuiTableFlags_Hideable)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = (flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1;
|
||||
if (init_mask & ImGuiTableFlags_Sortable)
|
||||
{
|
||||
// Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||
column->SortOrder = (flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1;
|
||||
column->SortDirection = (flags & ImGuiTableColumnFlags_DefaultSort) ? ((flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending)) : (ImS8)ImGuiSortDirection_None;
|
||||
}
|
||||
}
|
||||
|
||||
// See "COLUMNS SIZING POLICIES" comments at the top of this file
|
||||
// If (init_width_or_weight <= 0.0f) it is ignored
|
||||
void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id)
|
||||
@@ -1588,7 +1620,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column.");
|
||||
|
||||
// When passing a width automatically enforce WidthFixed policy
|
||||
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable)
|
||||
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not resizable)
|
||||
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f)
|
||||
if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
|
||||
flags |= ImGuiTableColumnFlags_WidthFixed;
|
||||
@@ -1606,27 +1638,10 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
column->InitStretchWeightOrWidth = init_width_or_weight;
|
||||
if (table->IsInitializing)
|
||||
{
|
||||
// Init width or weight
|
||||
ImGuiTableFlags init_flags = ~table->SettingsLoadedFlags;
|
||||
if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
|
||||
{
|
||||
if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
|
||||
column->WidthRequest = init_width_or_weight;
|
||||
if (flags & ImGuiTableColumnFlags_WidthStretch)
|
||||
column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
|
||||
|
||||
// Disable auto-fit if an explicit width/weight has been specified
|
||||
if (init_width_or_weight > 0.0f)
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
|
||||
// Init default visibility/sort state
|
||||
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = false;
|
||||
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
|
||||
{
|
||||
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||
column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending);
|
||||
}
|
||||
init_flags |= ImGuiTableFlags_Resizable;
|
||||
TableInitColumnDefaults(table, column, init_flags);
|
||||
}
|
||||
|
||||
// Store name (append with zero-terminator in contiguous buffer)
|
||||
@@ -1635,7 +1650,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
if (label != NULL && label[0] != 0)
|
||||
{
|
||||
column->NameOffset = (ImS16)table->ColumnsNames.size();
|
||||
table->ColumnsNames.append(label, label + strlen(label) + 1);
|
||||
table->ColumnsNames.append(label, label + ImStrlen(label) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2101,7 +2116,11 @@ bool ImGui::TableSetColumnIndex(int column_n)
|
||||
{
|
||||
if (table->CurrentColumn != -1)
|
||||
TableEndCell(table);
|
||||
IM_ASSERT(column_n >= 0 && table->ColumnsCount);
|
||||
if ((column_n >= 0 && column_n < table->ColumnsCount) == false)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(column_n >= 0 && column_n < table->ColumnsCount, "TableSetColumnIndex() invalid column index!");
|
||||
return false;
|
||||
}
|
||||
TableBeginCell(table, column_n);
|
||||
}
|
||||
|
||||
@@ -3714,6 +3733,14 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
table->SettingsLoadedFlags = settings->SaveFlags;
|
||||
table->RefScale = settings->RefScale;
|
||||
|
||||
// Initialize default columns settings
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
TableInitColumnDefaults(table, column, ~0);
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
|
||||
// Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
|
||||
ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
|
||||
ImU64 display_order_mask = 0;
|
||||
@@ -3730,14 +3757,12 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
column->StretchWeight = column_settings->WidthOrWeight;
|
||||
else
|
||||
column->WidthRequest = column_settings->WidthOrWeight;
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
|
||||
column->DisplayOrder = column_settings->DisplayOrder;
|
||||
else
|
||||
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
|
||||
display_order_mask |= (ImU64)1 << column->DisplayOrder;
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled;
|
||||
if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1;
|
||||
column->SortOrder = column_settings->SortOrder;
|
||||
column->SortDirection = column_settings->SortDirection;
|
||||
}
|
||||
@@ -3833,8 +3858,7 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle
|
||||
const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0;
|
||||
const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0;
|
||||
const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0;
|
||||
if (!save_size && !save_visible && !save_order && !save_sort)
|
||||
continue;
|
||||
// We need to save the [Table] entry even if all the bools are false, since this records a table with "default settings".
|
||||
|
||||
buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve
|
||||
buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount);
|
||||
|
||||
173
3rdparty/imgui/src/imgui_widgets.cpp
vendored
173
3rdparty/imgui/src/imgui_widgets.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.91.8
|
||||
// dear imgui, v1.91b
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
@@ -70,6 +70,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
|
||||
#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used.
|
||||
@@ -80,6 +81,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
|
||||
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
|
||||
@@ -169,7 +171,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
// Calculate length
|
||||
const char* text_begin = text;
|
||||
if (text_end == NULL)
|
||||
text_end = text + strlen(text); // FIXME-OPT
|
||||
text_end = text + ImStrlen(text); // FIXME-OPT
|
||||
|
||||
const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
|
||||
const float wrap_pos_x = window->DC.TextWrapPos;
|
||||
@@ -209,7 +211,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
int lines_skipped = 0;
|
||||
while (line < text_end && lines_skipped < lines_skippable)
|
||||
{
|
||||
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
|
||||
const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line);
|
||||
if (!line_end)
|
||||
line_end = text_end;
|
||||
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
|
||||
@@ -230,7 +232,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
if (IsClippedEx(line_rect, 0))
|
||||
break;
|
||||
|
||||
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
|
||||
const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line);
|
||||
if (!line_end)
|
||||
line_end = text_end;
|
||||
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);
|
||||
@@ -245,7 +247,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
||||
int lines_skipped = 0;
|
||||
while (line < text_end)
|
||||
{
|
||||
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
|
||||
const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line);
|
||||
if (!line_end)
|
||||
line_end = text_end;
|
||||
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
|
||||
@@ -913,7 +915,7 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)
|
||||
const ImRect outer_rect = window->Rect();
|
||||
const ImRect inner_rect = window->InnerRect;
|
||||
const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar)
|
||||
IM_ASSERT(scrollbar_size > 0.0f);
|
||||
IM_ASSERT(scrollbar_size >= 0.0f);
|
||||
const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f);
|
||||
const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f;
|
||||
if (axis == ImGuiAxis_X)
|
||||
@@ -971,8 +973,8 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
||||
|
||||
// When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab)
|
||||
float alpha = 1.0f;
|
||||
if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f)
|
||||
alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f));
|
||||
if ((axis == ImGuiAxis_Y) && bb_frame_height < bb_frame_width)
|
||||
alpha = ImSaturate(bb_frame_height / ImMax(bb_frame_width * 2.0f, 1.0f));
|
||||
if (alpha <= 0.0f)
|
||||
return false;
|
||||
|
||||
@@ -989,7 +991,8 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
||||
// But we maintain a minimum size in pixel to allow for the user to still aim inside.
|
||||
IM_ASSERT(ImMax(size_contents_v, size_visible_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
|
||||
const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_visible_v), (ImS64)1);
|
||||
const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), style.GrabMinSize, scrollbar_size_v);
|
||||
const float grab_h_minsize = ImMin(bb.GetSize()[axis], style.GrabMinSize);
|
||||
const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v);
|
||||
const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
|
||||
|
||||
// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
|
||||
@@ -1061,25 +1064,45 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
||||
|
||||
// - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
|
||||
// - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above.
|
||||
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
|
||||
void ImGui::ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
const float border_size = (border_col.w > 0.0f) ? 1.0f : 0.0f;
|
||||
const ImVec2 padding(border_size, border_size);
|
||||
const ImVec2 padding(g.Style.ImageBorderSize, g.Style.ImageBorderSize);
|
||||
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + image_size + padding * 2.0f);
|
||||
ItemSize(bb);
|
||||
if (!ItemAdd(bb, 0))
|
||||
return;
|
||||
|
||||
// Render
|
||||
if (border_size > 0.0f)
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f, ImDrawFlags_None, border_size);
|
||||
if (g.Style.ImageBorderSize > 0.0f)
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), 0.0f, ImDrawFlags_None, g.Style.ImageBorderSize);
|
||||
if (bg_col.w > 0.0f)
|
||||
window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col));
|
||||
window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col));
|
||||
}
|
||||
|
||||
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1)
|
||||
{
|
||||
ImageWithBg(user_texture_id, image_size, uv0, uv1);
|
||||
}
|
||||
|
||||
// 1.91.9 (February 2025) removed 'tint_col' and 'border_col' parameters, made border size not depend on color value. (#8131, #8238)
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
PushStyleVar(ImGuiStyleVar_ImageBorderSize, (border_col.w > 0.0f) ? ImMax(1.0f, g.Style.ImageBorderSize) : 0.0f); // Preserve legacy behavior where border is always visible when border_col's Alpha is >0.0f
|
||||
PushStyleColor(ImGuiCol_Border, border_col);
|
||||
ImageWithBg(user_texture_id, image_size, uv0, uv1, ImVec4(0, 0, 0, 0), tint_col);
|
||||
PopStyleColor();
|
||||
PopStyleVar();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -1423,7 +1446,7 @@ bool ImGui::TextLink(const char* label)
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const char* label_end = FindRenderedTextEnd(label);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
|
||||
ImVec2 size = CalcTextSize(label, label_end, true);
|
||||
ImRect bb(pos, pos + size);
|
||||
ItemSize(size, 0.0f);
|
||||
@@ -1828,7 +1851,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
||||
ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags;
|
||||
ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.HasFlags;
|
||||
g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
@@ -1897,7 +1920,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
|
||||
if (!popup_open)
|
||||
return false;
|
||||
|
||||
g.NextWindowData.Flags = backup_next_window_data_flags;
|
||||
g.NextWindowData.HasFlags = backup_next_window_data_flags;
|
||||
return BeginComboPopup(popup_id, bb, flags);
|
||||
}
|
||||
|
||||
@@ -1912,7 +1935,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
|
||||
|
||||
// Set popup size
|
||||
float w = bb.GetWidth();
|
||||
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
|
||||
if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint)
|
||||
{
|
||||
g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);
|
||||
}
|
||||
@@ -1926,9 +1949,9 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
|
||||
else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
|
||||
else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20;
|
||||
ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX);
|
||||
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size
|
||||
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size
|
||||
constraint_min.x = w;
|
||||
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f)
|
||||
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f)
|
||||
constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
|
||||
SetNextWindowSizeConstraints(constraint_min, constraint_max);
|
||||
}
|
||||
@@ -2043,7 +2066,7 @@ static const char* Items_SingleStringGetter(void* data, int idx)
|
||||
{
|
||||
if (idx == items_count)
|
||||
break;
|
||||
p += strlen(p) + 1;
|
||||
p += ImStrlen(p) + 1;
|
||||
items_count++;
|
||||
}
|
||||
return *p ? p : NULL;
|
||||
@@ -2060,7 +2083,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo
|
||||
preview_value = getter(user_data, *current_item);
|
||||
|
||||
// The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here.
|
||||
if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint))
|
||||
if (popup_max_height_in_items != -1 && !(g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint))
|
||||
SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
|
||||
|
||||
if (!BeginCombo(label, preview_value, ImGuiComboFlags_None))
|
||||
@@ -2111,7 +2134,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa
|
||||
const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open
|
||||
while (*p)
|
||||
{
|
||||
p += strlen(p) + 1;
|
||||
p += ImStrlen(p) + 1;
|
||||
items_count++;
|
||||
}
|
||||
bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items);
|
||||
@@ -2621,7 +2644,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
// Tabbing or CTRL-clicking on Drag turns it into an InputText
|
||||
// Tabbing or CTRL+click on Drag turns it into an InputText
|
||||
const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id);
|
||||
const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft, id));
|
||||
const bool make_active = (clicked || double_clicked || g.NavActivateId == id);
|
||||
@@ -3225,7 +3248,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
// Tabbing or CTRL-clicking on Slider turns it into an input box
|
||||
// Tabbing or CTRL+click on Slider turns it into an input box
|
||||
const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id);
|
||||
const bool make_active = (clicked || g.NavActivateId == id);
|
||||
if (make_active && clicked)
|
||||
@@ -3878,7 +3901,7 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
|
||||
line_count++;
|
||||
if (s_eol == NULL)
|
||||
{
|
||||
s = s + strlen(s);
|
||||
s = s + ImStrlen(s);
|
||||
break;
|
||||
}
|
||||
s = s_eol + 1;
|
||||
@@ -4166,7 +4189,7 @@ void ImGuiInputTextState::OnCharPressed(unsigned int c)
|
||||
// The changes we had to make to stb_textedit_key made it very much UTF-8 specific which is not too great.
|
||||
char utf8[5];
|
||||
ImTextCharToUtf8(utf8, c);
|
||||
stb_textedit_text(this, Stb, utf8, (int)strlen(utf8));
|
||||
stb_textedit_text(this, Stb, utf8, (int)ImStrlen(utf8));
|
||||
CursorFollow = true;
|
||||
CursorAnimReset();
|
||||
}
|
||||
@@ -4217,7 +4240,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
|
||||
|
||||
// Grow internal buffer if needed
|
||||
const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0;
|
||||
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
|
||||
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)ImStrlen(new_text);
|
||||
if (new_text_len + BufTextLen >= BufSize)
|
||||
{
|
||||
if (!is_resizable)
|
||||
@@ -4251,7 +4274,7 @@ void ImGui::PushPasswordFont()
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImFont* in_font = g.Font;
|
||||
ImFont* out_font = &g.InputTextPasswordFont;
|
||||
const ImFontGlyph* glyph = in_font->FindGlyph('*');
|
||||
ImFontGlyph* glyph = in_font->FindGlyph('*');
|
||||
out_font->FontSize = in_font->FontSize;
|
||||
out_font->Scale = in_font->Scale;
|
||||
out_font->Ascent = in_font->Ascent;
|
||||
@@ -4273,7 +4296,13 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
|
||||
if (c < 0x20)
|
||||
{
|
||||
bool pass = false;
|
||||
pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code)
|
||||
pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code)
|
||||
if (c == '\n' && input_source_is_clipboard && (flags & ImGuiInputTextFlags_Multiline) == 0) // In single line mode, replace \n with a space
|
||||
{
|
||||
c = *p_char = ' ';
|
||||
pass = true;
|
||||
}
|
||||
pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0;
|
||||
pass |= (c == '\t') && (flags & ImGuiInputTextFlags_AllowTabInput) != 0;
|
||||
if (!pass)
|
||||
return false;
|
||||
@@ -4539,7 +4568,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
const bool init_state = (init_make_active || user_scroll_active);
|
||||
if (init_reload_from_user_buf)
|
||||
{
|
||||
int new_len = (int)strlen(buf);
|
||||
int new_len = (int)ImStrlen(buf);
|
||||
IM_ASSERT(new_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?");
|
||||
state->WantReloadUserBuf = false;
|
||||
InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len);
|
||||
@@ -4561,7 +4590,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// Take a copy of the initial buffer value.
|
||||
// From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode)
|
||||
const int buf_len = (int)strlen(buf);
|
||||
const int buf_len = (int)ImStrlen(buf);
|
||||
IM_ASSERT(buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?");
|
||||
state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
|
||||
memcpy(state->TextToRevertTo.Data, buf, buf_len + 1);
|
||||
@@ -4646,7 +4675,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// Read-only mode always ever read from source buffer. Refresh TextLen when active.
|
||||
if (is_readonly && state != NULL)
|
||||
state->TextLen = (int)strlen(buf);
|
||||
state->TextLen = (int)ImStrlen(buf);
|
||||
//if (is_readonly && state != NULL)
|
||||
// state->TextA.clear(); // Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th allocation.
|
||||
}
|
||||
@@ -4669,7 +4698,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// Select the buffer to render.
|
||||
const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state;
|
||||
const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
|
||||
bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
|
||||
|
||||
// Password pushes a temporary font with only a fallback glyph
|
||||
if (is_password && !is_displaying_hint)
|
||||
@@ -4803,14 +4832,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
|
||||
const bool is_startend_key_down = is_osx && io.KeyCtrl && !io.KeySuper && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
|
||||
|
||||
// Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText)
|
||||
// Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: former would be handled by InputText)
|
||||
// Otherwise we could simply assume that we own the keys as we are active.
|
||||
const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat;
|
||||
const bool is_cut = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_X, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, f_repeat, id)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
|
||||
const bool is_copy = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, 0, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, 0, id)) && !is_password && (!is_multiline || state->HasSelection());
|
||||
const bool is_paste = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_V, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, f_repeat, id)) && !is_readonly;
|
||||
const bool is_undo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable;
|
||||
const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || (is_osx && Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id))) && !is_readonly && is_undoable;
|
||||
const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable;
|
||||
const bool is_select_all = Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, 0, id);
|
||||
|
||||
// We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful.
|
||||
@@ -4925,7 +4954,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (const char* clipboard = GetClipboardText())
|
||||
{
|
||||
// Filter pasted buffer
|
||||
const int clipboard_len = (int)strlen(clipboard);
|
||||
const int clipboard_len = (int)ImStrlen(clipboard);
|
||||
ImVector<char> clipboard_filtered;
|
||||
clipboard_filtered.reserve(clipboard_len + 1);
|
||||
for (const char* s = clipboard; *s != 0; )
|
||||
@@ -4937,7 +4966,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
continue;
|
||||
char c_utf8[5];
|
||||
ImTextCharToUtf8(c_utf8, c);
|
||||
int out_len = (int)strlen(c_utf8);
|
||||
int out_len = (int)ImStrlen(c_utf8);
|
||||
clipboard_filtered.resize(clipboard_filtered.Size + out_len);
|
||||
memcpy(clipboard_filtered.Data + clipboard_filtered.Size - out_len, c_utf8, out_len);
|
||||
}
|
||||
@@ -5067,7 +5096,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (buf_dirty)
|
||||
{
|
||||
// Callback may update buffer and thus set buf_dirty even in read-only mode.
|
||||
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
||||
IM_ASSERT(callback_data.BufTextLen == (int)ImStrlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
||||
InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen);
|
||||
state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
|
||||
state->CursorAnimReset();
|
||||
@@ -5151,10 +5180,22 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
const int buf_display_max_length = 2 * 1024 * 1024;
|
||||
const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595
|
||||
const char* buf_display_end = NULL; // We have specialized paths below for setting the length
|
||||
|
||||
// Display hint when contents is empty
|
||||
// At this point we need to handle the possibility that a callback could have modified the underlying buffer (#8368)
|
||||
const bool new_is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
|
||||
if (new_is_displaying_hint != is_displaying_hint)
|
||||
{
|
||||
if (is_password && !is_displaying_hint)
|
||||
PopFont();
|
||||
is_displaying_hint = new_is_displaying_hint;
|
||||
if (is_password && !is_displaying_hint)
|
||||
PushPasswordFont();
|
||||
}
|
||||
if (is_displaying_hint)
|
||||
{
|
||||
buf_display = hint;
|
||||
buf_display_end = hint + strlen(hint);
|
||||
buf_display_end = hint + ImStrlen(hint);
|
||||
}
|
||||
|
||||
// Render text. We currently only render selection when the widget is active or while scrolling.
|
||||
@@ -5187,7 +5228,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
int line_count = 1;
|
||||
if (is_multiline)
|
||||
{
|
||||
for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
|
||||
for (const char* s = text_begin; (s = (const char*)ImMemchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
|
||||
{
|
||||
if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_no = line_count; }
|
||||
if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_no = line_count; }
|
||||
@@ -5265,7 +5306,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
break;
|
||||
if (rect_pos.y < clip_rect.y)
|
||||
{
|
||||
p = (const char*)memchr((void*)p, '\n', text_selected_end - p);
|
||||
p = (const char*)ImMemchr((void*)p, '\n', text_selected_end - p);
|
||||
p = p ? p + 1 : text_selected_end;
|
||||
}
|
||||
else
|
||||
@@ -5317,7 +5358,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
else if (!is_displaying_hint && g.ActiveId == id)
|
||||
buf_display_end = buf_display + state->TextLen;
|
||||
else if (!is_displaying_hint)
|
||||
buf_display_end = buf_display + strlen(buf_display);
|
||||
buf_display_end = buf_display + ImStrlen(buf_display);
|
||||
|
||||
if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
|
||||
{
|
||||
@@ -5462,7 +5503,7 @@ static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V)
|
||||
|
||||
// Edit colors components (each component in 0.0f..1.0f range).
|
||||
// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
|
||||
// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item.
|
||||
// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL+Click over input fields to edit them and TAB to go to next item.
|
||||
bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
@@ -6166,7 +6207,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
|
||||
if (g.Style.FrameBorderSize > 0.0f)
|
||||
RenderFrameBorder(bb.Min, bb.Max, rounding);
|
||||
else
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
|
||||
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border
|
||||
}
|
||||
|
||||
// Drag and Drop Source
|
||||
@@ -7088,7 +7129,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
|
||||
// Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns.
|
||||
if (is_visible)
|
||||
RenderTextClipped(pos, ImVec2(window->WorkRect.Max.x, pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb);
|
||||
RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb);
|
||||
|
||||
// Automatically close popups
|
||||
if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups))
|
||||
@@ -7151,7 +7192,7 @@ ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags f
|
||||
|
||||
// Append to buffer
|
||||
const int buffer_max_len = IM_ARRAYSIZE(data->SearchBuffer) - 1;
|
||||
int buffer_len = (int)strlen(data->SearchBuffer);
|
||||
int buffer_len = (int)ImStrlen(data->SearchBuffer);
|
||||
bool select_request = false;
|
||||
for (ImWchar w : g.IO.InputQueueCharacters)
|
||||
{
|
||||
@@ -8834,7 +8875,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
if (g.MenusIdSubmittedThisFrame.contains(id))
|
||||
{
|
||||
if (menu_is_open)
|
||||
menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
else
|
||||
g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values
|
||||
return menu_is_open;
|
||||
@@ -8865,7 +8906,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups;
|
||||
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
|
||||
{
|
||||
// Menu inside an horizontal menu bar
|
||||
// Menu inside a horizontal menu bar
|
||||
// Selectable extend their highlight by half ItemSpacing in each direction.
|
||||
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
|
||||
popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight);
|
||||
@@ -8996,7 +9037,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
ImGuiLastItemData last_item_in_parent = g.LastItemData;
|
||||
SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos.
|
||||
PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding
|
||||
menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open may be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
PopStyleVar();
|
||||
if (menu_is_open)
|
||||
{
|
||||
@@ -10078,7 +10119,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
else
|
||||
{
|
||||
tab->NameOffset = (ImS32)tab_bar->TabsNames.size();
|
||||
tab_bar->TabsNames.append(label, label + strlen(label) + 1);
|
||||
tab_bar->TabsNames.append(label, label + ImStrlen(label) + 1);
|
||||
}
|
||||
|
||||
// Update selected tab
|
||||
@@ -10355,13 +10396,24 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
|
||||
// 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false
|
||||
bool close_button_pressed = false;
|
||||
bool close_button_visible = false;
|
||||
if (close_button_id != 0)
|
||||
if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton))
|
||||
if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id)
|
||||
close_button_visible = true;
|
||||
bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x);
|
||||
bool is_hovered = g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id; // Any interaction account for this too.
|
||||
|
||||
if (close_button_visible)
|
||||
if (close_button_id != 0)
|
||||
{
|
||||
if (is_contents_visible)
|
||||
close_button_visible = (g.Style.TabCloseButtonMinWidthSelected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthSelected));
|
||||
else
|
||||
close_button_visible = (g.Style.TabCloseButtonMinWidthUnselected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthUnselected));
|
||||
}
|
||||
|
||||
// When tabs/document is unsaved, the unsaved marker takes priority over the close button.
|
||||
const bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x) && (!close_button_visible || !is_hovered);
|
||||
if (unsaved_marker_visible)
|
||||
{
|
||||
const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz));
|
||||
RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text));
|
||||
}
|
||||
else if (close_button_visible)
|
||||
{
|
||||
ImGuiLastItemData last_item_backup = g.LastItemData;
|
||||
if (CloseButton(close_button_id, button_pos))
|
||||
@@ -10369,14 +10421,9 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
|
||||
g.LastItemData = last_item_backup;
|
||||
|
||||
// Close with middle mouse button
|
||||
if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
|
||||
if (is_hovered && !(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
|
||||
close_button_pressed = true;
|
||||
}
|
||||
else if (unsaved_marker_visible)
|
||||
{
|
||||
const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz));
|
||||
RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text));
|
||||
}
|
||||
|
||||
// This is all rather complicated
|
||||
// (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position)
|
||||
|
||||
15
3rdparty/rapidyaml/CMakeLists.txt
vendored
15
3rdparty/rapidyaml/CMakeLists.txt
vendored
@@ -34,15 +34,26 @@ add_library(pcsx2-rapidyaml
|
||||
include/c4/yml/detail/stack.hpp
|
||||
include/c4/yml/emit.def.hpp
|
||||
include/c4/yml/emit.hpp
|
||||
include/c4/yml/event_handler_stack.hpp
|
||||
include/c4/yml/event_handler_tree.hpp
|
||||
include/c4/yml/filter_processor.hpp
|
||||
include/c4/yml/fwd.hpp
|
||||
include/c4/yml/export.hpp
|
||||
include/c4/yml/node.hpp
|
||||
include/c4/yml/node_type.hpp
|
||||
include/c4/yml/parse.hpp
|
||||
include/c4/yml/parse_engine.def.hpp
|
||||
include/c4/yml/parse_engine.hpp
|
||||
include/c4/yml/parser_state.hpp
|
||||
include/c4/yml/reference_resolver.hpp
|
||||
include/c4/yml/preprocess.hpp
|
||||
include/c4/yml/std/map.hpp
|
||||
include/c4/yml/std/std.hpp
|
||||
include/c4/yml/std/string.hpp
|
||||
include/c4/yml/std/vector.hpp
|
||||
include/c4/yml/tag.hpp
|
||||
include/c4/yml/tree.hpp
|
||||
include/c4/yml/version.hpp
|
||||
include/c4/yml/writer.hpp
|
||||
include/c4/yml/yml.hpp
|
||||
include/ryml.hpp
|
||||
@@ -58,6 +69,10 @@ add_library(pcsx2-rapidyaml
|
||||
src/c4/yml/parse.cpp
|
||||
src/c4/yml/preprocess.cpp
|
||||
src/c4/yml/tree.cpp
|
||||
src/c4/yml/node_type.cpp
|
||||
src/c4/yml/reference_resolver.cpp
|
||||
src/c4/yml/tag.cpp
|
||||
src/c4/yml/version.cpp
|
||||
)
|
||||
|
||||
target_include_directories(pcsx2-rapidyaml PRIVATE
|
||||
|
||||
26
3rdparty/rapidyaml/include/c4/blob.hpp
vendored
26
3rdparty/rapidyaml/include/c4/blob.hpp
vendored
@@ -18,6 +18,8 @@ template<class T> struct is_blob_type<blob_<T>> : std::integral_constant<bool, t
|
||||
template<class T> struct is_blob_value_type : std::integral_constant<bool, (std::is_fundamental<T>::value || std::is_trivially_copyable<T>::value)> {};
|
||||
} // namespace
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
|
||||
template<class T>
|
||||
struct blob_
|
||||
{
|
||||
@@ -37,23 +39,25 @@ public:
|
||||
C4_ALWAYS_INLINE blob_& operator=(blob_ && that) noexcept = default;
|
||||
C4_ALWAYS_INLINE blob_& operator=(blob_ const& that) noexcept = default;
|
||||
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> const& that) noexcept : buf(that.buf), len(that.len) {}
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> && that) noexcept : buf(that.buf), len(that.len) {}
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> && that) noexcept { buf = that.buf; len = that.len; }
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> const& that) noexcept { buf = that.buf; len = that.len; }
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> const& that) noexcept : buf(that.buf), len(that.len) {} // NOLINT
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> && that) noexcept : buf(that.buf), len(that.len) {} // NOLINT
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> && that) noexcept { buf = that.buf; len = that.len; } // NOLINT
|
||||
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> const& that) noexcept { buf = that.buf; len = that.len; } // NOLINT
|
||||
|
||||
C4_ALWAYS_INLINE blob_(void *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {}
|
||||
C4_ALWAYS_INLINE blob_(void const *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {}
|
||||
C4_ALWAYS_INLINE blob_(void *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {} // NOLINT
|
||||
C4_ALWAYS_INLINE blob_(void const *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {} // NOLINT
|
||||
|
||||
#define _C4_REQUIRE_BLOBTYPE(ty) class=typename std::enable_if<((!detail::is_blob_type<ty>::value) && (detail::is_blob_value_type<ty>::value)), T>::type
|
||||
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U &var) noexcept : buf(reinterpret_cast<T*>(&var)), len(sizeof(U)) {}
|
||||
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(sizeof(U) * n) { C4_ASSERT(is_aligned(ptr)); }
|
||||
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U &var) noexcept { buf = reinterpret_cast<T*>(&var); len = sizeof(U); return *this; }
|
||||
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U (&arr)[N]) noexcept : buf(reinterpret_cast<T*>(arr)), len(sizeof(U) * N) {}
|
||||
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U (&arr)[N]) noexcept { buf = reinterpret_cast<T*>(arr); len = sizeof(U) * N; return *this; }
|
||||
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U &var) noexcept : buf(reinterpret_cast<T*>(&var)), len(sizeof(U)) {} // NOLINT
|
||||
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(sizeof(U) * n) { C4_ASSERT(is_aligned(ptr)); } // NOLINT
|
||||
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U &var) noexcept { buf = reinterpret_cast<T*>(&var); len = sizeof(U); return *this; } // NOLINT
|
||||
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U (&arr)[N]) noexcept : buf(reinterpret_cast<T*>(arr)), len(sizeof(U) * N) {} // NOLINT
|
||||
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U (&arr)[N]) noexcept { buf = reinterpret_cast<T*>(arr); len = sizeof(U) * N; return *this; } // NOLINT
|
||||
#undef _C4_REQUIRE_BLOBTYPE
|
||||
};
|
||||
|
||||
// NOLINTEND(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
|
||||
/** an immutable binary blob */
|
||||
using cblob = blob_<cbyte>;
|
||||
/** a mutable binary blob */
|
||||
|
||||
148
3rdparty/rapidyaml/include/c4/charconv.hpp
vendored
148
3rdparty/rapidyaml/include/c4/charconv.hpp
vendored
@@ -55,14 +55,7 @@
|
||||
# define C4CORE_HAVE_FAST_FLOAT 1
|
||||
# endif
|
||||
# if C4CORE_HAVE_FAST_FLOAT
|
||||
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wsign-conversion")
|
||||
C4_SUPPRESS_WARNING_GCC("-Warray-bounds")
|
||||
# if defined(__GNUC__) && __GNUC__ >= 5
|
||||
C4_SUPPRESS_WARNING_GCC("-Wshift-count-overflow")
|
||||
# endif
|
||||
//# include "c4/ext/fast_float.hpp"
|
||||
#include "fast_float/fast_float.h"
|
||||
C4_SUPPRESS_WARNING_GCC_POP
|
||||
# endif
|
||||
#elif (C4_CPP >= 17)
|
||||
# define C4CORE_HAVE_FAST_FLOAT 0
|
||||
@@ -102,15 +95,13 @@
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996) // snprintf/scanf: this function or variable may be unsafe
|
||||
# if C4_MSVC_VERSION != C4_MSVC_VERSION_2017
|
||||
# pragma warning(disable: 4800) //'int': forcing value to bool 'true' or 'false' (performance warning)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
|
||||
# pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
@@ -136,6 +127,7 @@
|
||||
#define C4_NO_UBSAN_IOVRFLW
|
||||
#endif
|
||||
|
||||
// NOLINTBEGIN(hicpp-signed-bitwise)
|
||||
|
||||
namespace c4 {
|
||||
|
||||
@@ -144,11 +136,11 @@ namespace c4 {
|
||||
* Lightweight, very fast generic type-safe wrappers for converting
|
||||
* individual values to/from strings. These are the main generic
|
||||
* functions:
|
||||
* - @ref doc_to_chars and its alias @ref doc_xtoa: implemented by calling @ref itoa()/@ref utoa()/@ref ftoa()/@ref dtoa() (or generically @ref xtoa())
|
||||
* - @ref doc_from_chars and its alias @ref doc_atox: implemented by calling @ref atoi()/@ref atou()/@ref atof()/@ref atod() (or generically @ref atox())
|
||||
* - @ref doc_to_chars and its alias @ref xtoa(): implemented by calling @ref itoa() / @ref utoa() / @ref ftoa() / @ref dtoa() (or generically @ref xtoa())
|
||||
* - @ref doc_from_chars and its alias @ref atox(): implemented by calling @ref atoi() / @ref atou() / @ref atof() / @ref atod() (or generically @ref atox())
|
||||
* - @ref to_chars_sub()
|
||||
* - @ref from_chars_first()
|
||||
* - @ref xtoa()/@ref atox() are implemented in terms @ref write_dec()/@ref read_dec() et al (see @ref doc_write/@ref doc_read())
|
||||
* - @ref xtoa() and @ref atox() are implemented in terms of @ref write_dec() / @ref read_dec() et al (see @ref doc_write / @ref doc_read())
|
||||
*
|
||||
* And also some modest brag is in order: these functions are really
|
||||
* fast: faster even than C++17 `std::to_chars()` and
|
||||
@@ -241,7 +233,7 @@ struct is_fixed_length
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# pragma warning(push)
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
@@ -377,7 +369,7 @@ template<> struct charconv_digits_<4u, false> // uint32_t
|
||||
static constexpr csubstr max_value_dec() noexcept { return csubstr("4294967295"); }
|
||||
static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 11) || (str.len == 11 && str[0] <= '3')); }
|
||||
};
|
||||
template<> struct charconv_digits_<8u, true> // int32_t
|
||||
template<> struct charconv_digits_<8u, true> // int64_t
|
||||
{
|
||||
enum : size_t {
|
||||
maxdigits_bin = 1 + 2 + 64, // len=67: -9223372036854775808 -0b1000000000000000000000000000000000000000000000000000000000000000
|
||||
@@ -396,7 +388,7 @@ template<> struct charconv_digits_<8u, true> // int32_t
|
||||
static constexpr csubstr max_value_dec() noexcept { return csubstr("9223372036854775807"); }
|
||||
static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 22)); }
|
||||
};
|
||||
template<> struct charconv_digits_<8u, false>
|
||||
template<> struct charconv_digits_<8u, false> // uint64_t
|
||||
{
|
||||
enum : size_t {
|
||||
maxdigits_bin = 2 + 64, // len=66: 18446744073709551615 0b1111111111111111111111111111111111111111111111111111111111111111
|
||||
@@ -545,24 +537,25 @@ C4_CONSTEXPR14 C4_ALWAYS_INLINE unsigned digits_oct(T v_) noexcept
|
||||
// TODO: is there a better way?
|
||||
C4_STATIC_ASSERT(std::is_integral<T>::value);
|
||||
C4_ASSERT(v_ >= 0);
|
||||
using U = typename
|
||||
std::conditional<sizeof(T) <= sizeof(unsigned),
|
||||
unsigned,
|
||||
typename std::make_unsigned<T>::type>::type;
|
||||
U v = (U) v_; // safe because we require v_ >= 0
|
||||
unsigned __n = 1;
|
||||
const unsigned __b2 = 64u;
|
||||
const unsigned __b3 = __b2 * 8u;
|
||||
const unsigned long __b4 = __b3 * 8u;
|
||||
using U = typename std::conditional<sizeof(T) <= sizeof(unsigned),
|
||||
unsigned,
|
||||
typename std::make_unsigned<T>::type>::type;
|
||||
U v = (U) v_; // safe because we require v_ >= 0 // NOLINT
|
||||
uint32_t __n = 1;
|
||||
enum : U {
|
||||
__b2 = 64u,
|
||||
__b3 = 64u * 8u,
|
||||
__b4 = 64u * 8u * 8u,
|
||||
};
|
||||
while(true)
|
||||
{
|
||||
if(v < 8u)
|
||||
return __n;
|
||||
if(v < __b2)
|
||||
else if(v < __b2)
|
||||
return __n + 1;
|
||||
if(v < __b3)
|
||||
else if(v < __b3)
|
||||
return __n + 2;
|
||||
if(v < __b4)
|
||||
else if(v < __b4)
|
||||
return __n + 3;
|
||||
v /= (U) __b4;
|
||||
__n += 4;
|
||||
@@ -617,7 +610,7 @@ void write_dec_unchecked(substr buf, T v, unsigned digits_v) noexcept
|
||||
{
|
||||
T quo = v;
|
||||
quo /= T(100);
|
||||
const auto num = (v - quo * T(100)) << 1u;
|
||||
const auto num = (v - quo * T(100)) << 1u; // NOLINT
|
||||
v = quo;
|
||||
buf.str[--digits_v] = detail::digits0099[num + 1];
|
||||
buf.str[--digits_v] = detail::digits0099[num];
|
||||
@@ -782,15 +775,18 @@ template<class T, NumberWriter<T> writer>
|
||||
size_t write_num_digits(substr buf, T v, size_t num_digits) noexcept
|
||||
{
|
||||
C4_STATIC_ASSERT(std::is_integral<T>::value);
|
||||
size_t ret = writer(buf, v);
|
||||
const size_t ret = writer(buf, v);
|
||||
if(ret >= num_digits)
|
||||
return ret;
|
||||
else if(ret >= buf.len || num_digits > buf.len)
|
||||
return num_digits;
|
||||
C4_ASSERT(num_digits >= ret);
|
||||
size_t delta = static_cast<size_t>(num_digits - ret);
|
||||
memmove(buf.str + delta, buf.str, ret);
|
||||
memset(buf.str, '0', delta);
|
||||
const size_t delta = static_cast<size_t>(num_digits - ret); // NOLINT
|
||||
C4_ASSERT(ret + delta <= buf.len);
|
||||
if(ret)
|
||||
memmove(buf.str + delta, buf.str, ret);
|
||||
if(delta)
|
||||
memset(buf.str, '0', delta);
|
||||
return num_digits;
|
||||
}
|
||||
} // namespace detail
|
||||
@@ -985,7 +981,9 @@ C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wswitch-default")
|
||||
namespace detail {
|
||||
inline size_t _itoa2buf(substr buf, size_t pos, csubstr val) noexcept
|
||||
{
|
||||
C4_ASSERT(pos < buf.len);
|
||||
C4_ASSERT(pos + val.len <= buf.len);
|
||||
C4_ASSERT(val.len > 0);
|
||||
memcpy(buf.str + pos, val.str, val.len);
|
||||
return pos + val.len;
|
||||
}
|
||||
@@ -1013,7 +1011,7 @@ C4_NO_INLINE size_t _itoa2buf(substr buf, I radix) noexcept
|
||||
size_t pos = 0;
|
||||
if(C4_LIKELY(buf.len > 0))
|
||||
buf.str[pos++] = '-';
|
||||
switch(radix)
|
||||
switch(radix) // NOLINT(hicpp-multiway-paths-covered)
|
||||
{
|
||||
case I(10):
|
||||
if(C4_UNLIKELY(buf.len < digits_type::maxdigits_dec))
|
||||
@@ -1052,7 +1050,7 @@ C4_NO_INLINE size_t _itoa2buf(substr buf, I radix, size_t num_digits) noexcept
|
||||
size_t needed_digits = 0;
|
||||
if(C4_LIKELY(buf.len > 0))
|
||||
buf.str[pos++] = '-';
|
||||
switch(radix)
|
||||
switch(radix) // NOLINT(hicpp-multiway-paths-covered)
|
||||
{
|
||||
case I(10):
|
||||
// add 1 to account for -
|
||||
@@ -1117,7 +1115,7 @@ C4_ALWAYS_INLINE size_t itoa(substr buf, T v) noexcept
|
||||
}
|
||||
// when T is the min value (eg i8: -128), negating it
|
||||
// will overflow, so treat the min as a special case
|
||||
else if(C4_LIKELY(v != std::numeric_limits<T>::min()))
|
||||
if(C4_LIKELY(v != std::numeric_limits<T>::min()))
|
||||
{
|
||||
v = -v;
|
||||
unsigned digits = digits_dec(v);
|
||||
@@ -1160,7 +1158,7 @@ C4_ALWAYS_INLINE size_t itoa(substr buf, T v, T radix) noexcept
|
||||
++pos;
|
||||
}
|
||||
unsigned digits = 0;
|
||||
switch(radix)
|
||||
switch(radix) // NOLINT(hicpp-multiway-paths-covered)
|
||||
{
|
||||
case T(10):
|
||||
digits = digits_dec(v);
|
||||
@@ -1237,7 +1235,7 @@ C4_ALWAYS_INLINE size_t itoa(substr buf, T v, T radix, size_t num_digits) noexce
|
||||
++pos;
|
||||
}
|
||||
unsigned total_digits = 0;
|
||||
switch(radix)
|
||||
switch(radix) // NOLINT(hicpp-multiway-paths-covered)
|
||||
{
|
||||
case T(10):
|
||||
total_digits = digits_dec(v);
|
||||
@@ -1322,7 +1320,7 @@ C4_ALWAYS_INLINE size_t utoa(substr buf, T v, T radix) noexcept
|
||||
C4_STATIC_ASSERT(std::is_unsigned<T>::value);
|
||||
C4_ASSERT(radix == 10 || radix == 16 || radix == 2 || radix == 8);
|
||||
unsigned digits = 0;
|
||||
switch(radix)
|
||||
switch(radix) // NOLINT(hicpp-multiway-paths-covered)
|
||||
{
|
||||
case T(10):
|
||||
digits = digits_dec(v);
|
||||
@@ -1377,7 +1375,7 @@ C4_ALWAYS_INLINE size_t utoa(substr buf, T v, T radix, size_t num_digits) noexce
|
||||
C4_STATIC_ASSERT(std::is_unsigned<T>::value);
|
||||
C4_ASSERT(radix == 10 || radix == 16 || radix == 2 || radix == 8);
|
||||
unsigned total_digits = 0;
|
||||
switch(radix)
|
||||
switch(radix) // NOLINT(hicpp-multiway-paths-covered)
|
||||
{
|
||||
case T(10):
|
||||
total_digits = digits_dec(v);
|
||||
@@ -1601,7 +1599,7 @@ C4_ALWAYS_INLINE size_t atou_first(csubstr str, T *v)
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# pragma warning(pop)
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
@@ -1618,19 +1616,16 @@ C4_ALWAYS_INLINE size_t atou_first(csubstr str, T *v)
|
||||
namespace detail {
|
||||
inline bool check_overflow(csubstr str, csubstr limit) noexcept
|
||||
{
|
||||
if(str.len == limit.len)
|
||||
{
|
||||
for(size_t i = 0; i < limit.len; ++i)
|
||||
{
|
||||
if(str[i] < limit[i])
|
||||
return false;
|
||||
else if(str[i] > limit[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if(str.len != limit.len)
|
||||
return str.len > limit.len;
|
||||
for(size_t i = 0; i < limit.len; ++i)
|
||||
{
|
||||
if(str[i] < limit[i])
|
||||
return false;
|
||||
else if(str[i] > limit[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace detail
|
||||
/** @endcond */
|
||||
@@ -1714,7 +1709,7 @@ auto overflows(csubstr str) noexcept
|
||||
* @see doc_overflow_checked for format specifiers to enforce no-overflow reads
|
||||
*/
|
||||
template<class T>
|
||||
auto overflows(csubstr str)
|
||||
auto overflows(csubstr str) noexcept
|
||||
-> typename std::enable_if<std::is_signed<T>::value, bool>::type
|
||||
{
|
||||
C4_STATIC_ASSERT(std::is_integral<T>::value);
|
||||
@@ -1762,7 +1757,9 @@ auto overflows(csubstr str)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return detail::check_overflow(str.sub(1), detail::charconv_digits<T>::min_value_dec());
|
||||
}
|
||||
}
|
||||
else if(str.str[0] == '0')
|
||||
{
|
||||
@@ -1805,7 +1802,9 @@ auto overflows(csubstr str)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return detail::check_overflow(str, detail::charconv_digits<T>::max_value_dec());
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -1989,7 +1988,7 @@ C4_ALWAYS_INLINE bool scan_rhex(csubstr s, T *C4_RESTRICT val) noexcept
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power; // no mantissa given, jump to power
|
||||
goto power; // no mantissa given, jump to power // NOLINT
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1999,7 +1998,7 @@ C4_ALWAYS_INLINE bool scan_rhex(csubstr s, T *C4_RESTRICT val) noexcept
|
||||
// mantissa
|
||||
{
|
||||
// 0.0625 == 1/16 == value of first digit after the comma
|
||||
for(T digit = T(0.0625); pos < s.len; ++pos, digit /= T(16))
|
||||
for(T digit = T(0.0625); pos < s.len; ++pos, digit /= T(16)) // NOLINT
|
||||
{
|
||||
const char c = s.str[pos];
|
||||
if(c >= '0' && c <= '9')
|
||||
@@ -2011,7 +2010,7 @@ C4_ALWAYS_INLINE bool scan_rhex(csubstr s, T *C4_RESTRICT val) noexcept
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power; // mantissa finished, jump to power
|
||||
goto power; // mantissa finished, jump to power // NOLINT
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2172,6 +2171,7 @@ inline size_t atof_first(csubstr str, float * C4_RESTRICT v) noexcept
|
||||
*/
|
||||
C4_ALWAYS_INLINE bool atod(csubstr str, double * C4_RESTRICT v) noexcept
|
||||
{
|
||||
C4_ASSERT(str.len > 0);
|
||||
C4_ASSERT(str.triml(" \r\t\n").len == str.len);
|
||||
#if C4CORE_HAVE_FAST_FLOAT
|
||||
// fastfloat cannot parse hexadecimal floats
|
||||
@@ -2228,8 +2228,8 @@ inline size_t atod_first(csubstr str, double * C4_RESTRICT v) noexcept
|
||||
/** @cond dev */
|
||||
// on some platforms, (unsigned) int and (unsigned) long
|
||||
// are not any of the fixed length types above
|
||||
#define _C4_IF_NOT_FIXED_LENGTH_I(T, ty) C4_ALWAYS_INLINE typename std::enable_if<std:: is_signed<T>::value && !is_fixed_length<T>::value_i, ty>
|
||||
#define _C4_IF_NOT_FIXED_LENGTH_U(T, ty) C4_ALWAYS_INLINE typename std::enable_if<std::is_unsigned<T>::value && !is_fixed_length<T>::value_u, ty>
|
||||
#define _C4_IF_NOT_FIXED_LENGTH_I(T, ty) typename std::enable_if<std:: is_signed<T>::value && !is_fixed_length<T>::value_i, ty>
|
||||
#define _C4_IF_NOT_FIXED_LENGTH_U(T, ty) typename std::enable_if<std::is_unsigned<T>::value && !is_fixed_length<T>::value_u, ty>
|
||||
/** @endcond*/
|
||||
|
||||
|
||||
@@ -2271,8 +2271,8 @@ C4_ALWAYS_INLINE size_t xtoa(substr s, int64_t v, int64_t radix, size_t num_di
|
||||
C4_ALWAYS_INLINE size_t xtoa(substr s, float v, int precision, RealFormat_e formatting=FTOA_FLEX) noexcept { return ftoa(s, v, precision, formatting); }
|
||||
C4_ALWAYS_INLINE size_t xtoa(substr s, double v, int precision, RealFormat_e formatting=FTOA_FLEX) noexcept { return dtoa(s, v, precision, formatting); }
|
||||
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type xtoa(substr buf, T v) noexcept { return itoa(buf, v); }
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type xtoa(substr buf, T v) noexcept { return write_dec(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto xtoa(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type { return itoa(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto xtoa(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type { return write_dec(buf, v); }
|
||||
template <class T>
|
||||
C4_ALWAYS_INLINE size_t xtoa(substr s, T *v) noexcept { return itoa(s, (intptr_t)v, (intptr_t)16); }
|
||||
|
||||
@@ -2296,8 +2296,8 @@ C4_ALWAYS_INLINE bool atox(csubstr s, int64_t *C4_RESTRICT v) noexcept { return
|
||||
C4_ALWAYS_INLINE bool atox(csubstr s, float *C4_RESTRICT v) noexcept { return atof(s, v); }
|
||||
C4_ALWAYS_INLINE bool atox(csubstr s, double *C4_RESTRICT v) noexcept { return atod(s, v); }
|
||||
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_I(T, bool )::type atox(csubstr buf, T *C4_RESTRICT v) noexcept { return atoi(buf, v); }
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_U(T, bool )::type atox(csubstr buf, T *C4_RESTRICT v) noexcept { return atou(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto atox(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, bool)::type { return atoi(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto atox(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, bool)::type { return atou(buf, v); }
|
||||
template <class T>
|
||||
C4_ALWAYS_INLINE bool atox(csubstr s, T **v) noexcept { intptr_t tmp; bool ret = atox(s, &tmp); if(ret) { *v = (T*)tmp; } return ret; }
|
||||
|
||||
@@ -2336,8 +2336,8 @@ C4_ALWAYS_INLINE size_t to_chars(substr buf, int64_t v) noexcept { return itoa(
|
||||
C4_ALWAYS_INLINE size_t to_chars(substr buf, float v) noexcept { return ftoa(buf, v); }
|
||||
C4_ALWAYS_INLINE size_t to_chars(substr buf, double v) noexcept { return dtoa(buf, v); }
|
||||
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type to_chars(substr buf, T v) noexcept { return itoa(buf, v); }
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type to_chars(substr buf, T v) noexcept { return write_dec(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto to_chars(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type { return itoa(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto to_chars(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type { return write_dec(buf, v); }
|
||||
template <class T>
|
||||
C4_ALWAYS_INLINE size_t to_chars(substr s, T *v) noexcept { return itoa(s, (intptr_t)v, (intptr_t)16); }
|
||||
|
||||
@@ -2371,8 +2371,8 @@ C4_ALWAYS_INLINE bool from_chars(csubstr buf, int64_t *C4_RESTRICT v) noexcept
|
||||
C4_ALWAYS_INLINE bool from_chars(csubstr buf, float *C4_RESTRICT v) noexcept { return atof(buf, v); }
|
||||
C4_ALWAYS_INLINE bool from_chars(csubstr buf, double *C4_RESTRICT v) noexcept { return atod(buf, v); }
|
||||
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_I(T, bool )::type from_chars(csubstr buf, T *C4_RESTRICT v) noexcept { return atoi(buf, v); }
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_U(T, bool )::type from_chars(csubstr buf, T *C4_RESTRICT v) noexcept { return atou(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto from_chars(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, bool)::type { return atoi(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto from_chars(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, bool)::type { return atou(buf, v); }
|
||||
template <class T>
|
||||
C4_ALWAYS_INLINE bool from_chars(csubstr buf, T **v) noexcept { intptr_t tmp; bool ret = from_chars(buf, &tmp); if(ret) { *v = (T*)tmp; } return ret; }
|
||||
|
||||
@@ -2399,8 +2399,8 @@ C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, int64_t *C4_RESTRICT v) n
|
||||
C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, float *C4_RESTRICT v) noexcept { return atof_first(buf, v); }
|
||||
C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, double *C4_RESTRICT v) noexcept { return atod_first(buf, v); }
|
||||
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type from_chars_first(csubstr buf, T *C4_RESTRICT v) noexcept { return atoi_first(buf, v); }
|
||||
template <class T> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type from_chars_first(csubstr buf, T *C4_RESTRICT v) noexcept { return atou_first(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto from_chars_first(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type { return atoi_first(buf, v); }
|
||||
template <class T> C4_ALWAYS_INLINE auto from_chars_first(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type { return atou_first(buf, v); }
|
||||
template <class T>
|
||||
C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, T **v) noexcept { intptr_t tmp; bool ret = from_chars_first(buf, &tmp); if(ret) { *v = (T*)tmp; } return ret; }
|
||||
|
||||
@@ -2657,11 +2657,11 @@ inline size_t to_chars(substr buf, const char * C4_RESTRICT v) noexcept
|
||||
|
||||
} // namespace c4
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
// NOLINTEND(hicpp-signed-bitwise)
|
||||
|
||||
#if defined(__clang__)
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# pragma warning(pop)
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
|
||||
5
3rdparty/rapidyaml/include/c4/compiler.hpp
vendored
5
3rdparty/rapidyaml/include/c4/compiler.hpp
vendored
@@ -24,7 +24,7 @@
|
||||
/** @see http://sourceforge.net/p/predef/wiki/Compilers/ for a list of compiler identifier macros */
|
||||
/** @see https://msdn.microsoft.com/en-us/library/b0084kay.aspx for VS2013 predefined macros */
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#if defined(_MSC_VER)
|
||||
# define C4_MSVC
|
||||
# define C4_MSVC_VERSION_2022 17
|
||||
# define C4_MSVC_VERSION_2019 16
|
||||
@@ -93,6 +93,9 @@
|
||||
# define C4_CLANG_VERSION __apple_build_version__
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# ifdef __MINGW32__
|
||||
# define C4_MINGW
|
||||
# endif
|
||||
# define C4_GCC
|
||||
# if defined(__GNUC_PATCHLEVEL__)
|
||||
# define C4_GCC_VERSION C4_VERSION_ENCODED(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
54
3rdparty/rapidyaml/include/c4/cpu.hpp
vendored
54
3rdparty/rapidyaml/include/c4/cpu.hpp
vendored
@@ -7,7 +7,7 @@
|
||||
// see also https://sourceforge.net/p/predef/wiki/Architectures/
|
||||
// see also https://sourceforge.net/p/predef/wiki/Endianness/
|
||||
// see also https://github.com/googlesamples/android-ndk/blob/android-mk/hello-jni/jni/hello-jni.c
|
||||
// see http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qprocessordetection.h
|
||||
// see also http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qprocessordetection.h
|
||||
|
||||
#ifdef __ORDER_LITTLE_ENDIAN__
|
||||
# define _C4EL __ORDER_LITTLE_ENDIAN__
|
||||
@@ -22,7 +22,11 @@
|
||||
#endif
|
||||
|
||||
// mixed byte order (eg, PowerPC or ia64)
|
||||
#define _C4EM 1111
|
||||
#define _C4EM 1111 // NOLINT
|
||||
|
||||
|
||||
// NOTE: to find defined macros in a platform,
|
||||
// g++ <flags> -dM -E - </dev/null | sort
|
||||
|
||||
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
|
||||
# define C4_CPU_X86_64
|
||||
@@ -60,11 +64,15 @@
|
||||
|| defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_6KZ__) \
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 6)
|
||||
# define C4_CPU_ARMV6
|
||||
# elif defined(__ARM_ARCH_5TEJ__) \
|
||||
# elif (defined(__ARM_ARCH) && __ARM_ARCH == 5) \
|
||||
|| defined(__ARM_ARCH_5TEJ__) \
|
||||
|| defined(__ARM_ARCH_5TE__) \
|
||||
|| defined(__ARM_ARCH_5T__) \
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 5)
|
||||
# define C4_CPU_ARMV5
|
||||
# elif defined(__ARM_ARCH_4T__) \
|
||||
# elif (defined(__ARM_ARCH) && __ARM_ARCH == 4) \
|
||||
|| defined(__ARM_ARCH_4T__) \
|
||||
|| defined(__ARM_ARCH_4__) \
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 4)
|
||||
# define C4_CPU_ARMV4
|
||||
# else
|
||||
@@ -145,6 +153,44 @@
|
||||
# endif
|
||||
# define C4_BYTE_ORDER _C4EL
|
||||
|
||||
#elif defined(__mips__) || defined(_mips) || defined(mips)
|
||||
# if defined(__mips)
|
||||
# if __mips == 64
|
||||
# define C4_CPU_MIPS64
|
||||
# define C4_WORDSIZE 8
|
||||
# elif __mips == 32
|
||||
# define C4_CPU_MIPS32
|
||||
# define C4_WORDSIZE 4
|
||||
# endif
|
||||
# elif defined(__arch64__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 64) || (defined(__LP64__) && __LP64__)
|
||||
# define C4_CPU_MIPS64
|
||||
# define C4_WORDSIZE 8
|
||||
# elif defined(__arch32__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 32) || (defined(__LP32__) && __LP32__)
|
||||
# define C4_CPU_MIPS32
|
||||
# define C4_WORDSIZE 4
|
||||
# else
|
||||
# error "unknown mips architecture"
|
||||
# endif
|
||||
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define C4_BYTE_ORDER _C4EB
|
||||
# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define C4_BYTE_ORDER _C4EL
|
||||
# else
|
||||
# error "unknown mips endianness"
|
||||
# endif
|
||||
|
||||
#elif defined(__sparc__) || defined(__sparc) || defined(sparc)
|
||||
# if defined(__arch64__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 64) || (defined(__LP64__) && __LP64__)
|
||||
# define C4_CPU_SPARC64
|
||||
# define C4_WORDSIZE 8
|
||||
# elif defined(__arch32__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 32) || (defined(__LP32__) && __LP32__)
|
||||
# define C4_CPU_SPARC32
|
||||
# define C4_WORDSIZE 4
|
||||
# else
|
||||
# error "unknown sparc architecture"
|
||||
# endif
|
||||
# define C4_BYTE_ORDER _C4EB
|
||||
|
||||
#elif defined(SWIG)
|
||||
# error "please define CPU architecture macros when compiling with swig"
|
||||
|
||||
|
||||
809
3rdparty/rapidyaml/include/c4/dump.hpp
vendored
809
3rdparty/rapidyaml/include/c4/dump.hpp
vendored
File diff suppressed because it is too large
Load Diff
19
3rdparty/rapidyaml/include/c4/error.hpp
vendored
19
3rdparty/rapidyaml/include/c4/error.hpp
vendored
@@ -63,6 +63,7 @@ struct fail_type__ {};
|
||||
#else
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wundef"
|
||||
# if !defined(__APPLE_CC__)
|
||||
# if __clang_major__ >= 10
|
||||
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
|
||||
@@ -73,12 +74,15 @@ struct fail_type__ {};
|
||||
# endif
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wundef"
|
||||
# endif
|
||||
# include <c4/ext/debugbreak/debugbreak.h>
|
||||
# define C4_DEBUG_BREAK() if(c4::is_debugger_attached()) { ::debug_break(); }
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -114,17 +118,17 @@ namespace c4 {
|
||||
typedef enum : uint32_t {
|
||||
/** when an error happens and the debugger is attached, call C4_DEBUG_BREAK().
|
||||
* Without effect otherwise. */
|
||||
ON_ERROR_DEBUGBREAK = 0x01 << 0,
|
||||
ON_ERROR_DEBUGBREAK = 0x01u << 0u,
|
||||
/** when an error happens log a message. */
|
||||
ON_ERROR_LOG = 0x01 << 1,
|
||||
ON_ERROR_LOG = 0x01u << 1u,
|
||||
/** when an error happens invoke a callback if it was set with
|
||||
* set_error_callback(). */
|
||||
ON_ERROR_CALLBACK = 0x01 << 2,
|
||||
ON_ERROR_CALLBACK = 0x01u << 2u,
|
||||
/** when an error happens call std::terminate(). */
|
||||
ON_ERROR_ABORT = 0x01 << 3,
|
||||
ON_ERROR_ABORT = 0x01u << 3u,
|
||||
/** when an error happens and exceptions are enabled throw an exception.
|
||||
* Without effect otherwise. */
|
||||
ON_ERROR_THROW = 0x01 << 4,
|
||||
ON_ERROR_THROW = 0x01u << 4u,
|
||||
/** the default flags. */
|
||||
ON_ERROR_DEFAULTS = ON_ERROR_DEBUGBREAK|ON_ERROR_LOG|ON_ERROR_CALLBACK|ON_ERROR_ABORT
|
||||
} ErrorFlags_e;
|
||||
@@ -140,7 +144,7 @@ C4CORE_EXPORT error_callback_type get_error_callback();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** RAII class controling the error settings inside a scope. */
|
||||
struct ScopedErrorSettings
|
||||
struct ScopedErrorSettings // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
{
|
||||
error_flags m_flags;
|
||||
error_callback_type m_callback;
|
||||
@@ -177,7 +181,8 @@ struct ScopedErrorSettings
|
||||
/** source location */
|
||||
struct srcloc;
|
||||
|
||||
C4CORE_EXPORT void handle_error(srcloc s, const char *fmt, ...);
|
||||
// watchout: for VS the [[noreturn]] needs to come before other annotations like C4CORE_EXPORT
|
||||
[[noreturn]] C4CORE_EXPORT void handle_error(srcloc s, const char *fmt, ...);
|
||||
C4CORE_EXPORT void handle_warning(srcloc s, const char *fmt, ...);
|
||||
|
||||
|
||||
|
||||
17
3rdparty/rapidyaml/include/c4/format.hpp
vendored
17
3rdparty/rapidyaml/include/c4/format.hpp
vendored
@@ -8,7 +8,7 @@
|
||||
#include "c4/blob.hpp"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# pragma warning(push)
|
||||
# if C4_MSVC_VERSION != C4_MSVC_VERSION_2017
|
||||
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning)
|
||||
@@ -20,6 +20,7 @@
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wuseless-cast"
|
||||
#endif
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast,*avoid-goto*)
|
||||
|
||||
/** @defgroup doc_format_utils Format utilities
|
||||
*
|
||||
@@ -323,7 +324,7 @@ to_chars(substr buf, fmt::integral_padded_<T> fmt)
|
||||
return utoa(buf, fmt.val, fmt.radix, fmt.num_digits);
|
||||
}
|
||||
|
||||
/** read an format an integer unsigned type
|
||||
/** read an integer type, detecting overflow (returns false on overflow)
|
||||
* @ingroup doc_from_chars */
|
||||
template<class T>
|
||||
C4_ALWAYS_INLINE bool from_chars(csubstr s, fmt::overflow_checked_<T> wrapper)
|
||||
@@ -332,6 +333,15 @@ C4_ALWAYS_INLINE bool from_chars(csubstr s, fmt::overflow_checked_<T> wrapper)
|
||||
return atox(s, wrapper.val);
|
||||
return false;
|
||||
}
|
||||
/** read an integer type, detecting overflow (returns false on overflow)
|
||||
* @ingroup doc_from_chars */
|
||||
template<class T>
|
||||
C4_ALWAYS_INLINE bool from_chars(csubstr s, fmt::overflow_checked_<T> *wrapper)
|
||||
{
|
||||
if(C4_LIKELY(!overflows<T>(s)))
|
||||
return atox(s, wrapper->val);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -967,7 +977,6 @@ inline CharOwningContainer catseprs(Sep const& C4_RESTRICT sep, Args const& C4_R
|
||||
* the result. The buffer is appended to.
|
||||
*
|
||||
* @return a csubstr of the appended part
|
||||
* @ingroup formatting_functions
|
||||
* @ingroup doc_catsep */
|
||||
template<class CharOwningContainer, class Sep, class... Args>
|
||||
inline csubstr catseprs_append(CharOwningContainer * C4_RESTRICT cont, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...args)
|
||||
@@ -1019,7 +1028,6 @@ inline CharOwningContainer formatrs(csubstr fmt, Args const& C4_RESTRICT ...args
|
||||
* arguments, resizing the container as needed to contain the
|
||||
* result. The buffer is appended to.
|
||||
* @return the region newly appended to the original container
|
||||
* @ingroup formatting_functions
|
||||
* @ingroup doc_format */
|
||||
template<class CharOwningContainer, class... Args>
|
||||
inline csubstr formatrs_append(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args const& C4_RESTRICT ...args)
|
||||
@@ -1038,6 +1046,7 @@ retry:
|
||||
|
||||
} // namespace c4
|
||||
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast,*avoid-goto*)
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#elif defined(__clang__)
|
||||
|
||||
2
3rdparty/rapidyaml/include/c4/language.hpp
vendored
2
3rdparty/rapidyaml/include/c4/language.hpp
vendored
@@ -333,7 +333,7 @@ namespace detail {
|
||||
#ifdef __GNUC__
|
||||
# define C4_DONT_OPTIMIZE(var) c4::detail::dont_optimize(var)
|
||||
template< class T >
|
||||
C4_ALWAYS_INLINE void dont_optimize(T const& value) { asm volatile("" : : "g"(value) : "memory"); }
|
||||
C4_ALWAYS_INLINE void dont_optimize(T const& value) { asm volatile("" : : "g"(value) : "memory"); } // NOLINT
|
||||
#else
|
||||
# define C4_DONT_OPTIMIZE(var) c4::detail::use_char_pointer(reinterpret_cast< const char* >(&var))
|
||||
void use_char_pointer(char const volatile*);
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
/** @file memory_util.hpp Some memory utilities. */
|
||||
|
||||
// NOLINTBEGIN(google-runtime-int)
|
||||
|
||||
namespace c4 {
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
@@ -696,8 +698,8 @@ struct tight_pair<First, Second, tpc_same_empty> : public First
|
||||
|
||||
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
|
||||
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
|
||||
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return reinterpret_cast<Second &>(*this); }
|
||||
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return reinterpret_cast<Second const&>(*this); }
|
||||
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return reinterpret_cast<Second &>(*this); } // NOLINT
|
||||
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return reinterpret_cast<Second const&>(*this); } // NOLINT
|
||||
};
|
||||
|
||||
template<class First, class Second>
|
||||
@@ -775,4 +777,6 @@ C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
} // namespace c4
|
||||
|
||||
// NOLINTEND(google-runtime-int)
|
||||
|
||||
#endif /* _C4_MEMORY_UTIL_HPP_ */
|
||||
|
||||
47
3rdparty/rapidyaml/include/c4/substr.hpp
vendored
47
3rdparty/rapidyaml/include/c4/substr.hpp
vendored
@@ -67,12 +67,9 @@ static inline void _do_reverse(C *C4_RESTRICT first, C *C4_RESTRICT last)
|
||||
* @see a [quickstart
|
||||
* sample](https://rapidyaml.readthedocs.io/latest/doxygen/group__doc__quickstart.html#ga43e253da0692c13967019446809c1113)
|
||||
* in rapidyaml's documentation.
|
||||
*
|
||||
* @see @ref substr and @ref to_substr()
|
||||
* @see @ref csubstr and @ref to_csubstr()
|
||||
*/
|
||||
template<class C>
|
||||
struct C4CORE_EXPORT basic_substring
|
||||
struct C4CORE_EXPORT basic_substring // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -530,11 +527,11 @@ public:
|
||||
/** @name Lookup methods */
|
||||
/** @{ */
|
||||
|
||||
inline size_t find(const C c, size_t start_pos=0) const
|
||||
size_t find(const C c, size_t start_pos=0) const
|
||||
{
|
||||
return first_of(c, start_pos);
|
||||
}
|
||||
inline size_t find(ro_substr pattern, size_t start_pos=0) const
|
||||
size_t find(ro_substr pattern, size_t start_pos=0) const
|
||||
{
|
||||
C4_ASSERT(start_pos == npos || (start_pos >= 0 && start_pos <= len));
|
||||
if(len < pattern.len) return npos;
|
||||
@@ -561,7 +558,7 @@ public:
|
||||
public:
|
||||
|
||||
/** count the number of occurrences of c */
|
||||
inline size_t count(const C c, size_t pos=0) const
|
||||
size_t count(const C c, size_t pos=0) const
|
||||
{
|
||||
C4_ASSERT(pos >= 0 && pos <= len);
|
||||
size_t num = 0;
|
||||
@@ -575,7 +572,7 @@ public:
|
||||
}
|
||||
|
||||
/** count the number of occurrences of s */
|
||||
inline size_t count(ro_substr c, size_t pos=0) const
|
||||
size_t count(ro_substr c, size_t pos=0) const
|
||||
{
|
||||
C4_ASSERT(pos >= 0 && pos <= len);
|
||||
size_t num = 0;
|
||||
@@ -589,14 +586,14 @@ public:
|
||||
}
|
||||
|
||||
/** get the substr consisting of the first occurrence of @p c after @p pos, or an empty substr if none occurs */
|
||||
inline basic_substring select(const C c, size_t pos=0) const
|
||||
basic_substring select(const C c, size_t pos=0) const
|
||||
{
|
||||
pos = find(c, pos);
|
||||
return pos != npos ? sub(pos, 1) : basic_substring();
|
||||
}
|
||||
|
||||
/** get the substr consisting of the first occurrence of @p pattern after @p pos, or an empty substr if none occurs */
|
||||
inline basic_substring select(ro_substr pattern, size_t pos=0) const
|
||||
basic_substring select(ro_substr pattern, size_t pos=0) const
|
||||
{
|
||||
pos = find(pattern, pos);
|
||||
return pos != npos ? sub(pos, pattern.len) : basic_substring();
|
||||
@@ -608,7 +605,7 @@ public:
|
||||
{
|
||||
size_t which;
|
||||
size_t pos;
|
||||
inline operator bool() const { return which != NONE && pos != npos; }
|
||||
operator bool() const { return which != NONE && pos != npos; }
|
||||
};
|
||||
|
||||
first_of_any_result first_of_any(ro_substr s0, ro_substr s1) const
|
||||
@@ -1307,12 +1304,12 @@ public:
|
||||
else if(c == '.')
|
||||
{
|
||||
++pos;
|
||||
goto fractional_part_dec;
|
||||
goto fractional_part_dec; // NOLINT
|
||||
}
|
||||
else if(c == 'e' || c == 'E')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_dec;
|
||||
goto power_part_dec; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1341,7 +1338,7 @@ public:
|
||||
else if(c == 'e' || c == 'E')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_dec;
|
||||
goto power_part_dec; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1394,12 +1391,12 @@ public:
|
||||
else if(c == '.')
|
||||
{
|
||||
++pos;
|
||||
goto fractional_part_hex;
|
||||
goto fractional_part_hex; // NOLINT
|
||||
}
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_hex;
|
||||
goto power_part_hex; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1428,7 +1425,7 @@ public:
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_hex;
|
||||
goto power_part_hex; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1484,12 +1481,12 @@ public:
|
||||
else if(c == '.')
|
||||
{
|
||||
++pos;
|
||||
goto fractional_part_bin;
|
||||
goto fractional_part_bin; // NOLINT
|
||||
}
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_bin;
|
||||
goto power_part_bin; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1518,7 +1515,7 @@ public:
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_bin;
|
||||
goto power_part_bin; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1574,12 +1571,12 @@ public:
|
||||
else if(c == '.')
|
||||
{
|
||||
++pos;
|
||||
goto fractional_part_oct;
|
||||
goto fractional_part_oct; // NOLINT
|
||||
}
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_oct;
|
||||
goto power_part_oct; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1608,7 +1605,7 @@ public:
|
||||
else if(c == 'p' || c == 'P')
|
||||
{
|
||||
++pos;
|
||||
goto power_part_oct;
|
||||
goto power_part_oct; // NOLINT
|
||||
}
|
||||
else if(_is_delim_char(c))
|
||||
{
|
||||
@@ -1714,7 +1711,7 @@ private:
|
||||
}
|
||||
|
||||
split_iterator_impl& operator++ () { _tick(); return *this; }
|
||||
split_iterator_impl operator++ (int) { split_iterator_impl it = *this; _tick(); return it; }
|
||||
split_iterator_impl operator++ (int) { split_iterator_impl it = *this; _tick(); return it; } // NOLINT
|
||||
|
||||
basic_substring& operator* () { return m_str; }
|
||||
basic_substring* operator-> () { return &m_str; }
|
||||
@@ -2069,7 +2066,7 @@ public:
|
||||
C4_REQUIRE_RW(basic_substring) erase_range(size_t first, size_t last)
|
||||
{
|
||||
C4_ASSERT(first <= last);
|
||||
return erase(first, static_cast<size_t>(last-first));
|
||||
return erase(first, static_cast<size_t>(last-first)); // NOLINT
|
||||
}
|
||||
|
||||
/** erase a part of the string.
|
||||
|
||||
2
3rdparty/rapidyaml/include/c4/szconv.hpp
vendored
2
3rdparty/rapidyaml/include/c4/szconv.hpp
vendored
@@ -53,7 +53,7 @@ szconv(SizeIn sz) noexcept
|
||||
template<class SizeOut, class SizeIn>
|
||||
C4_ALWAYS_INLINE
|
||||
typename std::enable_if<is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
|
||||
szconv(SizeIn sz) C4_NOEXCEPT_X
|
||||
szconv(SizeIn sz)
|
||||
{
|
||||
C4_XASSERT(sz >= 0);
|
||||
C4_XASSERT_MSG((SizeIn)sz <= (SizeIn)std::numeric_limits<SizeOut>::max(), "size conversion overflow: in=%zu", (size_t)sz);
|
||||
|
||||
16
3rdparty/rapidyaml/include/c4/types.hpp
vendored
16
3rdparty/rapidyaml/include/c4/types.hpp
vendored
@@ -17,6 +17,8 @@
|
||||
|
||||
/** @defgroup types Type utilities */
|
||||
|
||||
// NOLINTBEGIN(bugprone-macro-parentheses)
|
||||
|
||||
namespace c4 {
|
||||
|
||||
/** @defgroup intrinsic_types Intrinsic types
|
||||
@@ -114,17 +116,17 @@ using fastcref = typename std::conditional<c4::cref_uses_val<T>::value, T, T con
|
||||
//--------------------------------------------------
|
||||
|
||||
/** Just what its name says. Useful sometimes as a default empty policy class. */
|
||||
struct EmptyStruct
|
||||
struct EmptyStruct // NOLINT
|
||||
{
|
||||
template<class... T> EmptyStruct(T && ...){}
|
||||
template<class... T> EmptyStruct(T && ...){} // NOLINT
|
||||
};
|
||||
|
||||
/** Just what its name says. Useful sometimes as a default policy class to
|
||||
* be inherited from. */
|
||||
struct EmptyStructVirtual
|
||||
struct EmptyStructVirtual // NOLINT
|
||||
{
|
||||
virtual ~EmptyStructVirtual() = default;
|
||||
template<class... T> EmptyStructVirtual(T && ...){}
|
||||
template<class... T> EmptyStructVirtual(T && ...){} // NOLINT
|
||||
};
|
||||
|
||||
|
||||
@@ -159,7 +161,7 @@ struct Padded : public T
|
||||
using T::T;
|
||||
using T::operator=;
|
||||
Padded(T const& val) : T(val) {}
|
||||
Padded(T && val) : T(val) {}
|
||||
Padded(T && val) : T(std::forward<T>(val)) {} // NOLINT
|
||||
char ___c4padspace___[BytesToPadAtEnd];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
@@ -170,7 +172,7 @@ struct Padded<T, 0> : public T
|
||||
using T::T;
|
||||
using T::operator=;
|
||||
Padded(T const& val) : T(val) {}
|
||||
Padded(T && val) : T(val) {}
|
||||
Padded(T && val) : T(std::forward<T>(val)) {} // NOLINT
|
||||
};
|
||||
|
||||
/** make T have a size which is at least Min bytes */
|
||||
@@ -500,4 +502,6 @@ using index_sequence_for = make_index_sequence<sizeof...(_Tp)>;
|
||||
|
||||
} // namespace c4
|
||||
|
||||
// NOLINTEND(bugprone-macro-parentheses)
|
||||
|
||||
#endif /* _C4_TYPES_HPP_ */
|
||||
|
||||
61
3rdparty/rapidyaml/include/c4/utf.hpp
vendored
61
3rdparty/rapidyaml/include/c4/utf.hpp
vendored
@@ -6,10 +6,67 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** @file utf.hpp utilities for UTF and Byte Order Mark */
|
||||
|
||||
namespace c4 {
|
||||
|
||||
substr decode_code_point(substr out, csubstr code_point);
|
||||
size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, const uint32_t code);
|
||||
/** @defgroup doc_utf UTF utilities
|
||||
* @{ */
|
||||
|
||||
|
||||
/** skip the Byte Order Mark, or get the full string if there is Byte Order Mark.
|
||||
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
|
||||
C4CORE_EXPORT substr skip_bom(substr s);
|
||||
/** skip the Byte Order Mark, or get the full string if there is Byte Order Mark
|
||||
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
|
||||
C4CORE_EXPORT csubstr skip_bom(csubstr s);
|
||||
|
||||
|
||||
/** get the Byte Order Mark, or an empty string if there is no Byte Order Mark
|
||||
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
|
||||
C4CORE_EXPORT substr get_bom(substr s);
|
||||
/** get the Byte Order Mark, or an empty string if there is no Byte Order Mark
|
||||
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
|
||||
C4CORE_EXPORT csubstr get_bom(csubstr s);
|
||||
|
||||
|
||||
/** return the position of the first character not belonging to the
|
||||
* Byte Order Mark, or 0 if there is no Byte Order Mark.
|
||||
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
|
||||
C4CORE_EXPORT size_t first_non_bom(csubstr s);
|
||||
|
||||
|
||||
/** decode the given @p code_point, writing into the output string in
|
||||
* @p out.
|
||||
*
|
||||
* @param out the output string. must have at least 4 bytes (this is
|
||||
* asserted), and must not have a null string.
|
||||
*
|
||||
* @param code_point: must have length in ]0,8], and must not begin
|
||||
* with any of `U+`,`\\x`,`\\u,`\\U`,`0` (asserted)
|
||||
*
|
||||
* @return the part of @p out that was written, which will always be
|
||||
* at most 4 bytes.
|
||||
*/
|
||||
C4CORE_EXPORT substr decode_code_point(substr out, csubstr code_point);
|
||||
|
||||
/** decode the given @p code point, writing into the output string @p
|
||||
* buf, of size @p buflen
|
||||
*
|
||||
* @param buf the output string. must have at least 4 bytes (this is
|
||||
* asserted), and must not be null
|
||||
*
|
||||
* @param buflen the length of the output string. must be at least 4
|
||||
*
|
||||
* @param code: the code point must have length in ]0,8], and must not begin
|
||||
* with any of `U+`,`\\x`,`\\u,`\\U`,`0` (asserted)
|
||||
*
|
||||
* @return the part of @p out that was written, which will always be
|
||||
* at most 4 bytes.
|
||||
*/
|
||||
size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, uint32_t code);
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace c4
|
||||
|
||||
|
||||
272
3rdparty/rapidyaml/include/c4/yml/common.hpp
vendored
272
3rdparty/rapidyaml/include/c4/yml/common.hpp
vendored
@@ -5,8 +5,50 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <c4/substr.hpp>
|
||||
#include <c4/charconv.hpp>
|
||||
#include <c4/dump.hpp>
|
||||
#include <c4/yml/export.hpp>
|
||||
|
||||
#if defined(C4_MSVC) || defined(C4_MINGW)
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef RYML_ERRMSG_SIZE
|
||||
/// size for the error message buffer
|
||||
#define RYML_ERRMSG_SIZE (1024)
|
||||
#endif
|
||||
|
||||
#ifndef RYML_LOGBUF_SIZE
|
||||
/// size for the buffer used to format individual values to string
|
||||
/// while preparing an error message. This is only used for formatting
|
||||
/// individual values in the message; final messages will be larger
|
||||
/// than this value (see @ref RYML_ERRMSG_SIZE). This is also used for
|
||||
/// the detailed debug log messages when RYML_DBG is defined.
|
||||
#define RYML_LOGBUF_SIZE (256)
|
||||
#endif
|
||||
|
||||
#ifndef RYML_LOGBUF_SIZE_MAX
|
||||
/// size for the fallback larger log buffer. When @ref
|
||||
/// RYML_LOGBUF_SIZE is not large enough to convert a value to string,
|
||||
/// then temporary stack memory is allocated up to
|
||||
/// RYML_LOGBUF_SIZE_MAX. This limit is in place to prevent a stack
|
||||
/// overflow. If the printed value requires more than
|
||||
/// RYML_LOGBUF_SIZE_MAX, the value is silently skipped.
|
||||
#define RYML_LOGBUF_SIZE_MAX (1024)
|
||||
#endif
|
||||
|
||||
#ifndef RYML_LOCATIONS_SMALL_THRESHOLD
|
||||
/// threshold at which a location search will revert from linear to
|
||||
/// binary search.
|
||||
#define RYML_LOCATIONS_SMALL_THRESHOLD (30)
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Specify groups to have a predefined topic order in doxygen:
|
||||
@@ -83,6 +125,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/** @defgroup doc_ref_utils Anchor/Reference utilities
|
||||
*
|
||||
* @see sample::sample_anchors_and_aliases
|
||||
* */
|
||||
|
||||
/** @defgroup doc_tag_utils Tag utilities
|
||||
* @see sample::sample_tags
|
||||
*/
|
||||
@@ -134,11 +181,13 @@
|
||||
# define RYML_ASSERT(cond) RYML_CHECK(cond)
|
||||
# define RYML_ASSERT_MSG(cond, msg) RYML_CHECK_MSG(cond, msg)
|
||||
# define _RYML_CB_ASSERT(cb, cond) _RYML_CB_CHECK((cb), (cond))
|
||||
# define _RYML_CB_ASSERT_(cb, cond, loc) _RYML_CB_CHECK((cb), (cond), (loc))
|
||||
# define RYML_NOEXCEPT
|
||||
#else
|
||||
# define RYML_ASSERT(cond)
|
||||
# define RYML_ASSERT_MSG(cond, msg)
|
||||
# define _RYML_CB_ASSERT(cb, cond)
|
||||
# define _RYML_CB_ASSERT_(cb, cond, loc)
|
||||
# define RYML_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
@@ -148,7 +197,7 @@
|
||||
do { \
|
||||
if(C4_UNLIKELY(!(cond))) \
|
||||
{ \
|
||||
RYML_DEBUG_BREAK() \
|
||||
RYML_DEBUG_BREAK(); \
|
||||
c4::yml::error("check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
|
||||
C4_UNREACHABLE_AFTER_ERR(); \
|
||||
} \
|
||||
@@ -159,7 +208,7 @@
|
||||
{ \
|
||||
if(C4_UNLIKELY(!(cond))) \
|
||||
{ \
|
||||
RYML_DEBUG_BREAK() \
|
||||
RYML_DEBUG_BREAK(); \
|
||||
c4::yml::error(msg ": check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
|
||||
C4_UNREACHABLE_AFTER_ERR(); \
|
||||
} \
|
||||
@@ -167,17 +216,16 @@
|
||||
|
||||
#if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
|
||||
# define RYML_DEBUG_BREAK() \
|
||||
{ \
|
||||
do { \
|
||||
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
|
||||
{ \
|
||||
C4_DEBUG_BREAK(); \
|
||||
} \
|
||||
}
|
||||
} while(0)
|
||||
#else
|
||||
# define RYML_DEBUG_BREAK()
|
||||
#endif
|
||||
|
||||
|
||||
/** @endcond */
|
||||
|
||||
|
||||
@@ -190,11 +238,33 @@ namespace yml {
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
|
||||
enum : size_t {
|
||||
/** a null position */
|
||||
npos = size_t(-1),
|
||||
|
||||
#ifndef RYML_ID_TYPE
|
||||
/** The type of a node id in the YAML tree. In the future, the default
|
||||
* will likely change to int32_t, which was observed to be faster.
|
||||
* @see id_type */
|
||||
#define RYML_ID_TYPE size_t
|
||||
#endif
|
||||
|
||||
|
||||
/** The type of a node id in the YAML tree; to override the default
|
||||
* type, define the macro @ref RYML_ID_TYPE to a suitable integer
|
||||
* type. */
|
||||
using id_type = RYML_ID_TYPE;
|
||||
static_assert(std::is_integral<id_type>::value, "id_type must be an integer type");
|
||||
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
|
||||
enum : id_type {
|
||||
/** an index to none */
|
||||
NONE = size_t(-1)
|
||||
NONE = id_type(-1),
|
||||
};
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
|
||||
enum : size_t {
|
||||
/** a null string position */
|
||||
npos = size_t(-1)
|
||||
};
|
||||
|
||||
|
||||
@@ -212,28 +282,40 @@ struct RYML_EXPORT LineCol
|
||||
//! column
|
||||
size_t col;
|
||||
|
||||
LineCol() : offset(), line(), col() {}
|
||||
LineCol() = default;
|
||||
//! construct from line and column
|
||||
LineCol(size_t l, size_t c) : offset(0), line(l), col(c) {}
|
||||
//! construct from offset, line and column
|
||||
LineCol(size_t o, size_t l, size_t c) : offset(o), line(l), col(c) {}
|
||||
};
|
||||
static_assert(std::is_trivial<LineCol>::value, "LineCol not trivial");
|
||||
static_assert(std::is_standard_layout<LineCol>::value, "Location not trivial");
|
||||
|
||||
|
||||
//! a source file position
|
||||
struct RYML_EXPORT Location : public LineCol
|
||||
struct RYML_EXPORT Location
|
||||
{
|
||||
//! number of bytes from the beginning of the source buffer
|
||||
size_t offset;
|
||||
//! line
|
||||
size_t line;
|
||||
//! column
|
||||
size_t col;
|
||||
//! file name
|
||||
csubstr name;
|
||||
|
||||
operator bool () const { return !name.empty() || line != 0 || offset != 0; }
|
||||
operator bool () const { return !name.empty() || line != 0 || offset != 0 || col != 0; }
|
||||
operator LineCol const& () const { return reinterpret_cast<LineCol const&>(*this); } // NOLINT
|
||||
|
||||
Location() : LineCol(), name() {}
|
||||
Location( size_t l, size_t c) : LineCol{ l, c}, name( ) {}
|
||||
Location( csubstr n, size_t l, size_t c) : LineCol{ l, c}, name(n) {}
|
||||
Location( csubstr n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(n) {}
|
||||
Location(const char *n, size_t l, size_t c) : LineCol{ l, c}, name(to_csubstr(n)) {}
|
||||
Location(const char *n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(to_csubstr(n)) {}
|
||||
Location() = default;
|
||||
Location( size_t l, size_t c) : offset( ), line(l), col(c), name( ) {}
|
||||
Location( size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name( ) {}
|
||||
Location( csubstr n, size_t l, size_t c) : offset( ), line(l), col(c), name(n) {}
|
||||
Location( csubstr n, size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name(n) {}
|
||||
Location(const char *n, size_t l, size_t c) : offset( ), line(l), col(c), name(to_csubstr(n)) {}
|
||||
Location(const char *n, size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name(to_csubstr(n)) {}
|
||||
};
|
||||
static_assert(std::is_standard_layout<Location>::value, "Location not trivial");
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -300,7 +382,7 @@ struct RYML_EXPORT Callbacks
|
||||
/** Construct an object with the default callbacks. If
|
||||
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, the object will have null
|
||||
* members.*/
|
||||
Callbacks();
|
||||
Callbacks() noexcept;
|
||||
|
||||
/** Construct an object with the given callbacks.
|
||||
*
|
||||
@@ -338,6 +420,20 @@ struct RYML_EXPORT Callbacks
|
||||
/** @} */
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
typedef enum {
|
||||
NOBOM,
|
||||
UTF8,
|
||||
UTF16LE,
|
||||
UTF16BE,
|
||||
UTF32LE,
|
||||
UTF32BE,
|
||||
} Encoding_e;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -364,30 +460,30 @@ template<size_t N>
|
||||
}
|
||||
|
||||
#define _RYML_CB_ERR(cb, msg_literal) \
|
||||
_RYML_CB_ERR_(cb, msg_literal, c4::yml::Location(__FILE__, 0, __LINE__, 0))
|
||||
#define _RYML_CB_CHECK(cb, cond) \
|
||||
_RYML_CB_CHECK_(cb, cond, c4::yml::Location(__FILE__, 0, __LINE__, 0))
|
||||
#define _RYML_CB_ERR_(cb, msg_literal, loc) \
|
||||
do \
|
||||
{ \
|
||||
const char msg[] = msg_literal; \
|
||||
RYML_DEBUG_BREAK() \
|
||||
c4::yml::error((cb), \
|
||||
msg, sizeof(msg), \
|
||||
c4::yml::Location(__FILE__, 0, __LINE__, 0)); \
|
||||
RYML_DEBUG_BREAK(); \
|
||||
c4::yml::error((cb), msg, sizeof(msg)-1, loc); \
|
||||
C4_UNREACHABLE_AFTER_ERR(); \
|
||||
} while(0)
|
||||
#define _RYML_CB_CHECK(cb, cond) \
|
||||
#define _RYML_CB_CHECK_(cb, cond, loc) \
|
||||
do \
|
||||
{ \
|
||||
if(!(cond)) \
|
||||
if(C4_UNLIKELY(!(cond))) \
|
||||
{ \
|
||||
const char msg[] = "check failed: " #cond; \
|
||||
RYML_DEBUG_BREAK() \
|
||||
c4::yml::error((cb), \
|
||||
msg, sizeof(msg), \
|
||||
c4::yml::Location(__FILE__, 0, __LINE__, 0)); \
|
||||
RYML_DEBUG_BREAK(); \
|
||||
c4::yml::error((cb), msg, sizeof(msg)-1, loc); \
|
||||
C4_UNREACHABLE_AFTER_ERR(); \
|
||||
} \
|
||||
} while(0)
|
||||
#define _RYML_CB_ALLOC_HINT(cb, T, num, hint) (T*) (cb).m_allocate((num) * sizeof(T), (hint), (cb).m_user_data)
|
||||
#define _RYML_CB_ALLOC(cb, T, num) _RYML_CB_ALLOC_HINT((cb), (T), (num), nullptr)
|
||||
#define _RYML_CB_ALLOC(cb, T, num) _RYML_CB_ALLOC_HINT((cb), T, (num), nullptr)
|
||||
#define _RYML_CB_FREE(cb, buf, T, num) \
|
||||
do { \
|
||||
(cb).m_free((buf), (num) * sizeof(T), (cb).m_user_data); \
|
||||
@@ -395,11 +491,54 @@ do \
|
||||
} while(0)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
typedef enum {
|
||||
BLOCK_LITERAL, //!< keep newlines (|)
|
||||
BLOCK_FOLD //!< replace newline with single space (>)
|
||||
} BlockStyle_e;
|
||||
|
||||
typedef enum {
|
||||
CHOMP_CLIP, //!< single newline at end (default)
|
||||
CHOMP_STRIP, //!< no newline at end (-)
|
||||
CHOMP_KEEP //!< all newlines from end (+)
|
||||
} BlockChomp_e;
|
||||
|
||||
|
||||
/** Abstracts the fact that a scalar filter result may not fit in the
|
||||
* intended memory. */
|
||||
struct FilterResult
|
||||
{
|
||||
C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
|
||||
C4_ALWAYS_INLINE size_t required_len() const noexcept { return str.len; }
|
||||
C4_ALWAYS_INLINE csubstr get() const { RYML_ASSERT(valid()); return str; }
|
||||
csubstr str;
|
||||
};
|
||||
/** Abstracts the fact that a scalar filter result may not fit in the
|
||||
* intended memory. */
|
||||
struct FilterResultExtending
|
||||
{
|
||||
C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
|
||||
C4_ALWAYS_INLINE size_t required_len() const noexcept { return reqlen; }
|
||||
C4_ALWAYS_INLINE csubstr get() const { RYML_ASSERT(valid()); return str; }
|
||||
csubstr str;
|
||||
size_t reqlen;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace detail {
|
||||
// is there a better way to do this?
|
||||
template<int8_t signedval, uint8_t unsignedval>
|
||||
struct _charconstant_t
|
||||
: public std::conditional<std::is_signed<char>::value,
|
||||
std::integral_constant<int8_t, signedval>,
|
||||
std::integral_constant<int8_t, static_cast<int8_t>(unsignedval)>,
|
||||
std::integral_constant<uint8_t, unsignedval>>::type
|
||||
{};
|
||||
#define _RYML_CHCONST(signedval, unsignedval) ::c4::yml::detail::_charconstant_t<INT8_C(signedval), UINT8_C(unsignedval)>::value
|
||||
@@ -411,10 +550,11 @@ struct _SubstrWriter
|
||||
{
|
||||
substr buf;
|
||||
size_t pos;
|
||||
_SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) {}
|
||||
_SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) { C4_ASSERT(buf.str); }
|
||||
void append(csubstr s)
|
||||
{
|
||||
C4_ASSERT(!s.overlaps(buf));
|
||||
C4_ASSERT(s.str || !s.len);
|
||||
if(s.len && pos + s.len <= buf.len)
|
||||
{
|
||||
C4_ASSERT(s.str);
|
||||
@@ -424,12 +564,14 @@ struct _SubstrWriter
|
||||
}
|
||||
void append(char c)
|
||||
{
|
||||
C4_ASSERT(buf.str);
|
||||
if(pos < buf.len)
|
||||
buf.str[pos] = c;
|
||||
++pos;
|
||||
}
|
||||
void append_n(char c, size_t numtimes)
|
||||
{
|
||||
C4_ASSERT(buf.str);
|
||||
if(numtimes && pos + numtimes < buf.len)
|
||||
memset(buf.str + pos, c, numtimes);
|
||||
pos += numtimes;
|
||||
@@ -439,15 +581,77 @@ struct _SubstrWriter
|
||||
//! get the part written so far
|
||||
csubstr curr() const { return pos <= buf.len ? buf.first(pos) : buf; }
|
||||
//! get the part that is still free to write to (the remainder)
|
||||
substr rem() { return pos < buf.len ? buf.sub(pos) : buf.last(0); }
|
||||
substr rem() const { return pos < buf.len ? buf.sub(pos) : buf.last(0); }
|
||||
|
||||
size_t advance(size_t more) { pos += more; return pos; }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
||||
namespace detail {
|
||||
// dumpfn is a function abstracting prints to terminal (or to string).
|
||||
template<class DumpFn, class ...Args>
|
||||
C4_NO_INLINE void _dump(DumpFn &&dumpfn, csubstr fmt, Args&& ...args)
|
||||
{
|
||||
DumpResults results;
|
||||
// try writing everything:
|
||||
{
|
||||
// buffer for converting individual arguments. it is defined
|
||||
// in a child scope to free it in case the buffer is too small
|
||||
// for any of the arguments.
|
||||
char writebuf[RYML_LOGBUF_SIZE];
|
||||
results = format_dump_resume(std::forward<DumpFn>(dumpfn), writebuf, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
// if any of the arguments failed to fit the buffer, allocate a
|
||||
// larger buffer (up to a limit) and resume writing.
|
||||
//
|
||||
// results.bufsize is set to the size of the largest element
|
||||
// serialized. Eg int(1) will require 1 byte.
|
||||
if(C4_UNLIKELY(results.bufsize > RYML_LOGBUF_SIZE))
|
||||
{
|
||||
const size_t bufsize = results.bufsize <= RYML_LOGBUF_SIZE_MAX ? results.bufsize : RYML_LOGBUF_SIZE_MAX;
|
||||
#ifdef C4_MSVC
|
||||
substr largerbuf = {static_cast<char*>(_alloca(bufsize)), bufsize};
|
||||
#else
|
||||
substr largerbuf = {static_cast<char*>(alloca(bufsize)), bufsize};
|
||||
#endif
|
||||
results = format_dump_resume(std::forward<DumpFn>(dumpfn), results, largerbuf, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
template<class ...Args>
|
||||
C4_NORETURN C4_NO_INLINE void _report_err(Callbacks const& C4_RESTRICT callbacks, csubstr fmt, Args const& C4_RESTRICT ...args)
|
||||
{
|
||||
char errmsg[RYML_ERRMSG_SIZE] = {0};
|
||||
detail::_SubstrWriter writer(errmsg);
|
||||
auto dumpfn = [&writer](csubstr s){ writer.append(s); };
|
||||
_dump(dumpfn, fmt, args...);
|
||||
writer.append('\n');
|
||||
const size_t len = writer.pos < RYML_ERRMSG_SIZE ? writer.pos : RYML_ERRMSG_SIZE;
|
||||
callbacks.m_error(errmsg, len, {}, callbacks.m_user_data);
|
||||
C4_UNREACHABLE_AFTER_ERR();
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
inline csubstr _c4prc(const char &C4_RESTRICT c) // pass by reference!
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case '\n': return csubstr("\\n");
|
||||
case '\t': return csubstr("\\t");
|
||||
case '\0': return csubstr("\\0");
|
||||
case '\r': return csubstr("\\r");
|
||||
case '\f': return csubstr("\\f");
|
||||
case '\b': return csubstr("\\b");
|
||||
case '\v': return csubstr("\\v");
|
||||
case '\a': return csubstr("\\a");
|
||||
default: return csubstr(&c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
C4_SUPPRESS_WARNING_GCC_POP
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
|
||||
void check_invariants(Tree const& t, size_t node=NONE);
|
||||
void check_invariants(Tree const& t, id_type node=NONE);
|
||||
void check_free_list(Tree const& t);
|
||||
void check_arena(Tree const& t);
|
||||
|
||||
@@ -26,16 +26,16 @@ void check_arena(Tree const& t);
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline void check_invariants(Tree const& t, size_t node)
|
||||
inline void check_invariants(Tree const& t, id_type node)
|
||||
{
|
||||
if(node == NONE)
|
||||
{
|
||||
if(t.size() == 0) return;
|
||||
if(t.empty()) return;
|
||||
node = t.root_id();
|
||||
}
|
||||
|
||||
auto const& n = *t._p(node);
|
||||
#ifdef RYML_DBG
|
||||
NodeData const& n = *t._p(node);
|
||||
#if defined(RYML_DBG) && 0
|
||||
if(n.m_first_child != NONE || n.m_last_child != NONE)
|
||||
{
|
||||
printf("check(%zu): fc=%zu lc=%zu\n", node, n.m_first_child, n.m_last_child);
|
||||
@@ -100,10 +100,10 @@ inline void check_invariants(Tree const& t, size_t node)
|
||||
C4_CHECK(t._p(n.m_next_sibling)->m_next_sibling != node);
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
for(size_t i = n.m_first_child; i != NONE; i = t.next_sibling(i))
|
||||
id_type count = 0;
|
||||
for(id_type i = n.m_first_child; i != NONE; i = t.next_sibling(i))
|
||||
{
|
||||
#ifdef RYML_DBG
|
||||
#if defined(RYML_DBG) && 0
|
||||
printf("check(%zu): descend to child[%zu]=%zu\n", node, count, i);
|
||||
#endif
|
||||
auto const& ch = *t._p(i);
|
||||
@@ -131,7 +131,7 @@ inline void check_invariants(Tree const& t, size_t node)
|
||||
check_arena(t);
|
||||
}
|
||||
|
||||
for(size_t i = t.first_child(node); i != NONE; i = t.next_sibling(i))
|
||||
for(id_type i = t.first_child(node); i != NONE; i = t.next_sibling(i))
|
||||
{
|
||||
check_invariants(t, i);
|
||||
}
|
||||
@@ -159,8 +159,8 @@ inline void check_free_list(Tree const& t)
|
||||
//C4_CHECK(head.m_prev_sibling == NONE);
|
||||
//C4_CHECK(tail.m_next_sibling == NONE);
|
||||
|
||||
size_t count = 0;
|
||||
for(size_t i = t.m_free_head, prev = NONE; i != NONE; i = t._p(i)->m_next_sibling)
|
||||
id_type count = 0;
|
||||
for(id_type i = t.m_free_head, prev = NONE; i != NONE; i = t._p(i)->m_next_sibling)
|
||||
{
|
||||
auto const& elm = *t._p(i);
|
||||
if(&elm != &head)
|
||||
|
||||
@@ -4,135 +4,144 @@
|
||||
#ifndef _C4_YML_COMMON_HPP_
|
||||
#include "../common.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef RYML_DBG
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// some debugging scaffolds
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4068/*unknown pragma*/)
|
||||
#endif
|
||||
// NOLINTBEGIN(*)
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
|
||||
C4_SUPPRESS_WARNING_MSVC_PUSH
|
||||
C4_SUPPRESS_WARNING_MSVC(4068/*unknown pragma*/)
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
//#pragma GCC diagnostic ignored "-Wpragma-system-header-outside-header"
|
||||
#pragma GCC system_header
|
||||
C4_SUPPRESS_WARNING_GCC("-Wunknown-pragmas")
|
||||
C4_SUPPRESS_WARNING_CLANG("-Wgnu-zero-variadic-macro-arguments")
|
||||
// NOLINTEND(*)
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Werror"
|
||||
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||
|
||||
// some debugging scaffolds
|
||||
#ifdef RYML_DBG
|
||||
#include <c4/dump.hpp>
|
||||
namespace c4 {
|
||||
inline void _dbg_dumper(csubstr s) { fwrite(s.str, 1, s.len, stdout); };
|
||||
template<class ...Args>
|
||||
void _dbg_printf(c4::csubstr fmt, Args&& ...args)
|
||||
{
|
||||
static char writebuf[256];
|
||||
auto results = c4::format_dump_resume<&_dbg_dumper>(writebuf, fmt, std::forward<Args>(args)...);
|
||||
// resume writing if the results failed to fit the buffer
|
||||
if(C4_UNLIKELY(results.bufsize > sizeof(writebuf))) // bufsize will be that of the largest element serialized. Eg int(1), will require 1 byte.
|
||||
{
|
||||
results = format_dump_resume<&_dbg_dumper>(results, writebuf, fmt, std::forward<Args>(args)...);
|
||||
if(C4_UNLIKELY(results.bufsize > sizeof(writebuf)))
|
||||
{
|
||||
results = format_dump_resume<&_dbg_dumper>(results, writebuf, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace c4
|
||||
|
||||
# define _c4dbgt(fmt, ...) this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, ## __VA_ARGS__)
|
||||
# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__)
|
||||
# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
|
||||
# define _c4dbgq(msg) _dbg_printf(msg "\n")
|
||||
#ifndef RYML_DBG
|
||||
# define _c4err(fmt, ...) \
|
||||
do { if(c4::is_debugger_attached()) { C4_DEBUG_BREAK(); } \
|
||||
this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__, ## __VA_ARGS__); } while(0)
|
||||
#else
|
||||
this->_err("ERROR: " fmt, ## __VA_ARGS__)
|
||||
# define _c4dbgt(fmt, ...)
|
||||
# define _c4dbgpf(fmt, ...)
|
||||
# define _c4dbgpf_(fmt, ...)
|
||||
# define _c4dbgp(msg)
|
||||
# define _c4dbgp_(msg)
|
||||
# define _c4dbgq(msg)
|
||||
# define _c4presc(...)
|
||||
# define _c4prscalar(msg, scalar, keep_newlines)
|
||||
#else
|
||||
# define _c4err(fmt, ...) \
|
||||
do { if(c4::is_debugger_attached()) { C4_DEBUG_BREAK(); } \
|
||||
this->_err("ERROR: " fmt, ## __VA_ARGS__); } while(0)
|
||||
#endif
|
||||
do { RYML_DEBUG_BREAK(); this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__, ## __VA_ARGS__); } while(0)
|
||||
# define _c4dbgt(fmt, ...) do { if(_dbg_enabled()) { \
|
||||
this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, ## __VA_ARGS__); } } while(0)
|
||||
# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__)
|
||||
# define _c4dbgpf_(fmt, ...) _dbg_printf("{}:{}: " fmt , __FILE__, __LINE__, ## __VA_ARGS__)
|
||||
# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
|
||||
# define _c4dbgp_(msg) _dbg_printf("{}:{}: " msg , __FILE__, __LINE__ )
|
||||
# define _c4dbgq(msg) _dbg_printf(msg "\n")
|
||||
# define _c4presc(...) do { if(_dbg_enabled()) __c4presc(__VA_ARGS__); } while(0)
|
||||
# define _c4prscalar(msg, scalar, keep_newlines) \
|
||||
do { \
|
||||
_c4dbgpf_("{}: [{}]~~~", msg, scalar.len); \
|
||||
if(_dbg_enabled()) { \
|
||||
__c4presc((scalar).str, (scalar).len, (keep_newlines)); \
|
||||
} \
|
||||
_c4dbgq("~~~"); \
|
||||
} while(0)
|
||||
#endif // RYML_DBG
|
||||
|
||||
#define _c4prsp(sp) sp
|
||||
#define _c4presc(s) __c4presc(s.str, s.len)
|
||||
inline c4::csubstr _c4prc(const char &C4_RESTRICT c)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef RYML_DBG
|
||||
|
||||
#include <c4/dump.hpp>
|
||||
namespace c4 {
|
||||
inline bool& _dbg_enabled() { static bool enabled = true; return enabled; }
|
||||
inline void _dbg_set_enabled(bool yes) { _dbg_enabled() = yes; }
|
||||
inline void _dbg_dumper(csubstr s)
|
||||
{
|
||||
switch(c)
|
||||
if(s.str)
|
||||
fwrite(s.str, 1, s.len, stdout);
|
||||
}
|
||||
inline substr _dbg_buf() noexcept
|
||||
{
|
||||
static char writebuf[2048];
|
||||
return substr{writebuf, sizeof(writebuf)}; // g++-5 has trouble with return writebuf;
|
||||
}
|
||||
template<class ...Args>
|
||||
C4_NO_INLINE void _dbg_printf(c4::csubstr fmt, Args const& ...args)
|
||||
{
|
||||
if(_dbg_enabled())
|
||||
{
|
||||
case '\n': return c4::csubstr("\\n");
|
||||
case '\t': return c4::csubstr("\\t");
|
||||
case '\0': return c4::csubstr("\\0");
|
||||
case '\r': return c4::csubstr("\\r");
|
||||
case '\f': return c4::csubstr("\\f");
|
||||
case '\b': return c4::csubstr("\\b");
|
||||
case '\v': return c4::csubstr("\\v");
|
||||
case '\a': return c4::csubstr("\\a");
|
||||
default: return c4::csubstr(&c, 1);
|
||||
substr buf = _dbg_buf();
|
||||
const size_t needed_size = c4::format_dump(&_dbg_dumper, buf, fmt, args...);
|
||||
C4_CHECK(needed_size <= buf.len);
|
||||
}
|
||||
}
|
||||
inline void __c4presc(const char *s, size_t len)
|
||||
inline C4_NO_INLINE void __c4presc(const char *s, size_t len, bool keep_newlines=false)
|
||||
{
|
||||
RYML_ASSERT(s || !len);
|
||||
size_t prev = 0;
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
switch(s[i])
|
||||
{
|
||||
case '\n' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('n'); putchar('\n'); prev = i+1; break;
|
||||
case '\t' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('t'); prev = i+1; break;
|
||||
case '\0' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('0'); prev = i+1; break;
|
||||
case '\r' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('r'); prev = i+1; break;
|
||||
case '\f' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('f'); prev = i+1; break;
|
||||
case '\b' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('b'); prev = i+1; break;
|
||||
case '\v' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('v'); prev = i+1; break;
|
||||
case '\a' : if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('a'); prev = i+1; break;
|
||||
case '\x1b': if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('e'); prev = i+1; break;
|
||||
case '\n' : _dbg_printf("{}{}{}", csubstr(s+prev, i-prev), csubstr("\\n"), csubstr(keep_newlines ? "\n":"")); prev = i+1; break;
|
||||
case '\t' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\t")); prev = i+1; break;
|
||||
case '\0' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\0")); prev = i+1; break;
|
||||
case '\r' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\r")); prev = i+1; break;
|
||||
case '\f' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\f")); prev = i+1; break;
|
||||
case '\b' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\b")); prev = i+1; break;
|
||||
case '\v' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\v")); prev = i+1; break;
|
||||
case '\a' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\a")); prev = i+1; break;
|
||||
case '\x1b': _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\x1b")); prev = i+1; break;
|
||||
case -0x3e/*0xc2u*/:
|
||||
if(i+1 < len)
|
||||
{
|
||||
if(s[i+1] == -0x60/*0xa0u*/)
|
||||
{
|
||||
if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('_'); prev = i+2; ++i;
|
||||
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\_")); prev = i+1;
|
||||
}
|
||||
else if(s[i+1] == -0x7b/*0x85u*/)
|
||||
{
|
||||
if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('N'); prev = i+2; ++i;
|
||||
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\N")); prev = i+1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case -0x1e/*0xe2u*/:
|
||||
if(i+2 < len && s[i+1] == -0x80/*0x80u*/)
|
||||
{
|
||||
if(s[i+2] == -0x58/*0xa8u*/)
|
||||
{
|
||||
if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('L'); prev = i+3; i += 2;
|
||||
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\L")); prev = i+1;
|
||||
}
|
||||
else if(s[i+2] == -0x57/*0xa9u*/)
|
||||
{
|
||||
if(i > prev) { fwrite(s+prev, 1, i-prev, stdout); } putchar('\\'); putchar('P'); prev = i+3; i += 2;
|
||||
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\P")); prev = i+1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(len > prev)
|
||||
fwrite(s + prev, 1, len - prev, stdout);
|
||||
_dbg_printf("{}", csubstr(s+prev, len-prev));
|
||||
}
|
||||
inline void __c4presc(csubstr s, bool keep_newlines=false)
|
||||
{
|
||||
__c4presc(s.str, s.len, keep_newlines);
|
||||
}
|
||||
} // namespace c4
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
#endif // RYML_DBG
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
C4_SUPPRESS_WARNING_MSVC_POP
|
||||
|
||||
#endif /* _C4_YML_DETAIL_PARSER_DBG_HPP_ */
|
||||
|
||||
152
3rdparty/rapidyaml/include/c4/yml/detail/print.hpp
vendored
152
3rdparty/rapidyaml/include/c4/yml/detail/print.hpp
vendored
@@ -4,20 +4,76 @@
|
||||
#include "c4/yml/tree.hpp"
|
||||
#include "c4/yml/node.hpp"
|
||||
|
||||
#ifdef RYML_DBG
|
||||
#define _c4dbg_tree(...) print_tree(__VA_ARGS__)
|
||||
#define _c4dbg_node(...) print_tree(__VA_ARGS__)
|
||||
#else
|
||||
#define _c4dbg_tree(...)
|
||||
#define _c4dbg_node(...)
|
||||
#endif
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
|
||||
|
||||
inline size_t print_node(Tree const& p, size_t node, int level, size_t count, bool print_children)
|
||||
inline const char* _container_style_code(Tree const& p, id_type node)
|
||||
{
|
||||
printf("[%zd]%*s[%zd] %p", count, (2*level), "", node, (void const*)p.get(node));
|
||||
if(p.is_container(node))
|
||||
{
|
||||
if(p._p(node)->m_type & (FLOW_SL|FLOW_ML))
|
||||
{
|
||||
return "[FLOW]";
|
||||
}
|
||||
if(p._p(node)->m_type & (BLOCK))
|
||||
{
|
||||
return "[BLCK]";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
inline char _scalar_code(NodeType masked)
|
||||
{
|
||||
if(masked & (KEY_LITERAL|VAL_LITERAL))
|
||||
return '|';
|
||||
if(masked & (KEY_FOLDED|VAL_FOLDED))
|
||||
return '>';
|
||||
if(masked & (KEY_SQUO|VAL_SQUO))
|
||||
return '\'';
|
||||
if(masked & (KEY_DQUO|VAL_DQUO))
|
||||
return '"';
|
||||
if(masked & (KEY_PLAIN|VAL_PLAIN))
|
||||
return '~';
|
||||
return '@';
|
||||
}
|
||||
inline char _scalar_code_key(NodeType t)
|
||||
{
|
||||
return _scalar_code(t & KEY_STYLE);
|
||||
}
|
||||
inline char _scalar_code_val(NodeType t)
|
||||
{
|
||||
return _scalar_code(t & VAL_STYLE);
|
||||
}
|
||||
inline char _scalar_code_key(Tree const& p, id_type node)
|
||||
{
|
||||
return _scalar_code_key(p._p(node)->m_type);
|
||||
}
|
||||
inline char _scalar_code_val(Tree const& p, id_type node)
|
||||
{
|
||||
return _scalar_code_key(p._p(node)->m_type);
|
||||
}
|
||||
inline id_type print_node(Tree const& p, id_type node, int level, id_type count, bool print_children)
|
||||
{
|
||||
printf("[%zu]%*s[%zu] %p", (size_t)count, (2*level), "", (size_t)node, (void const*)p.get(node));
|
||||
if(p.is_root(node))
|
||||
{
|
||||
printf(" [ROOT]");
|
||||
}
|
||||
printf(" %s:", p.type_str(node));
|
||||
char typebuf[128];
|
||||
csubstr typestr = p.type(node).type_str(typebuf);
|
||||
RYML_CHECK(typestr.str);
|
||||
printf(" %.*s", (int)typestr.len, typestr.str);
|
||||
if(p.has_key(node))
|
||||
{
|
||||
if(p.has_key_anchor(node))
|
||||
@@ -28,65 +84,47 @@ inline size_t print_node(Tree const& p, size_t node, int level, size_t count, bo
|
||||
if(p.has_key_tag(node))
|
||||
{
|
||||
csubstr kt = p.key_tag(node);
|
||||
csubstr k = p.key(node);
|
||||
printf(" %.*s '%.*s'", (int)kt.len, kt.str, (int)k.len, k.str);
|
||||
}
|
||||
else
|
||||
{
|
||||
csubstr k = p.key(node);
|
||||
printf(" '%.*s'", (int)k.len, k.str);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RYML_ASSERT( ! p.has_key_tag(node));
|
||||
}
|
||||
if(p.has_val(node))
|
||||
{
|
||||
if(p.has_val_tag(node))
|
||||
{
|
||||
csubstr vt = p.val_tag(node);
|
||||
csubstr v = p.val(node);
|
||||
printf(" %.*s '%.*s'", (int)vt.len, vt.str, (int)v.len, v.str);
|
||||
}
|
||||
else
|
||||
{
|
||||
csubstr v = p.val(node);
|
||||
printf(" '%.*s'", (int)v.len, v.str);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(p.has_val_tag(node))
|
||||
{
|
||||
csubstr vt = p.val_tag(node);
|
||||
printf(" %.*s", (int)vt.len, vt.str);
|
||||
printf(" <%.*s>", (int)kt.len, kt.str);
|
||||
}
|
||||
const char code = _scalar_code_key(p, node);
|
||||
csubstr k = p.key(node);
|
||||
printf(" %c%.*s%c :", code, (int)k.len, k.str, code);
|
||||
}
|
||||
if(p.has_val_anchor(node))
|
||||
{
|
||||
auto &a = p.val_anchor(node);
|
||||
printf(" valanchor='&%.*s'", (int)a.len, a.str);
|
||||
csubstr a = p.val_anchor(node);
|
||||
printf(" &%.*s'", (int)a.len, a.str);
|
||||
}
|
||||
printf(" (%zd sibs)", p.num_siblings(node));
|
||||
if(p.has_val_tag(node))
|
||||
{
|
||||
csubstr vt = p.val_tag(node);
|
||||
printf(" <%.*s>", (int)vt.len, vt.str);
|
||||
}
|
||||
if(p.has_val(node))
|
||||
{
|
||||
const char code = _scalar_code_val(p, node);
|
||||
csubstr v = p.val(node);
|
||||
printf(" %c%.*s%c", code, (int)v.len, v.str, code);
|
||||
}
|
||||
printf(" (%zu sibs)", (size_t)p.num_siblings(node));
|
||||
|
||||
++count;
|
||||
|
||||
if(p.is_container(node))
|
||||
if(!p.is_container(node))
|
||||
{
|
||||
printf(" %zd children:\n", p.num_children(node));
|
||||
printf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" (%zu children)\n", (size_t)p.num_children(node));
|
||||
if(print_children)
|
||||
{
|
||||
for(size_t i = p.first_child(node); i != NONE; i = p.next_sibling(i))
|
||||
for(id_type i = p.first_child(node); i != NONE; i = p.next_sibling(i))
|
||||
{
|
||||
count = print_node(p, i, level+1, count, print_children);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -106,21 +144,37 @@ inline void print_node(ConstNodeRef const& p, int level=0)
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline size_t print_tree(Tree const& p, size_t node=NONE)
|
||||
inline id_type print_tree(const char *message, Tree const& p, id_type node=NONE)
|
||||
{
|
||||
printf("--------------------------------------\n");
|
||||
size_t ret = 0;
|
||||
if(message != nullptr)
|
||||
printf("%s:\n", message);
|
||||
id_type ret = 0;
|
||||
if(!p.empty())
|
||||
{
|
||||
if(node == NONE)
|
||||
node = p.root_id();
|
||||
ret = print_node(p, node, 0, 0, true);
|
||||
}
|
||||
printf("#nodes=%zd vs #printed=%zd\n", p.size(), ret);
|
||||
printf("#nodes=%zu vs #printed=%zu\n", (size_t)p.size(), (size_t)ret);
|
||||
printf("--------------------------------------\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline id_type print_tree(Tree const& p, id_type node=NONE)
|
||||
{
|
||||
return print_tree(nullptr, p, node);
|
||||
}
|
||||
|
||||
inline void print_tree(ConstNodeRef const& p, int level)
|
||||
{
|
||||
print_node(p, level);
|
||||
for(ConstNodeRef ch : p.children())
|
||||
{
|
||||
print_tree(ch, level+1);
|
||||
}
|
||||
}
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
} /* namespace yml */
|
||||
|
||||
115
3rdparty/rapidyaml/include/c4/yml/detail/stack.hpp
vendored
115
3rdparty/rapidyaml/include/c4/yml/detail/stack.hpp
vendored
@@ -18,22 +18,27 @@ C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
|
||||
namespace detail {
|
||||
|
||||
/** A lightweight contiguous stack with SSO. This avoids a dependency on std. */
|
||||
template<class T, size_t N=16>
|
||||
/** A lightweight contiguous stack with Small Storage
|
||||
* Optimization. This is required because std::vector can throw
|
||||
* exceptions, and we don't want to enforce any particular error
|
||||
* mechanism. */
|
||||
template<class T, id_type N=16>
|
||||
class stack
|
||||
{
|
||||
static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||
static_assert(std::is_trivially_destructible<T>::value, "T must be trivially destructible");
|
||||
|
||||
enum : size_t { sso_size = N };
|
||||
public:
|
||||
|
||||
enum : id_type { sso_size = N };
|
||||
|
||||
public:
|
||||
|
||||
T m_buf[N];
|
||||
T * m_stack;
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
Callbacks m_callbacks;
|
||||
T m_buf[size_t(N)];
|
||||
T *C4_RESTRICT m_stack;
|
||||
id_type m_size;
|
||||
id_type m_capacity;
|
||||
Callbacks m_callbacks;
|
||||
|
||||
public:
|
||||
|
||||
@@ -64,9 +69,12 @@ public:
|
||||
|
||||
stack& operator= (stack const& that) RYML_NOEXCEPT
|
||||
{
|
||||
_cb(that.m_callbacks);
|
||||
resize(that.m_size);
|
||||
_cp(&that);
|
||||
if(&that != this)
|
||||
{
|
||||
_cb(that.m_callbacks);
|
||||
resize(that.m_size);
|
||||
_cp(&that);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -79,29 +87,29 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
size_t empty() const { return m_size == 0; }
|
||||
size_t capacity() const { return m_capacity; }
|
||||
id_type size() const { return m_size; }
|
||||
id_type empty() const { return m_size == 0; }
|
||||
id_type capacity() const { return m_capacity; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void resize(size_t sz)
|
||||
void resize(id_type sz)
|
||||
{
|
||||
reserve(sz);
|
||||
m_size = sz;
|
||||
}
|
||||
|
||||
void reserve(size_t sz);
|
||||
void reserve(id_type sz);
|
||||
|
||||
void push(T const& C4_RESTRICT n)
|
||||
{
|
||||
RYML_ASSERT((const char*)&n + sizeof(T) < (const char*)m_stack || &n > m_stack + m_capacity);
|
||||
_RYML_CB_ASSERT(m_callbacks, (const char*)&n + sizeof(T) < (const char*)m_stack || &n > m_stack + m_capacity);
|
||||
if(m_size == m_capacity)
|
||||
{
|
||||
size_t cap = m_capacity == 0 ? N : 2 * m_capacity;
|
||||
id_type cap = m_capacity == 0 ? N : 2 * m_capacity;
|
||||
reserve(cap);
|
||||
}
|
||||
m_stack[m_size] = n;
|
||||
@@ -110,10 +118,10 @@ public:
|
||||
|
||||
void push_top()
|
||||
{
|
||||
RYML_ASSERT(m_size > 0);
|
||||
_RYML_CB_ASSERT(m_callbacks, m_size > 0);
|
||||
if(m_size == m_capacity)
|
||||
{
|
||||
size_t cap = m_capacity == 0 ? N : 2 * m_capacity;
|
||||
id_type cap = m_capacity == 0 ? N : 2 * m_capacity;
|
||||
reserve(cap);
|
||||
}
|
||||
m_stack[m_size] = m_stack[m_size - 1];
|
||||
@@ -122,25 +130,25 @@ public:
|
||||
|
||||
T const& C4_RESTRICT pop()
|
||||
{
|
||||
RYML_ASSERT(m_size > 0);
|
||||
_RYML_CB_ASSERT(m_callbacks, m_size > 0);
|
||||
--m_size;
|
||||
return m_stack[m_size];
|
||||
}
|
||||
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT top() const { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT top() { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT top() const { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[m_size - 1]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT top() { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[m_size - 1]; }
|
||||
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom() const { RYML_ASSERT(m_size > 0); return m_stack[0]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT bottom() { RYML_ASSERT(m_size > 0); return m_stack[0]; }
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom() const { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[0]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT bottom() { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[0]; }
|
||||
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT top(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT top(size_t i) { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT top(id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[m_size - 1 - i]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT top(id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[m_size - 1 - i]; }
|
||||
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT bottom(size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom(id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT bottom(id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
|
||||
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT operator[](size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT operator[](size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||
C4_ALWAYS_INLINE T const& C4_RESTRICT operator[](id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
|
||||
C4_ALWAYS_INLINE T & C4_RESTRICT operator[](id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
|
||||
|
||||
public:
|
||||
|
||||
@@ -154,10 +162,12 @@ public:
|
||||
const_iterator end () const { return (const_iterator)m_stack + m_size; }
|
||||
|
||||
public:
|
||||
|
||||
void _free();
|
||||
void _cp(stack const* C4_RESTRICT that);
|
||||
void _mv(stack * that);
|
||||
void _cb(Callbacks const& cb);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -165,8 +175,8 @@ public:
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T, size_t N>
|
||||
void stack<T, N>::reserve(size_t sz)
|
||||
template<class T, id_type N>
|
||||
void stack<T, N>::reserve(id_type sz)
|
||||
{
|
||||
if(sz <= m_size)
|
||||
return;
|
||||
@@ -176,11 +186,12 @@ void stack<T, N>::reserve(size_t sz)
|
||||
m_capacity = N;
|
||||
return;
|
||||
}
|
||||
T *buf = (T*) m_callbacks.m_allocate(sz * sizeof(T), m_stack, m_callbacks.m_user_data);
|
||||
memcpy(buf, m_stack, m_size * sizeof(T));
|
||||
T *buf = (T*) m_callbacks.m_allocate((size_t)sz * sizeof(T), m_stack, m_callbacks.m_user_data);
|
||||
_RYML_CB_ASSERT(m_callbacks, ((uintptr_t)buf % alignof(T)) == 0u);
|
||||
memcpy(buf, m_stack, (size_t)m_size * sizeof(T));
|
||||
if(m_stack != m_buf)
|
||||
{
|
||||
m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);
|
||||
m_callbacks.m_free(m_stack, (size_t)m_capacity * sizeof(T), m_callbacks.m_user_data);
|
||||
}
|
||||
m_stack = buf;
|
||||
m_capacity = sz;
|
||||
@@ -189,38 +200,38 @@ void stack<T, N>::reserve(size_t sz)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T, size_t N>
|
||||
template<class T, id_type N>
|
||||
void stack<T, N>::_free()
|
||||
{
|
||||
RYML_ASSERT(m_stack != nullptr); // this structure cannot be memset() to zero
|
||||
_RYML_CB_ASSERT(m_callbacks, m_stack != nullptr); // this structure cannot be memset() to zero
|
||||
if(m_stack != m_buf)
|
||||
{
|
||||
m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);
|
||||
m_callbacks.m_free(m_stack, (size_t)m_capacity * sizeof(T), m_callbacks.m_user_data);
|
||||
m_stack = m_buf;
|
||||
m_size = N;
|
||||
m_capacity = N;
|
||||
}
|
||||
else
|
||||
{
|
||||
RYML_ASSERT(m_capacity == N);
|
||||
_RYML_CB_ASSERT(m_callbacks, m_capacity == N);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T, size_t N>
|
||||
template<class T, id_type N>
|
||||
void stack<T, N>::_cp(stack const* C4_RESTRICT that)
|
||||
{
|
||||
if(that->m_stack != that->m_buf)
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity > N);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_capacity > N);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity <= N);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_capacity <= N);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
|
||||
}
|
||||
memcpy(m_stack, that->m_stack, that->m_size * sizeof(T));
|
||||
m_size = that->m_size;
|
||||
@@ -231,19 +242,19 @@ void stack<T, N>::_cp(stack const* C4_RESTRICT that)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T, size_t N>
|
||||
template<class T, id_type N>
|
||||
void stack<T, N>::_mv(stack * that)
|
||||
{
|
||||
if(that->m_stack != that->m_buf)
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity > N);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_capacity > N);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
|
||||
m_stack = that->m_stack;
|
||||
}
|
||||
else
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity <= N);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_capacity <= N);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
|
||||
memcpy(m_buf, that->m_buf, that->m_size * sizeof(T));
|
||||
m_stack = m_buf;
|
||||
}
|
||||
@@ -251,7 +262,7 @@ void stack<T, N>::_mv(stack * that)
|
||||
m_capacity = that->m_capacity;
|
||||
m_callbacks = that->m_callbacks;
|
||||
// make sure no deallocation happens on destruction
|
||||
RYML_ASSERT(that->m_stack != m_buf);
|
||||
_RYML_CB_ASSERT(m_callbacks, that->m_stack != m_buf);
|
||||
that->m_stack = that->m_buf;
|
||||
that->m_capacity = N;
|
||||
that->m_size = 0;
|
||||
@@ -260,7 +271,7 @@ void stack<T, N>::_mv(stack * that)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T, size_t N>
|
||||
template<class T, id_type N>
|
||||
void stack<T, N>::_cb(Callbacks const& cb)
|
||||
{
|
||||
if(cb != m_callbacks)
|
||||
|
||||
916
3rdparty/rapidyaml/include/c4/yml/emit.def.hpp
vendored
916
3rdparty/rapidyaml/include/c4/yml/emit.def.hpp
vendored
File diff suppressed because it is too large
Load Diff
681
3rdparty/rapidyaml/include/c4/yml/emit.hpp
vendored
681
3rdparty/rapidyaml/include/c4/yml/emit.hpp
vendored
@@ -15,13 +15,8 @@
|
||||
#include "./node.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef emit
|
||||
#error "emit is defined, likely from a Qt include. This will cause a compilation error. See https://github.com/biojppm/rapidyaml/issues/120"
|
||||
#endif
|
||||
#define RYML_DEPRECATE_EMIT \
|
||||
RYML_DEPRECATED("use emit_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
|
||||
#define RYML_DEPRECATE_EMITRS \
|
||||
RYML_DEPRECATED("use emitrs_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -43,6 +38,15 @@ using EmitterOStream = Emitter<WriterOStream<OStream>>;
|
||||
using EmitterFile = Emitter<WriterFile>;
|
||||
using EmitterBuf = Emitter<WriterBuf>;
|
||||
|
||||
namespace detail {
|
||||
inline bool is_set_(ConstNodeRef n) { return n.tree() && (n.id() != NONE); }
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** Specifies the type of content to emit */
|
||||
typedef enum {
|
||||
EMIT_YAML = 0, ///< emit YAML
|
||||
@@ -50,6 +54,59 @@ typedef enum {
|
||||
} EmitType_e;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** A lightweight object containing options to be used when emitting. */
|
||||
struct EmitOptions
|
||||
{
|
||||
typedef enum : uint32_t {
|
||||
DEFAULT_FLAGS = 0u,
|
||||
JSON_ERR_ON_TAG = 1u << 0u,
|
||||
JSON_ERR_ON_ANCHOR = 1u << 1u,
|
||||
_JSON_ERR_MASK = JSON_ERR_ON_TAG|JSON_ERR_ON_ANCHOR,
|
||||
} EmitOptionFlags_e;
|
||||
|
||||
public:
|
||||
|
||||
/** @name option flags
|
||||
*
|
||||
* @{ */
|
||||
C4_ALWAYS_INLINE EmitOptionFlags_e json_error_flags() const noexcept { return m_option_flags; }
|
||||
EmitOptions& json_error_flags(EmitOptionFlags_e d) noexcept { m_option_flags = (EmitOptionFlags_e)(d & _JSON_ERR_MASK); return *this; }
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name max depth for the emitted tree
|
||||
*
|
||||
* This makes the emitter fail when emitting trees exceeding the
|
||||
* max_depth.
|
||||
*
|
||||
* @{ */
|
||||
C4_ALWAYS_INLINE id_type max_depth() const noexcept { return m_max_depth; }
|
||||
EmitOptions& max_depth(id_type d) noexcept { m_max_depth = d; return *this; }
|
||||
static constexpr const id_type max_depth_default = 64;
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
bool operator== (const EmitOptions& that) const noexcept
|
||||
{
|
||||
return m_max_depth == that.m_max_depth &&
|
||||
m_option_flags == that.m_option_flags;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** @cond dev */
|
||||
id_type m_max_depth{max_depth_default};
|
||||
EmitOptionFlags_e m_option_flags{DEFAULT_FLAGS};
|
||||
/** @endcond */
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -61,12 +118,21 @@ class Emitter : public Writer
|
||||
{
|
||||
public:
|
||||
|
||||
/** Construct the emitter and its internal Writer state. Every
|
||||
* parameter is forwarded to the constructor of the writer. */
|
||||
/** Construct the emitter and its internal Writer state, using default emit options.
|
||||
* @param args arguments to be forwarded to the constructor of the writer.
|
||||
* */
|
||||
template<class ...Args>
|
||||
Emitter(Args &&...args) : Writer(std::forward<Args>(args)...), m_tree() {}
|
||||
/** emit!
|
||||
Emitter(Args &&...args) : Writer(std::forward<Args>(args)...), m_tree(), m_opts(), m_flow(false) {}
|
||||
|
||||
/** Construct the emitter and its internal Writer state.
|
||||
*
|
||||
* @param opts EmitOptions
|
||||
* @param args arguments to be forwarded to the constructor of the writer.
|
||||
* */
|
||||
template<class ...Args>
|
||||
Emitter(EmitOptions const& opts, Args &&...args) : Writer(std::forward<Args>(args)...), m_tree(), m_opts(opts), m_flow(false) {}
|
||||
|
||||
/** emit!
|
||||
*
|
||||
* When writing to a buffer, returns a substr of the emitted YAML.
|
||||
* If the given buffer has insufficient space, the returned substr
|
||||
@@ -83,36 +149,63 @@ public:
|
||||
* @param error_on_excess when true, an error is raised when the
|
||||
* output buffer is too small for the emitted YAML/JSON
|
||||
* */
|
||||
substr emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);
|
||||
substr emit_as(EmitType_e type, Tree const& t, id_type id, bool error_on_excess);
|
||||
/** emit starting at the root node */
|
||||
substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true);
|
||||
/** emit the given node */
|
||||
substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true);
|
||||
substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true)
|
||||
{
|
||||
if(t.empty())
|
||||
return {};
|
||||
return this->emit_as(type, t, t.root_id(), error_on_excess);
|
||||
}
|
||||
/** emit starting at the given node */
|
||||
substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true)
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return {};
|
||||
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
|
||||
return this->emit_as(type, *n.tree(), n.id(), error_on_excess);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** get the emit options for this object */
|
||||
EmitOptions const& options() const noexcept { return m_opts; }
|
||||
|
||||
/** set the max depth for emitted trees (to prevent a stack overflow) */
|
||||
void max_depth(id_type max_depth) noexcept { m_opts.max_depth(max_depth); }
|
||||
/** get the max depth for emitted trees (to prevent a stack overflow) */
|
||||
id_type max_depth() const noexcept { return m_opts.max_depth(); }
|
||||
|
||||
private:
|
||||
|
||||
Tree const* C4_RESTRICT m_tree;
|
||||
|
||||
void _emit_yaml(size_t id);
|
||||
void _do_visit_flow_sl(size_t id, size_t ilevel=0);
|
||||
void _do_visit_flow_ml(size_t id, size_t ilevel=0, size_t do_indent=1);
|
||||
void _do_visit_block(size_t id, size_t ilevel=0, size_t do_indent=1);
|
||||
void _do_visit_block_container(size_t id, size_t next_level, size_t do_indent);
|
||||
void _do_visit_json(size_t id);
|
||||
EmitOptions m_opts;
|
||||
bool m_flow;
|
||||
|
||||
private:
|
||||
|
||||
void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t level);
|
||||
void _emit_yaml(id_type id);
|
||||
void _do_visit_flow_sl(id_type id, id_type depth, id_type ilevel=0);
|
||||
void _do_visit_flow_ml(id_type id, id_type depth, id_type ilevel=0, id_type do_indent=1);
|
||||
void _do_visit_block(id_type id, id_type depth, id_type ilevel=0, id_type do_indent=1);
|
||||
void _do_visit_block_container(id_type id, id_type depth, id_type next_level, bool do_indent);
|
||||
void _do_visit_json(id_type id, id_type depth);
|
||||
|
||||
private:
|
||||
|
||||
void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, id_type level);
|
||||
void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);
|
||||
|
||||
void _write_doc(size_t id);
|
||||
void _write_scalar(csubstr s, bool was_quoted);
|
||||
void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);
|
||||
void _write_scalar_literal(csubstr s, size_t level, bool as_key, bool explicit_indentation=false);
|
||||
void _write_scalar_folded(csubstr s, size_t level, bool as_key);
|
||||
void _write_scalar_squo(csubstr s, size_t level);
|
||||
void _write_scalar_dquo(csubstr s, size_t level);
|
||||
void _write_scalar_plain(csubstr s, size_t level);
|
||||
void _write_doc(id_type id);
|
||||
void _write_scalar_json_dquo(csubstr s);
|
||||
void _write_scalar_literal(csubstr s, id_type level, bool as_key);
|
||||
void _write_scalar_folded(csubstr s, id_type level, bool as_key);
|
||||
void _write_scalar_squo(csubstr s, id_type level);
|
||||
void _write_scalar_dquo(csubstr s, id_type level);
|
||||
void _write_scalar_plain(csubstr s, id_type level);
|
||||
|
||||
size_t _write_escaped_newlines(csubstr s, size_t i);
|
||||
size_t _write_indented_block(csubstr s, size_t i, id_type level);
|
||||
|
||||
void _write_tag(csubstr tag)
|
||||
{
|
||||
@@ -122,18 +215,28 @@ private:
|
||||
}
|
||||
|
||||
enum : type_bits {
|
||||
_keysc = (KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
|
||||
_valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
|
||||
_keysc = (KEY|KEYREF|KEYANCH|KEYQUO|KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|VAL_STYLE) | CONTAINER_STYLE,
|
||||
_valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|VAL_STYLE) | CONTAINER_STYLE,
|
||||
_keysc_json = (KEY) | ~(VAL),
|
||||
_valsc_json = ~(KEY) | (VAL),
|
||||
};
|
||||
|
||||
C4_ALWAYS_INLINE void _writek(size_t id, size_t level) { _write(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~_valsc, level); }
|
||||
C4_ALWAYS_INLINE void _writev(size_t id, size_t level) { _write(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~_keysc, level); }
|
||||
C4_ALWAYS_INLINE void _writek(id_type id, id_type level) { _write(m_tree->keysc(id), (m_tree->_p(id)->m_type.type & ~_valsc), level); }
|
||||
C4_ALWAYS_INLINE void _writev(id_type id, id_type level) { _write(m_tree->valsc(id), (m_tree->_p(id)->m_type.type & ~_keysc), level); }
|
||||
|
||||
C4_ALWAYS_INLINE void _writek_json(size_t id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
|
||||
C4_ALWAYS_INLINE void _writev_json(size_t id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
|
||||
C4_ALWAYS_INLINE void _writek_json(id_type id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
|
||||
C4_ALWAYS_INLINE void _writev_json(id_type id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
|
||||
|
||||
void _indent(id_type level, bool enabled)
|
||||
{
|
||||
if(enabled)
|
||||
this->Writer::_do_write(' ', 2u * (size_t)level);
|
||||
}
|
||||
void _indent(id_type level)
|
||||
{
|
||||
if(!m_flow)
|
||||
this->Writer::_do_write(' ', 2u * (size_t)level);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -147,33 +250,59 @@ private:
|
||||
*/
|
||||
|
||||
|
||||
/** emit YAML to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written. */
|
||||
inline size_t emit_yaml(Tree const& t, size_t id, FILE *f)
|
||||
// emit from tree and node id -----------------------
|
||||
|
||||
/** (1) emit YAML to the given file, starting at the given node. A null
|
||||
* file defaults to stdout. Return the number of bytes written. */
|
||||
inline size_t emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
|
||||
{
|
||||
EmitterFile em(opts, f);
|
||||
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline size_t emit_yaml(Tree const& t, id_type id, FILE *f)
|
||||
{
|
||||
EmitterFile em(f);
|
||||
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** emit JSON to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written. */
|
||||
inline size_t emit_json(Tree const& t, size_t id, FILE *f)
|
||||
/** (1) emit JSON to the given file, starting at the given node. A null
|
||||
* file defaults to stdout. Return the number of bytes written. */
|
||||
inline size_t emit_json(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
|
||||
{
|
||||
EmitterFile em(opts, f);
|
||||
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline size_t emit_json(Tree const& t, id_type id, FILE *f)
|
||||
{
|
||||
EmitterFile em(f);
|
||||
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
|
||||
}
|
||||
|
||||
|
||||
/** emit YAML to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written.
|
||||
* @overload */
|
||||
// emit from root -------------------------
|
||||
|
||||
/** (1) emit YAML to the given file, starting at the root node. A null file defaults to stdout.
|
||||
* Return the number of bytes written. */
|
||||
inline size_t emit_yaml(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
|
||||
{
|
||||
EmitterFile em(opts, f);
|
||||
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
|
||||
{
|
||||
EmitterFile em(f);
|
||||
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** emit JSON to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written.
|
||||
* @overload */
|
||||
/** (1) emit JSON to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written. */
|
||||
inline size_t emit_json(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
|
||||
{
|
||||
EmitterFile em(opts, f);
|
||||
return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline size_t emit_json(Tree const& t, FILE *f=nullptr)
|
||||
{
|
||||
EmitterFile em(f);
|
||||
@@ -181,19 +310,39 @@ inline size_t emit_json(Tree const& t, FILE *f=nullptr)
|
||||
}
|
||||
|
||||
|
||||
/** emit YAML to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written.
|
||||
* @overload */
|
||||
// emit from ConstNodeRef ------------------------
|
||||
|
||||
/** (1) emit YAML to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written. */
|
||||
inline size_t emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterFile em(opts, f);
|
||||
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterFile em(f);
|
||||
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** emit JSON to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written.
|
||||
* @overload */
|
||||
/** (1) emit JSON to the given file. A null file defaults to stdout.
|
||||
* Return the number of bytes written. */
|
||||
inline size_t emit_json(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterFile em(opts, f);
|
||||
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterFile em(f);
|
||||
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
|
||||
}
|
||||
@@ -208,24 +357,6 @@ inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** mark a tree or node to be emitted as json when using @ref operator<< . For example:
|
||||
*
|
||||
* ```cpp
|
||||
* Tree t = parse_in_arena("{foo: bar}");
|
||||
* std::cout << t; // emits YAML
|
||||
* std::cout << as_json(t); // emits JSON
|
||||
* ```
|
||||
*
|
||||
* @see @ref operator<< */
|
||||
struct as_json
|
||||
{
|
||||
Tree const* tree;
|
||||
size_t node;
|
||||
as_json(Tree const& t) : tree(&t), node(t.empty() ? NONE : t.root_id()) {}
|
||||
as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
|
||||
as_json(ConstNodeRef const& n) : tree(n.tree()), node(n.id()) {}
|
||||
};
|
||||
|
||||
/** emit YAML to an STL-like ostream */
|
||||
template<class OStream>
|
||||
inline OStream& operator<< (OStream& s, Tree const& t)
|
||||
@@ -240,20 +371,77 @@ inline OStream& operator<< (OStream& s, Tree const& t)
|
||||
template<class OStream>
|
||||
inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return s;
|
||||
EmitterOStream<OStream> em(s);
|
||||
em.emit_as(EMIT_YAML, n);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** mark a tree or node to be emitted as yaml when using @ref
|
||||
* operator<<, with options. For example:
|
||||
*
|
||||
* ```cpp
|
||||
* Tree t = parse_in_arena("{foo: bar}");
|
||||
* std::cout << t; // emits YAML
|
||||
* std::cout << as_yaml(t); // emits YAML, same as above
|
||||
* std::cout << as_yaml(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
|
||||
* ```
|
||||
*
|
||||
* @see @ref operator<< */
|
||||
struct as_json
|
||||
{
|
||||
Tree const* tree;
|
||||
size_t node;
|
||||
EmitOptions options;
|
||||
as_json(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
|
||||
as_json(Tree const& t, size_t id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
|
||||
as_json(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
|
||||
};
|
||||
|
||||
/** mark a tree or node to be emitted as yaml when using @ref
|
||||
* operator<< . For example:
|
||||
*
|
||||
* ```cpp
|
||||
* Tree t = parse_in_arena("{foo: bar}");
|
||||
* std::cout << t; // emits YAML
|
||||
* std::cout << as_json(t); // emits JSON
|
||||
* std::cout << as_json(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
|
||||
* ```
|
||||
*
|
||||
* @see @ref operator<< */
|
||||
struct as_yaml
|
||||
{
|
||||
Tree const* tree;
|
||||
size_t node;
|
||||
EmitOptions options;
|
||||
as_yaml(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
|
||||
as_yaml(Tree const& t, size_t id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
|
||||
as_yaml(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
|
||||
};
|
||||
|
||||
/** emit json to an STL-like stream */
|
||||
template<class OStream>
|
||||
inline OStream& operator<< (OStream& s, as_json const& j)
|
||||
{
|
||||
EmitterOStream<OStream> em(s);
|
||||
if(!j.tree || j.node == NONE)
|
||||
return s;
|
||||
EmitterOStream<OStream> em(j.options, s);
|
||||
em.emit_as(EMIT_JSON, *j.tree, j.node, true);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** emit yaml to an STL-like stream */
|
||||
template<class OStream>
|
||||
inline OStream& operator<< (OStream& s, as_yaml const& y)
|
||||
{
|
||||
if(!y.tree || y.node == NONE)
|
||||
return s;
|
||||
EmitterOStream<OStream> em(y.options, s);
|
||||
em.emit_as(EMIT_YAML, *y.tree, y.node, true);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -264,35 +452,85 @@ inline OStream& operator<< (OStream& s, as_json const& j)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||
// emit from tree and node id -----------------------
|
||||
|
||||
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||
* @param t the tree to emit.
|
||||
* @param id the node where to start emitting.
|
||||
* @param opts emit options.
|
||||
* @param buf the output buffer.
|
||||
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||
* @overload */
|
||||
inline substr emit_yaml(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
|
||||
* @return a substr trimmed to the result in the output buffer. If the buffer is
|
||||
* insufficient (when error_on_excess is false), the string pointer of the
|
||||
* result will be set to null, and the length will report the required buffer size. */
|
||||
inline substr emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(opts, buf);
|
||||
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline substr emit_yaml(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(buf);
|
||||
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
|
||||
}
|
||||
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||
* @param t the tree to emit.
|
||||
* @param id the node where to start emitting.
|
||||
* @param opts emit options.
|
||||
* @param buf the output buffer.
|
||||
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||
* @overload */
|
||||
inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
|
||||
* @return a substr trimmed to the result in the output buffer. If the buffer is
|
||||
* insufficient (when error_on_excess is false), the string pointer of the
|
||||
* result will be set to null, and the length will report the required buffer size. */
|
||||
inline substr emit_json(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(opts, buf);
|
||||
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline substr emit_json(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(buf);
|
||||
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
|
||||
}
|
||||
|
||||
|
||||
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||
// emit from root -------------------------
|
||||
|
||||
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||
* @param t the tree; will be emitted from the root node.
|
||||
* @param opts emit options.
|
||||
* @param buf the output buffer.
|
||||
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||
* @overload */
|
||||
* @return a substr trimmed to the result in the output buffer. If the buffer is
|
||||
* insufficient (when error_on_excess is false), the string pointer of the
|
||||
* result will be set to null, and the length will report the required buffer size. */
|
||||
inline substr emit_yaml(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(opts, buf);
|
||||
return em.emit_as(EMIT_YAML, t, error_on_excess);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(buf);
|
||||
return em.emit_as(EMIT_YAML, t, error_on_excess);
|
||||
}
|
||||
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||
* @param t the tree; will be emitted from the root node.
|
||||
* @param opts emit options.
|
||||
* @param buf the output buffer.
|
||||
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||
* @overload */
|
||||
* @return a substr trimmed to the result in the output buffer. If the buffer is
|
||||
* insufficient (when error_on_excess is false), the string pointer of the
|
||||
* result will be set to null, and the length will report the required buffer size. */
|
||||
inline substr emit_json(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(opts, buf);
|
||||
return em.emit_as(EMIT_JSON, t, error_on_excess);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
EmitterBuf em(buf);
|
||||
@@ -300,21 +538,51 @@ inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
|
||||
}
|
||||
|
||||
|
||||
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||
// emit from ConstNodeRef ------------------------
|
||||
|
||||
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||
* @param r the starting node.
|
||||
* @param buf the output buffer.
|
||||
* @param opts emit options.
|
||||
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||
* @overload
|
||||
*/
|
||||
* @return a substr trimmed to the result in the output buffer. If the buffer is
|
||||
* insufficient (when error_on_excess is false), the string pointer of the
|
||||
* result will be set to null, and the length will report the required buffer size. */
|
||||
inline substr emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterBuf em(opts, buf);
|
||||
return em.emit_as(EMIT_YAML, r, error_on_excess);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterBuf em(buf);
|
||||
return em.emit_as(EMIT_YAML, r, error_on_excess);
|
||||
}
|
||||
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||
* @param r the starting node.
|
||||
* @param buf the output buffer.
|
||||
* @param opts emit options.
|
||||
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||
* @overload
|
||||
*/
|
||||
* @return a substr trimmed to the result in the output buffer. If the buffer is
|
||||
* insufficient (when error_on_excess is false), the string pointer of the
|
||||
* result will be set to null, and the length will report the required buffer size. */
|
||||
inline substr emit_json(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterBuf em(opts, buf);
|
||||
return em.emit_as(EMIT_JSON, r, error_on_excess);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
if(!detail::is_set_(r))
|
||||
return {};
|
||||
EmitterBuf em(buf);
|
||||
return em.emit_as(EMIT_JSON, r, error_on_excess);
|
||||
}
|
||||
@@ -322,141 +590,225 @@ inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** emit+resize: emit YAML to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted YAML. */
|
||||
/** @defgroup doc_emit_to_container Emit to resizeable container
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
// emit from tree and node id ---------------------------
|
||||
|
||||
/** (1) emit+resize: emit YAML to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted YAML. If @p append is
|
||||
* set to true, the emitted YAML is appended at the end of the container.
|
||||
*
|
||||
* @return a substr trimmed to the emitted YAML (excluding the initial contents, when appending) */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_yaml(Tree const& t, size_t id, CharOwningContainer * cont)
|
||||
substr emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
substr buf = to_substr(*cont);
|
||||
substr ret = emit_yaml(t, id, buf, /*error_on_excess*/false);
|
||||
size_t startpos = append ? cont->size() : 0u;
|
||||
cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
|
||||
substr buf = to_substr(*cont).sub(startpos);
|
||||
substr ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/false);
|
||||
if(ret.str == nullptr && ret.len > 0)
|
||||
{
|
||||
cont->resize(ret.len);
|
||||
buf = to_substr(*cont);
|
||||
ret = emit_yaml(t, id, buf, /*error_on_excess*/true);
|
||||
cont->resize(startpos + ret.len);
|
||||
buf = to_substr(*cont).sub(startpos);
|
||||
ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cont->resize(startpos + ret.len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/** emit+resize: emit JSON to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted JSON. */
|
||||
/** (2) like (1), but use default emit options */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
|
||||
substr emitrs_yaml(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
substr buf = to_substr(*cont);
|
||||
substr ret = emit_json(t, id, buf, /*error_on_excess*/false);
|
||||
return emitrs_yaml(t, id, EmitOptions{}, cont, append);
|
||||
}
|
||||
/** (1) emit+resize: emit JSON to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted JSON. If @p append is
|
||||
* set to true, the emitted YAML is appended at the end of the container.
|
||||
*
|
||||
* @return a substr trimmed to the emitted JSON (excluding the initial contents, when appending) */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
const size_t startpos = append ? cont->size() : 0u;
|
||||
cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
|
||||
substr buf = to_substr(*cont).sub(startpos);
|
||||
EmitterBuf em(opts, buf);
|
||||
substr ret = emit_json(t, id, opts, buf, /*error_on_excess*/false);
|
||||
if(ret.str == nullptr && ret.len > 0)
|
||||
{
|
||||
cont->resize(ret.len);
|
||||
buf = to_substr(*cont);
|
||||
ret = emit_json(t, id, buf, /*error_on_excess*/true);
|
||||
cont->resize(startpos + ret.len);
|
||||
buf = to_substr(*cont).sub(startpos);
|
||||
ret = emit_json(t, id, opts, buf, /*error_on_excess*/true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cont->resize(startpos + ret.len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/** emit+resize: emit YAML to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted YAML. */
|
||||
/** (2) like (1), but use default emit options */
|
||||
template<class CharOwningContainer>
|
||||
CharOwningContainer emitrs_yaml(Tree const& t, size_t id)
|
||||
substr emitrs_json(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
return emitrs_json(t, id, EmitOptions{}, cont, append);
|
||||
}
|
||||
|
||||
|
||||
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
|
||||
template<class CharOwningContainer>
|
||||
CharOwningContainer emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts={})
|
||||
{
|
||||
CharOwningContainer c;
|
||||
emitrs_yaml(t, id, &c);
|
||||
emitrs_yaml(t, id, opts, &c);
|
||||
return c;
|
||||
}
|
||||
/** emit+resize: emit JSON to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted JSON. */
|
||||
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
|
||||
template<class CharOwningContainer>
|
||||
CharOwningContainer emitrs_json(Tree const& t, size_t id)
|
||||
CharOwningContainer emitrs_json(Tree const& t, id_type id, EmitOptions const& opts={})
|
||||
{
|
||||
CharOwningContainer c;
|
||||
emitrs_json(t, id, &c);
|
||||
emitrs_json(t, id, opts, &c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/** emit+resize: YAML to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted YAML. */
|
||||
// emit from root -------------------------
|
||||
|
||||
/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted YAML.
|
||||
* @return a substr trimmed to the new emitted contents. */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_yaml(Tree const& t, CharOwningContainer * cont)
|
||||
substr emitrs_yaml(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(t.empty())
|
||||
return {};
|
||||
return emitrs_yaml(t, t.root_id(), cont);
|
||||
return emitrs_yaml(t, t.root_id(), opts, cont, append);
|
||||
}
|
||||
/** emit+resize: JSON to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted JSON. */
|
||||
/** (2) like (1), but use default emit options */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(Tree const& t, CharOwningContainer * cont)
|
||||
substr emitrs_yaml(Tree const& t, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(t.empty())
|
||||
return {};
|
||||
return emitrs_json(t, t.root_id(), cont);
|
||||
return emitrs_yaml(t, t.root_id(), EmitOptions{}, cont, append);
|
||||
}
|
||||
/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like
|
||||
* container, resizing it as needed to fit the emitted JSON.
|
||||
* @return a substr trimmed to the new emitted contents. */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(t.empty())
|
||||
return {};
|
||||
return emitrs_json(t, t.root_id(), opts, cont, append);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(Tree const& t, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(t.empty())
|
||||
return {};
|
||||
return emitrs_json(t, t.root_id(), EmitOptions{}, cont, append);
|
||||
}
|
||||
|
||||
|
||||
/** emit+resize: YAML to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted YAML. */
|
||||
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
|
||||
template<class CharOwningContainer>
|
||||
CharOwningContainer emitrs_yaml(Tree const& t)
|
||||
CharOwningContainer emitrs_yaml(Tree const& t, EmitOptions const& opts={})
|
||||
{
|
||||
CharOwningContainer c;
|
||||
if(t.empty())
|
||||
return c;
|
||||
emitrs_yaml(t, t.root_id(), &c);
|
||||
emitrs_yaml(t, t.root_id(), opts, &c);
|
||||
return c;
|
||||
}
|
||||
/** emit+resize: JSON to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted JSON. */
|
||||
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
|
||||
template<class CharOwningContainer>
|
||||
CharOwningContainer emitrs_json(Tree const& t)
|
||||
CharOwningContainer emitrs_json(Tree const& t, EmitOptions const& opts={})
|
||||
{
|
||||
CharOwningContainer c;
|
||||
if(t.empty())
|
||||
return c;
|
||||
emitrs_json(t, t.root_id(), &c);
|
||||
emitrs_json(t, t.root_id(), opts, &c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/** emit+resize: YAML to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted YAML. */
|
||||
// emit from ConstNodeRef ------------------------
|
||||
|
||||
|
||||
/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted YAML.
|
||||
* @return a substr trimmed to the new emitted contents */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont)
|
||||
substr emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return {};
|
||||
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
|
||||
return emitrs_yaml(*n.tree(), n.id(), cont);
|
||||
return emitrs_yaml(*n.tree(), n.id(), opts, cont, append);
|
||||
}
|
||||
/** emit+resize: JSON to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted JSON. */
|
||||
/** (2) like (1), but use default emit options */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)
|
||||
substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return {};
|
||||
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
|
||||
return emitrs_json(*n.tree(), n.id(), cont);
|
||||
return emitrs_yaml(*n.tree(), n.id(), EmitOptions{}, cont, append);
|
||||
}
|
||||
/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted JSON.
|
||||
* @return a substr trimmed to the new emitted contents */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return {};
|
||||
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
|
||||
return emitrs_json(*n.tree(), n.id(), opts, cont, append);
|
||||
}
|
||||
/** (2) like (1), but use default emit options */
|
||||
template<class CharOwningContainer>
|
||||
substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return {};
|
||||
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
|
||||
return emitrs_json(*n.tree(), n.id(), EmitOptions{}, cont, append);
|
||||
}
|
||||
|
||||
|
||||
/** emit+resize: YAML to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted YAML. */
|
||||
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
|
||||
template<class CharOwningContainer>
|
||||
CharOwningContainer emitrs_yaml(ConstNodeRef const& n)
|
||||
CharOwningContainer emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts={})
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return {};
|
||||
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
|
||||
CharOwningContainer c;
|
||||
emitrs_yaml(*n.tree(), n.id(), &c);
|
||||
emitrs_yaml(*n.tree(), n.id(), opts, &c);
|
||||
return c;
|
||||
}
|
||||
/** emit+resize: JSON to the given `std::string`/`std::vector`-like container,
|
||||
* resizing it as needed to fit the emitted JSON. */
|
||||
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
|
||||
template<class CharOwningContainer>
|
||||
CharOwningContainer emitrs_json(ConstNodeRef const& n)
|
||||
CharOwningContainer emitrs_json(ConstNodeRef const& n, EmitOptions const& opts={})
|
||||
{
|
||||
if(!detail::is_set_(n))
|
||||
return {};
|
||||
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
|
||||
CharOwningContainer c;
|
||||
emitrs_json(*n.tree(), n.id(), &c);
|
||||
emitrs_json(*n.tree(), n.id(), opts, &c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -464,7 +816,22 @@ CharOwningContainer emitrs_json(ConstNodeRef const& n)
|
||||
|
||||
/** @cond dev */
|
||||
|
||||
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, size_t id, FILE *f)
|
||||
#define RYML_DEPRECATE_EMIT \
|
||||
RYML_DEPRECATED("use emit_yaml() instead. " \
|
||||
"See https://github.com/biojppm/rapidyaml/issues/120")
|
||||
#define RYML_DEPRECATE_EMITRS \
|
||||
RYML_DEPRECATED("use emitrs_yaml() instead. " \
|
||||
"See https://github.com/biojppm/rapidyaml/issues/120")
|
||||
|
||||
// workaround for Qt emit which is a macro;
|
||||
// see https://github.com/biojppm/rapidyaml/issues/120.
|
||||
// emit is defined in qobjectdefs.h (as an empty define).
|
||||
#ifdef emit
|
||||
#define RYML_TMP_EMIT_
|
||||
#undef emit
|
||||
#endif
|
||||
|
||||
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, id_type id, FILE *f)
|
||||
{
|
||||
return emit_yaml(t, id, f);
|
||||
}
|
||||
@@ -477,7 +844,7 @@ RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
|
||||
return emit_yaml(r, f);
|
||||
}
|
||||
|
||||
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
|
||||
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
|
||||
{
|
||||
return emit_yaml(t, id, buf, error_on_excess);
|
||||
}
|
||||
@@ -490,13 +857,18 @@ RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool e
|
||||
return emit_yaml(r, buf, error_on_excess);
|
||||
}
|
||||
|
||||
#ifdef RYML_TMP_EMIT_
|
||||
#define emit
|
||||
#undef RYML_TMP_EMIT_
|
||||
#endif
|
||||
|
||||
template<class CharOwningContainer>
|
||||
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
|
||||
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, id_type id, CharOwningContainer * cont)
|
||||
{
|
||||
return emitrs_yaml(t, id, cont);
|
||||
}
|
||||
template<class CharOwningContainer>
|
||||
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, size_t id)
|
||||
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, id_type id)
|
||||
{
|
||||
return emitrs_yaml<CharOwningContainer>(t, id);
|
||||
}
|
||||
@@ -520,15 +892,18 @@ RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
|
||||
{
|
||||
return emitrs_yaml<CharOwningContainer>(n);
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
#undef RYML_DEPRECATE_EMIT
|
||||
#undef RYML_DEPRECATE_EMITRS
|
||||
|
||||
#include "c4/yml/emit.def.hpp"
|
||||
#include "c4/yml/emit.def.hpp" // NOLINT
|
||||
|
||||
#endif /* _C4_YML_EMIT_HPP_ */
|
||||
|
||||
194
3rdparty/rapidyaml/include/c4/yml/event_handler_stack.hpp
vendored
Normal file
194
3rdparty/rapidyaml/include/c4/yml/event_handler_stack.hpp
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
#ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
|
||||
#define _C4_YML_EVENT_HANDLER_STACK_HPP_
|
||||
|
||||
#ifndef _C4_YML_DETAIL_STACK_HPP_
|
||||
#include "c4/yml/detail/stack.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef _C4_YML_NODE_TYPE_HPP_
|
||||
#include "c4/yml/node_type.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
|
||||
#include "c4/yml/detail/parser_dbg.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef _C4_YML_PARSER_STATE_HPP_
|
||||
#include "c4/yml/parser_state.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef RYML_DBG
|
||||
#ifndef _C4_YML_DETAIL_PRINT_HPP_
|
||||
#include "c4/yml/detail/print.hpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// NOLINTBEGIN(hicpp-signed-bitwise)
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
/** @addtogroup doc_event_handlers
|
||||
* @{ */
|
||||
|
||||
namespace detail {
|
||||
using pfn_relocate_arena = void (*)(void*, csubstr prev_arena, substr next_arena);
|
||||
} // detail
|
||||
|
||||
/** Use this class a base of implementations of event handler to
|
||||
* simplify the stack logic. */
|
||||
template<class HandlerImpl, class HandlerState>
|
||||
struct EventHandlerStack
|
||||
{
|
||||
static_assert(std::is_base_of<ParserState, HandlerState>::value,
|
||||
"ParserState must be a base of HandlerState");
|
||||
|
||||
using state = HandlerState;
|
||||
using pfn_relocate_arena = detail::pfn_relocate_arena;
|
||||
|
||||
public:
|
||||
|
||||
detail::stack<state> m_stack;
|
||||
state *C4_RESTRICT m_curr; ///< current stack level: top of the stack. cached here for easier access.
|
||||
state *C4_RESTRICT m_parent; ///< parent of the current stack level.
|
||||
pfn_relocate_arena m_relocate_arena; ///< callback when the arena gets relocated
|
||||
void * m_relocate_arena_data;
|
||||
|
||||
protected:
|
||||
|
||||
EventHandlerStack() : m_stack(), m_curr(), m_parent(), m_relocate_arena(), m_relocate_arena_data() {}
|
||||
EventHandlerStack(Callbacks const& cb) : m_stack(cb), m_curr(), m_parent(), m_relocate_arena(), m_relocate_arena_data() {}
|
||||
|
||||
protected:
|
||||
|
||||
void _stack_start_parse(const char *filename, pfn_relocate_arena relocate_arena, void *relocate_arena_data)
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_curr != nullptr);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, relocate_arena != nullptr);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, relocate_arena_data != nullptr);
|
||||
m_curr->start_parse(filename, m_curr->node_id);
|
||||
m_relocate_arena = relocate_arena;
|
||||
m_relocate_arena_data = relocate_arena_data;
|
||||
}
|
||||
|
||||
void _stack_finish_parse()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void _stack_reset_root()
|
||||
{
|
||||
m_stack.clear();
|
||||
m_stack.push({});
|
||||
m_parent = nullptr;
|
||||
m_curr = &m_stack.top();
|
||||
}
|
||||
|
||||
void _stack_reset_non_root()
|
||||
{
|
||||
m_stack.clear();
|
||||
m_stack.push({}); // parent
|
||||
m_stack.push({}); // node
|
||||
m_parent = &m_stack.top(1);
|
||||
m_curr = &m_stack.top();
|
||||
}
|
||||
|
||||
void _stack_push()
|
||||
{
|
||||
m_stack.push_top();
|
||||
m_parent = &m_stack.top(1); // don't use m_curr. watch out for relocations inside the prev push
|
||||
m_curr = &m_stack.top();
|
||||
m_curr->reset_after_push();
|
||||
}
|
||||
|
||||
void _stack_pop()
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_stack.size() > 1);
|
||||
m_parent->reset_before_pop(*m_curr);
|
||||
m_stack.pop();
|
||||
m_parent = m_stack.size() > 1 ? &m_stack.top(1) : nullptr;
|
||||
m_curr = &m_stack.top();
|
||||
#ifdef RYML_DBG
|
||||
if(m_parent)
|
||||
_c4dbgpf("popped! top is now node={} (parent={})", m_curr->node_id, m_parent->node_id);
|
||||
else
|
||||
_c4dbgpf("popped! top is now node={} @ ROOT", m_curr->node_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// undefined at the end
|
||||
#define _has_any_(bits) (static_cast<HandlerImpl const* C4_RESTRICT>(this)->template _has_any__<bits>())
|
||||
|
||||
bool _stack_should_push_on_begin_doc() const
|
||||
{
|
||||
const bool is_root = (m_stack.size() == 1u);
|
||||
return is_root && (_has_any_(DOC|VAL|MAP|SEQ) || m_curr->has_children);
|
||||
}
|
||||
|
||||
bool _stack_should_pop_on_end_doc() const
|
||||
{
|
||||
const bool is_root = (m_stack.size() == 1u);
|
||||
return !is_root && _has_any_(DOC);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void _stack_relocate_to_new_arena(csubstr prev, substr curr)
|
||||
{
|
||||
for(state &st : m_stack)
|
||||
{
|
||||
if(st.line_contents.rem.is_sub(prev))
|
||||
st.line_contents.rem = _stack_relocate_to_new_arena(st.line_contents.rem, prev, curr);
|
||||
if(st.line_contents.full.is_sub(prev))
|
||||
st.line_contents.full = _stack_relocate_to_new_arena(st.line_contents.full, prev, curr);
|
||||
if(st.line_contents.stripped.is_sub(prev))
|
||||
st.line_contents.stripped = _stack_relocate_to_new_arena(st.line_contents.stripped, prev, curr);
|
||||
}
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_relocate_arena != nullptr);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_relocate_arena_data != nullptr);
|
||||
m_relocate_arena(m_relocate_arena_data, prev, curr);
|
||||
}
|
||||
|
||||
substr _stack_relocate_to_new_arena(csubstr s, csubstr prev, substr curr)
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, prev.is_super(s));
|
||||
auto pos = s.str - prev.str;
|
||||
substr out = {curr.str + pos, s.len};
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, curr.is_super(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** Check whether the current parse tokens are trailing on the
|
||||
* previous doc, and raise an error if they are. This function is
|
||||
* called by the parse engine (not the event handler) before a doc
|
||||
* is started. */
|
||||
void check_trailing_doc_token() const
|
||||
{
|
||||
const bool is_root = (m_stack.size() == 1u);
|
||||
const bool isndoc = (m_curr->flags & NDOC) != 0;
|
||||
const bool suspicious = _has_any_(MAP|SEQ|VAL);
|
||||
_c4dbgpf("target={} isroot={} suspicious={} ndoc={}", m_curr->node_id, is_root, suspicious, isndoc);
|
||||
if((is_root || _has_any_(DOC)) && suspicious && !isndoc)
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "parse error", m_curr->pos);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
#undef _has_any_
|
||||
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
|
||||
// NOLINTEND(hicpp-signed-bitwise)
|
||||
|
||||
#endif /* _C4_YML_EVENT_HANDLER_STACK_HPP_ */
|
||||
769
3rdparty/rapidyaml/include/c4/yml/event_handler_tree.hpp
vendored
Normal file
769
3rdparty/rapidyaml/include/c4/yml/event_handler_tree.hpp
vendored
Normal file
@@ -0,0 +1,769 @@
|
||||
#ifndef _C4_YML_EVENT_HANDLER_TREE_HPP_
|
||||
#define _C4_YML_EVENT_HANDLER_TREE_HPP_
|
||||
|
||||
#ifndef _C4_YML_TREE_HPP_
|
||||
#include "c4/yml/tree.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
|
||||
#include "c4/yml/event_handler_stack.hpp"
|
||||
#endif
|
||||
|
||||
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702) // unreachable code
|
||||
// NOLINTBEGIN(hicpp-signed-bitwise)
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
/** @addtogroup doc_event_handlers
|
||||
* @{ */
|
||||
|
||||
|
||||
/** The stack state needed specifically by @ref EventHandlerTree */
|
||||
struct EventHandlerTreeState : public ParserState
|
||||
{
|
||||
NodeData *tr_data;
|
||||
};
|
||||
|
||||
|
||||
/** The event handler to create a ryml @ref Tree. See the
|
||||
* documentation for @ref doc_event_handlers, which has important
|
||||
* notes about the event model used by rapidyaml. */
|
||||
struct EventHandlerTree : public EventHandlerStack<EventHandlerTree, EventHandlerTreeState>
|
||||
{
|
||||
|
||||
/** @name types
|
||||
* @{ */
|
||||
|
||||
using state = EventHandlerTreeState;
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @cond dev */
|
||||
Tree *C4_RESTRICT m_tree;
|
||||
id_type m_id;
|
||||
size_t m_num_directives;
|
||||
bool m_yaml_directive;
|
||||
|
||||
#ifdef RYML_DBG
|
||||
#define _enable_(bits) _enable__<bits>(); _c4dbgpf("node[{}]: enable {}", m_curr->node_id, #bits)
|
||||
#define _disable_(bits) _disable__<bits>(); _c4dbgpf("node[{}]: disable {}", m_curr->node_id, #bits)
|
||||
#else
|
||||
#define _enable_(bits) _enable__<bits>()
|
||||
#define _disable_(bits) _disable__<bits>()
|
||||
#endif
|
||||
#define _has_any_(bits) _has_any__<bits>()
|
||||
/** @endcond */
|
||||
|
||||
public:
|
||||
|
||||
/** @name construction and resetting
|
||||
* @{ */
|
||||
|
||||
EventHandlerTree() : EventHandlerStack(), m_tree(), m_id(NONE), m_num_directives(), m_yaml_directive() {}
|
||||
EventHandlerTree(Callbacks const& cb) : EventHandlerStack(cb), m_tree(), m_id(NONE), m_num_directives(), m_yaml_directive() {}
|
||||
EventHandlerTree(Tree *tree, id_type id) : EventHandlerStack(tree->callbacks()), m_tree(tree), m_id(id), m_num_directives(), m_yaml_directive()
|
||||
{
|
||||
reset(tree, id);
|
||||
}
|
||||
|
||||
void reset(Tree *tree, id_type id)
|
||||
{
|
||||
if(C4_UNLIKELY(!tree))
|
||||
_RYML_CB_ERR(m_stack.m_callbacks, "null tree");
|
||||
if(C4_UNLIKELY(id >= tree->capacity()))
|
||||
_RYML_CB_ERR(tree->callbacks(), "invalid node");
|
||||
if(C4_UNLIKELY(!tree->is_root(id)))
|
||||
if(C4_UNLIKELY(tree->is_map(tree->parent(id))))
|
||||
if(C4_UNLIKELY(!tree->has_key(id)))
|
||||
_RYML_CB_ERR(tree->callbacks(), "destination node belongs to a map and has no key");
|
||||
m_tree = tree;
|
||||
m_id = id;
|
||||
if(m_tree->is_root(id))
|
||||
{
|
||||
_stack_reset_root();
|
||||
_reset_parser_state(m_curr, id, m_tree->root_id());
|
||||
}
|
||||
else
|
||||
{
|
||||
_stack_reset_non_root();
|
||||
_reset_parser_state(m_parent, id, m_tree->parent(id));
|
||||
_reset_parser_state(m_curr, id, id);
|
||||
}
|
||||
m_num_directives = 0;
|
||||
m_yaml_directive = false;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name parse events
|
||||
* @{ */
|
||||
|
||||
void start_parse(const char* filename, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree != nullptr);
|
||||
this->_stack_start_parse(filename, relocate_arena, relocate_arena_data);
|
||||
}
|
||||
|
||||
void finish_parse()
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree != nullptr);
|
||||
if(m_num_directives && !m_tree->is_stream(m_tree->root_id()))
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "directives cannot be used without a document", {});
|
||||
this->_stack_finish_parse();
|
||||
/* This pointer is temporary. Remember that:
|
||||
*
|
||||
* - this handler object may be held by the user
|
||||
* - it may be used with a temporary tree inside the parse function
|
||||
* - when the parse function returns the temporary tree, its address
|
||||
* will change
|
||||
*
|
||||
* As a result, the user could try to read the tree from m_tree, and
|
||||
* end up reading the stale temporary object.
|
||||
*
|
||||
* So it is better to clear it here; then the user will get an obvious
|
||||
* segfault if reading from m_tree. */
|
||||
m_tree = nullptr;
|
||||
}
|
||||
|
||||
void cancel_parse()
|
||||
{
|
||||
m_tree = nullptr;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML stream events */
|
||||
/** @{ */
|
||||
|
||||
C4_ALWAYS_INLINE void begin_stream() const noexcept { /*nothing to do*/ }
|
||||
|
||||
C4_ALWAYS_INLINE void end_stream() const noexcept { /*nothing to do*/ }
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML document events */
|
||||
/** @{ */
|
||||
|
||||
/** implicit doc start (without ---) */
|
||||
void begin_doc()
|
||||
{
|
||||
_c4dbgp("begin_doc");
|
||||
if(_stack_should_push_on_begin_doc())
|
||||
{
|
||||
_c4dbgp("push!");
|
||||
_set_root_as_stream();
|
||||
_push();
|
||||
_enable_(DOC);
|
||||
}
|
||||
}
|
||||
/** implicit doc end (without ...) */
|
||||
void end_doc()
|
||||
{
|
||||
_c4dbgp("end_doc");
|
||||
if(_stack_should_pop_on_end_doc())
|
||||
{
|
||||
_remove_speculative();
|
||||
_c4dbgp("pop!");
|
||||
_pop();
|
||||
}
|
||||
}
|
||||
|
||||
/** explicit doc start, with --- */
|
||||
void begin_doc_expl()
|
||||
{
|
||||
_c4dbgp("begin_doc_expl");
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->root_id() == m_curr->node_id);
|
||||
if(!m_tree->is_stream(m_tree->root_id())) //if(_should_push_on_begin_doc())
|
||||
{
|
||||
_c4dbgp("ensure stream");
|
||||
_set_root_as_stream();
|
||||
id_type first = m_tree->first_child(m_tree->root_id());
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_stream(m_tree->root_id()));
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->num_children(m_tree->root_id()) == 1u);
|
||||
if(m_tree->has_children(first) || m_tree->is_val(first))
|
||||
{
|
||||
_c4dbgp("push!");
|
||||
_push();
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgp("tweak");
|
||||
_push();
|
||||
_remove_speculative();
|
||||
m_curr->node_id = m_tree->last_child(m_tree->root_id());
|
||||
m_curr->tr_data = m_tree->_p(m_curr->node_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgp("push!");
|
||||
_push();
|
||||
}
|
||||
_enable_(DOC);
|
||||
}
|
||||
/** explicit doc end, with ... */
|
||||
void end_doc_expl()
|
||||
{
|
||||
_c4dbgp("end_doc_expl");
|
||||
_remove_speculative();
|
||||
if(_stack_should_pop_on_end_doc())
|
||||
{
|
||||
_c4dbgp("pop!");
|
||||
_pop();
|
||||
}
|
||||
m_yaml_directive = false;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML map events */
|
||||
/** @{ */
|
||||
|
||||
void begin_map_key_flow()
|
||||
{
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
|
||||
}
|
||||
void begin_map_key_block()
|
||||
{
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
|
||||
}
|
||||
|
||||
void begin_map_val_flow()
|
||||
{
|
||||
_c4dbgpf("node[{}]: begin_map_val_flow", m_curr->node_id);
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
|
||||
_enable_(MAP|FLOW_SL);
|
||||
_save_loc();
|
||||
_push();
|
||||
}
|
||||
void begin_map_val_block()
|
||||
{
|
||||
_c4dbgpf("node[{}]: begin_map_val_block", m_curr->node_id);
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
|
||||
_enable_(MAP|BLOCK);
|
||||
_save_loc();
|
||||
_push();
|
||||
}
|
||||
|
||||
void end_map()
|
||||
{
|
||||
_pop();
|
||||
_c4dbgpf("node[{}]: end_map_val", m_curr->node_id);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML seq events */
|
||||
/** @{ */
|
||||
|
||||
void begin_seq_key_flow()
|
||||
{
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
|
||||
}
|
||||
void begin_seq_key_block()
|
||||
{
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
|
||||
}
|
||||
|
||||
void begin_seq_val_flow()
|
||||
{
|
||||
_c4dbgpf("node[{}]: begin_seq_val_flow", m_curr->node_id);
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
|
||||
_enable_(SEQ|FLOW_SL);
|
||||
_save_loc();
|
||||
_push();
|
||||
}
|
||||
void begin_seq_val_block()
|
||||
{
|
||||
_c4dbgpf("node[{}]: begin_seq_val_block", m_curr->node_id);
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
|
||||
_enable_(SEQ|BLOCK);
|
||||
_save_loc();
|
||||
_push();
|
||||
}
|
||||
|
||||
void end_seq()
|
||||
{
|
||||
_pop();
|
||||
_c4dbgpf("node[{}]: end_seq_val", m_curr->node_id);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML structure events */
|
||||
/** @{ */
|
||||
|
||||
void add_sibling()
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->has_children(m_parent->node_id));
|
||||
NodeData const* prev = m_tree->m_buf; // watchout against relocation of the tree nodes
|
||||
_set_state_(m_curr, m_tree->_append_child__unprotected(m_parent->node_id));
|
||||
if(prev != m_tree->m_buf)
|
||||
_refresh_after_relocation();
|
||||
_c4dbgpf("node[{}]: added sibling={} prev={}", m_parent->node_id, m_curr->node_id, m_tree->prev_sibling(m_curr->node_id));
|
||||
}
|
||||
|
||||
/** set the previous val as the first key of a new map, with flow style.
|
||||
*
|
||||
* See the documentation for @ref doc_event_handlers, which has
|
||||
* important notes about this event.
|
||||
*/
|
||||
void actually_val_is_first_key_of_new_map_flow()
|
||||
{
|
||||
if(C4_UNLIKELY(m_tree->is_container(m_curr->node_id)))
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_seq(m_parent->node_id));
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, !m_tree->is_container(m_curr->node_id));
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, !m_tree->has_key(m_curr->node_id));
|
||||
const NodeData tmp = _val2key_(*m_curr->tr_data);
|
||||
_disable_(_VALMASK|VAL_STYLE);
|
||||
m_curr->tr_data->m_val = {};
|
||||
begin_map_val_flow();
|
||||
m_curr->tr_data->m_type = tmp.m_type;
|
||||
m_curr->tr_data->m_key = tmp.m_key;
|
||||
}
|
||||
|
||||
/** like its flow counterpart, but this function can only be
|
||||
* called after the end of a flow-val at root or doc level.
|
||||
*
|
||||
* See the documentation for @ref doc_event_handlers, which has
|
||||
* important notes about this event.
|
||||
*/
|
||||
void actually_val_is_first_key_of_new_map_block()
|
||||
{
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML scalar events */
|
||||
/** @{ */
|
||||
|
||||
|
||||
C4_ALWAYS_INLINE void set_key_scalar_plain_empty() noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
|
||||
m_curr->tr_data->m_key.scalar = {};
|
||||
_enable_(KEY|KEY_PLAIN|KEYNIL);
|
||||
}
|
||||
C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
|
||||
m_curr->tr_data->m_val.scalar = {};
|
||||
_enable_(VAL|VAL_PLAIN|VALNIL);
|
||||
}
|
||||
|
||||
C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_key.scalar = scalar;
|
||||
_enable_(KEY|KEY_PLAIN);
|
||||
}
|
||||
C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_val.scalar = scalar;
|
||||
_enable_(VAL|VAL_PLAIN);
|
||||
}
|
||||
|
||||
|
||||
C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_key.scalar = scalar;
|
||||
_enable_(KEY|KEY_DQUO);
|
||||
}
|
||||
C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_val.scalar = scalar;
|
||||
_enable_(VAL|VAL_DQUO);
|
||||
}
|
||||
|
||||
|
||||
C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_key.scalar = scalar;
|
||||
_enable_(KEY|KEY_SQUO);
|
||||
}
|
||||
C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_val.scalar = scalar;
|
||||
_enable_(VAL|VAL_SQUO);
|
||||
}
|
||||
|
||||
|
||||
C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_key.scalar = scalar;
|
||||
_enable_(KEY|KEY_LITERAL);
|
||||
}
|
||||
C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_val.scalar = scalar;
|
||||
_enable_(VAL|VAL_LITERAL);
|
||||
}
|
||||
|
||||
|
||||
C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_key.scalar = scalar;
|
||||
_enable_(KEY|KEY_FOLDED);
|
||||
}
|
||||
C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
|
||||
m_curr->tr_data->m_val.scalar = scalar;
|
||||
_enable_(VAL|VAL_FOLDED);
|
||||
}
|
||||
|
||||
|
||||
C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() noexcept
|
||||
{
|
||||
_enable_(KEY_UNFILT);
|
||||
}
|
||||
C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() noexcept
|
||||
{
|
||||
_enable_(VAL_UNFILT);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML anchor/reference events */
|
||||
/** @{ */
|
||||
|
||||
void set_key_anchor(csubstr anchor)
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
if(C4_UNLIKELY(_has_any_(KEYREF)))
|
||||
_RYML_CB_ERR_(m_tree->callbacks(), "key cannot have both anchor and ref", m_curr->pos);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), !anchor.begins_with('&'));
|
||||
_enable_(KEYANCH);
|
||||
m_curr->tr_data->m_key.anchor = anchor;
|
||||
}
|
||||
void set_val_anchor(csubstr anchor)
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
if(C4_UNLIKELY(_has_any_(VALREF)))
|
||||
_RYML_CB_ERR_(m_tree->callbacks(), "val cannot have both anchor and ref", m_curr->pos);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), !anchor.begins_with('&'));
|
||||
_enable_(VALANCH);
|
||||
m_curr->tr_data->m_val.anchor = anchor;
|
||||
}
|
||||
|
||||
void set_key_ref(csubstr ref)
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
if(C4_UNLIKELY(_has_any_(KEYANCH)))
|
||||
_RYML_CB_ERR_(m_tree->callbacks(), "key cannot have both anchor and ref", m_curr->pos);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), ref.begins_with('*'));
|
||||
_enable_(KEY|KEYREF);
|
||||
m_curr->tr_data->m_key.anchor = ref.sub(1);
|
||||
m_curr->tr_data->m_key.scalar = ref;
|
||||
}
|
||||
void set_val_ref(csubstr ref)
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
if(C4_UNLIKELY(_has_any_(VALANCH)))
|
||||
_RYML_CB_ERR_(m_tree->callbacks(), "val cannot have both anchor and ref", m_curr->pos);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), ref.begins_with('*'));
|
||||
_enable_(VAL|VALREF);
|
||||
m_curr->tr_data->m_val.anchor = ref.sub(1);
|
||||
m_curr->tr_data->m_val.scalar = ref;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML tag events */
|
||||
/** @{ */
|
||||
|
||||
void set_key_tag(csubstr tag) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
|
||||
_enable_(KEYTAG);
|
||||
m_curr->tr_data->m_key.tag = tag;
|
||||
}
|
||||
void set_val_tag(csubstr tag) noexcept
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
|
||||
_enable_(VALTAG);
|
||||
m_curr->tr_data->m_val.tag = tag;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name YAML directive events */
|
||||
/** @{ */
|
||||
|
||||
C4_NO_INLINE void add_directive(csubstr directive)
|
||||
{
|
||||
_c4dbgpf("% directive! {}", directive);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), directive.begins_with('%'));
|
||||
if(directive.begins_with("%TAG"))
|
||||
{
|
||||
if(C4_UNLIKELY(!m_tree->add_tag_directive(directive)))
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "failed to add directive", m_curr->pos);
|
||||
}
|
||||
else if(directive.begins_with("%YAML"))
|
||||
{
|
||||
_c4dbgpf("%YAML directive! ignoring...: {}", directive);
|
||||
if(C4_UNLIKELY(m_yaml_directive))
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "multiple yaml directives", m_curr->pos);
|
||||
m_yaml_directive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgpf("unknown directive! ignoring... {}", directive);
|
||||
}
|
||||
++m_num_directives;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @name arena functions */
|
||||
/** @{ */
|
||||
|
||||
substr alloc_arena(size_t len)
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
csubstr prev = m_tree->arena();
|
||||
substr out = m_tree->alloc_arena(len);
|
||||
substr curr = m_tree->arena();
|
||||
if(curr.str != prev.str)
|
||||
_stack_relocate_to_new_arena(prev, curr);
|
||||
return out;
|
||||
}
|
||||
|
||||
substr alloc_arena(size_t len, substr *relocated)
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
csubstr prev = m_tree->arena();
|
||||
if(!prev.is_super(*relocated))
|
||||
return alloc_arena(len);
|
||||
substr out = alloc_arena(len);
|
||||
substr curr = m_tree->arena();
|
||||
if(curr.str != prev.str)
|
||||
*relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
public:
|
||||
|
||||
/** @cond dev */
|
||||
void _reset_parser_state(state* st, id_type parse_root, id_type node)
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
_set_state_(st, node);
|
||||
const NodeType type = m_tree->type(node);
|
||||
#ifdef RYML_DBG
|
||||
char flagbuf[80];
|
||||
_c4dbgpf("resetting state: initial flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
|
||||
#endif
|
||||
if(type == NOTYPE)
|
||||
{
|
||||
_c4dbgpf("node[{}] is notype", node);
|
||||
if(m_tree->is_root(parse_root))
|
||||
{
|
||||
_c4dbgpf("node[{}] is root", node);
|
||||
st->flags |= RUNK|RTOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgpf("node[{}] is not root. setting USTY", node);
|
||||
st->flags |= USTY;
|
||||
}
|
||||
}
|
||||
else if(type.is_map())
|
||||
{
|
||||
_c4dbgpf("node[{}] is map", node);
|
||||
st->flags |= RMAP|USTY;
|
||||
}
|
||||
else if(type.is_seq())
|
||||
{
|
||||
_c4dbgpf("node[{}] is map", node);
|
||||
st->flags |= RSEQ|USTY;
|
||||
}
|
||||
else if(type.has_key())
|
||||
{
|
||||
_c4dbgpf("node[{}] has key. setting USTY", node);
|
||||
st->flags |= USTY;
|
||||
}
|
||||
else
|
||||
{
|
||||
_RYML_CB_ERR(m_tree->callbacks(), "cannot append to node");
|
||||
}
|
||||
if(type.is_doc())
|
||||
{
|
||||
_c4dbgpf("node[{}] is doc", node);
|
||||
st->flags |= RDOC;
|
||||
}
|
||||
#ifdef RYML_DBG
|
||||
_c4dbgpf("resetting state: final flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
/** push a new parent, add a child to the new parent, and set the
|
||||
* child as the current node */
|
||||
void _push()
|
||||
{
|
||||
_stack_push();
|
||||
NodeData const* prev = m_tree->m_buf; // watch out against relocation of the tree nodes
|
||||
m_curr->node_id = m_tree->_append_child__unprotected(m_parent->node_id);
|
||||
m_curr->tr_data = m_tree->_p(m_curr->node_id);
|
||||
if(prev != m_tree->m_buf)
|
||||
_refresh_after_relocation();
|
||||
_c4dbgpf("pushed! level={}. top is now node={} (parent={})", m_curr->level, m_curr->node_id, m_parent ? m_parent->node_id : NONE);
|
||||
}
|
||||
/** end the current scope */
|
||||
void _pop()
|
||||
{
|
||||
_remove_speculative_with_parent();
|
||||
_stack_pop();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _enable__() noexcept
|
||||
{
|
||||
m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type | bits);
|
||||
}
|
||||
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _disable__() noexcept
|
||||
{
|
||||
m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type & (~bits));
|
||||
}
|
||||
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE bool _has_any__() const noexcept
|
||||
{
|
||||
return (m_curr->tr_data->m_type.type & bits) != 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
C4_ALWAYS_INLINE void _set_state_(state *C4_RESTRICT s, id_type id) const noexcept
|
||||
{
|
||||
s->node_id = id;
|
||||
s->tr_data = m_tree->_p(id);
|
||||
}
|
||||
void _refresh_after_relocation()
|
||||
{
|
||||
_c4dbgp("tree: refreshing stack data after tree data relocation");
|
||||
for(auto &st : m_stack)
|
||||
st.tr_data = m_tree->_p(st.node_id);
|
||||
}
|
||||
|
||||
void _set_root_as_stream()
|
||||
{
|
||||
_c4dbgp("set root as stream");
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->root_id() == 0u);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), m_curr->node_id == 0u);
|
||||
const bool hack = !m_tree->has_children(m_curr->node_id) && !m_tree->is_val(m_curr->node_id);
|
||||
if(hack)
|
||||
m_tree->_p(m_tree->root_id())->m_type.add(VAL);
|
||||
m_tree->set_root_as_stream();
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()));
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()));
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())));
|
||||
if(hack)
|
||||
m_tree->_p(m_tree->first_child(m_tree->root_id()))->m_type.rem(VAL);
|
||||
_set_state_(m_curr, m_tree->root_id());
|
||||
}
|
||||
|
||||
static NodeData _val2key_(NodeData const& C4_RESTRICT d) noexcept
|
||||
{
|
||||
NodeData r = d;
|
||||
r.m_key = d.m_val;
|
||||
r.m_val = {};
|
||||
r.m_type = d.m_type;
|
||||
static_assert((_VALMASK >> 1u) == _KEYMASK, "required for this function to work");
|
||||
static_assert((VAL_STYLE >> 1u) == KEY_STYLE, "required for this function to work");
|
||||
r.m_type.type = ((d.m_type.type & (_VALMASK|VAL_STYLE)) >> 1u);
|
||||
r.m_type.type = (r.m_type.type & ~(_VALMASK|VAL_STYLE));
|
||||
r.m_type.type = (r.m_type.type | KEY);
|
||||
return r;
|
||||
}
|
||||
|
||||
void _remove_speculative()
|
||||
{
|
||||
_c4dbgp("remove speculative node");
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->empty());
|
||||
const id_type last_added = m_tree->size() - 1;
|
||||
if(m_tree->has_parent(last_added))
|
||||
if(m_tree->_p(last_added)->m_type == NOTYPE)
|
||||
m_tree->remove(last_added);
|
||||
}
|
||||
|
||||
void _remove_speculative_with_parent()
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->empty());
|
||||
const id_type last_added = m_tree->size() - 1;
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_parent(last_added));
|
||||
if(m_tree->_p(last_added)->m_type == NOTYPE)
|
||||
{
|
||||
_c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
|
||||
m_tree->remove(last_added);
|
||||
}
|
||||
}
|
||||
|
||||
C4_ALWAYS_INLINE void _save_loc()
|
||||
{
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
|
||||
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->_p(m_curr->node_id)->m_val.scalar.len == 0);
|
||||
m_tree->_p(m_curr->node_id)->m_val.scalar.str = m_curr->line_contents.rem.str;
|
||||
}
|
||||
|
||||
#undef _enable_
|
||||
#undef _disable_
|
||||
#undef _has_any_
|
||||
|
||||
/** @endcond */
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
|
||||
// NOLINTEND(hicpp-signed-bitwise)
|
||||
C4_SUPPRESS_WARNING_MSVC_POP
|
||||
|
||||
#endif /* _C4_YML_EVENT_HANDLER_TREE_HPP_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user