Compare commits
715 Commits
f077a29cf0
...
master
Author | SHA1 | Date | |
---|---|---|---|
cfb7d22b23 | |||
40df69d8f0 | |||
20a96e7f58 | |||
4872e08c53 | |||
8567e684e6 | |||
85abab4610 | |||
b05ed1a886 | |||
ebfde8e87c | |||
ab12fbe820 | |||
d401bf0fd2 | |||
8dbb9ab30d | |||
cdb46d6b6b | |||
bd7ee1c167 | |||
1c189bfd9c | |||
9878cabc9c | |||
2d59cdb4b2 | |||
f6fff83396 | |||
a6bffe5eea | |||
8c972d0a83 | |||
7b1a3751fc | |||
1572044ade | |||
9d2f2a0344 | |||
3b5874739b | |||
12893ac743 | |||
87de9b6df3 | |||
0318a89f93 | |||
3a929569ee | |||
99a92c0f04 | |||
822b1adbc8 | |||
e6a86869d9 | |||
2654cd1b19 | |||
7021e092b1 | |||
f35a97c33c | |||
da821cefbc | |||
8a7b823a46 | |||
ab40ef7cb1 | |||
f18d716924 | |||
8cb8470c3a | |||
1b72de01fa | |||
1bebb91138 | |||
e5498a36ba | |||
b10e1ed99a | |||
c74025ceac | |||
aa38cbeab1 | |||
241c6c2f8e | |||
c1bfed50b6 | |||
d9f2f90a5a | |||
c3d53a2ecf | |||
86042dc522 | |||
8cb6005b45 | |||
ec0bc95d02 | |||
0bfeb64026 | |||
5bd76bb2be | |||
72c4451ebe | |||
ea9c02539e | |||
da42321807 | |||
4ca3048988 | |||
923dbed53d | |||
65b98e0d38 | |||
84e983f40f | |||
2b992ade88 | |||
ace5ea9bf0 | |||
de75a067a3 | |||
9b40c417a2 | |||
a800b82cff | |||
6d33c6e141 | |||
ac6c36994c | |||
18af7a7a38 | |||
30f60ab667 | |||
ee085e348e | |||
553e883ee1 | |||
fa7a77ca14 | |||
c7be863daf | |||
73d454e4eb | |||
9d8d565c07 | |||
a1024c8fde | |||
98e55e20ce | |||
34fbf05fb3 | |||
a11581c836 | |||
528e312f25 | |||
7420c3f80d | |||
b87866cb0b | |||
0f85bcc128 | |||
1fb590dfc1 | |||
c383c4f5a0 | |||
119bd4fb1d | |||
4668304df0 | |||
90a28d727b | |||
10ad2be8bf | |||
7ef29c9f04 | |||
74f2de81e8 | |||
cc96ed9ea9 | |||
72325822b8 | |||
059034e03c | |||
f6573750a7 | |||
a34165d2c2 | |||
3105cc20ef | |||
a677637be6 | |||
dfcce8ea9d | |||
4a4498fe89 | |||
8cc98aba8f | |||
746b567040 | |||
cc9af3e3a3 | |||
11d8e976ca | |||
b297c00c89 | |||
03f2c904ce | |||
e618732f43 | |||
c29aa523dc | |||
77a95811f2 | |||
0b6fdeec55 | |||
4c3e0fc4e9 | |||
c7367a6a4d | |||
bfbeafddf7 | |||
ce0ff0bea9 | |||
d8d5b8e9a3 | |||
11cce8363b | |||
d691b265b9 | |||
8daa8bb976 | |||
d91eb4d282 | |||
549acd645c | |||
db0dffafd9 | |||
6bd151e618 | |||
96b20aab67 | |||
ca59e51e9e | |||
d416d3d595 | |||
bd6368a8f9 | |||
ee212845a0 | |||
3b6bb15e86 | |||
a61e84dfa4 | |||
5d779bb36c | |||
b8ca49f7dc | |||
288d5a8adf | |||
88b82b0cef | |||
46a2c981e7 | |||
702c59e3e7 | |||
291d5370a3 | |||
c6688e47b3 | |||
3518148a9a | |||
cf2ba1946e | |||
90297633aa | |||
2fa116b76b | |||
859ad7df81 | |||
a417f9059e | |||
4efdbf2e84 | |||
59df8c6748 | |||
b226e9436d | |||
0a83a1252b | |||
d9a6eed921 | |||
3647ff3d54 | |||
0fb985c4f9 | |||
74df5dcca1 | |||
378d95e9a7 | |||
586b49f4a8 | |||
ac951b2afa | |||
261d2e53b7 | |||
d71ebb79aa | |||
bb510b685a | |||
876f482391 | |||
42dd6d16d7 | |||
11ae259f67 | |||
f2027befc8 | |||
9777cb81cb | |||
84ade4d683 | |||
f89aeae62b | |||
c68a9a2245 | |||
1a12447804 | |||
02600a3bc6 | |||
1faa7e5510 | |||
a0cc3c3fe7 | |||
f97134b841 | |||
8777539c2c | |||
5708a83ba6 | |||
2d54a3111c | |||
1cd1390901 | |||
3fbbf80e8c | |||
281e681bf8 | |||
9277ef34f6 | |||
9bf9753bd1 | |||
cae0ab9c5c | |||
326d72a965 | |||
765340a727 | |||
72d3575670 | |||
31352ed06a | |||
2d96139d4a | |||
92740c8dbe | |||
a9d8c070bc | |||
f93602e524 | |||
e82a99c312 | |||
6a9e02e241 | |||
54409b01f5 | |||
8ba8b6322f | |||
bc0f21175b | |||
f7471ca4cb | |||
70bc3a47f2 | |||
788abb7383 | |||
211ecd1aa1 | |||
9402ff666f | |||
8de4c4b301 | |||
abd95b949f | |||
cdc90f975e | |||
7886dc5e39 | |||
050af74ef2 | |||
ee8604b234 | |||
3475f0751f | |||
09c8bbfcc6 | |||
14a726ad75 | |||
7cb4f67f96 | |||
a290bec8f1 | |||
2554229211 | |||
54a57896b6 | |||
51ec99a42f | |||
b5d0d16d31 | |||
0039340fd5 | |||
45e6fe0033 | |||
84c48d7f5a | |||
acbc1552eb | |||
9501292fc9 | |||
a1d3e0a480 | |||
0886e9c8ef | |||
064106c6b2 | |||
06c7c1fa37 | |||
472615a31f | |||
0acabf70b7 | |||
d8a58ee286 | |||
28be54ac97 | |||
ce6febdc29 | |||
3d8deb310e | |||
248b00dafb | |||
59cdb2638f | |||
61b9044f94 | |||
d89ab0bf42 | |||
b899b8131e | |||
3bdf262068 | |||
fe6c5391a2 | |||
c9f34e4656 | |||
86ce199ac8 | |||
557a642ad3 | |||
fd4c16d090 | |||
6af0ddc3ec | |||
407c7cfadd | |||
3b399fec5c | |||
4b9fd6db81 | |||
7e92e9808e | |||
a3c9be2348 | |||
73afcfaaeb | |||
08c9ba3983 | |||
ebbaaa93b1 | |||
f9c9eefb40 | |||
b133c5f79f | |||
b48d7e3cfd | |||
c7ba6d19ad | |||
84b1bb45b9 | |||
78a2e0751b | |||
60f2c07a6a | |||
2abf09ac06 | |||
f27d178b78 | |||
b550810db5 | |||
09372b3865 | |||
ca037b6bad | |||
ac7437c89b | |||
99cb817353 | |||
3490704d64 | |||
43e233c233 | |||
468eac8e6b | |||
d838933e0e | |||
66a9271f44 | |||
25b55b3530 | |||
9fd2440ec6 | |||
d6d91e61f4 | |||
1dccce8097 | |||
5230770062 | |||
7f2df29304 | |||
732e08736f | |||
d5709c421c | |||
18c37f9934 | |||
53ae3f8ce5 | |||
b5e90528f0 | |||
22071b60e6 | |||
5283df7b98 | |||
21243ea979 | |||
1d212c5fab | |||
37239f1c25 | |||
780e1e06d4 | |||
7c227457cd | |||
5544adf345 | |||
6d3ef742b5 | |||
cba3282dce | |||
5c5e830f0f | |||
e08dbba940 | |||
752f2ebe2c | |||
a47d607a8d | |||
5356e59088 | |||
2189c4c3cb | |||
4b99da5e4e | |||
16dc9e4071 | |||
faad603d88 | |||
41c83619b5 | |||
ea83589a82 | |||
727f33ae82 | |||
1111a11577 | |||
9b163e00d9 | |||
183277250f | |||
6b96be7a57 | |||
a2001b34ea | |||
85b5c9200a | |||
8ab503840a | |||
5a2a30ada6 | |||
64959270a9 | |||
9d6404d130 | |||
ef4e0d0857 | |||
56f1bf559c | |||
b0e25627b3 | |||
e7b1eec2cc | |||
7a2d7336fb | |||
fc5023ec1c | |||
95eb0eb26d | |||
d7e658eba6 | |||
04191858de | |||
df449a475c | |||
9a95dba138 | |||
ef79aa8b80 | |||
ba7188cf66 | |||
2d4729a877 | |||
8cf1f97ac4 | |||
293f4fd0a0 | |||
0e8c752df8 | |||
a5ec166794 | |||
35a0d97170 | |||
d0ab985349 | |||
b65b9b284b | |||
18db2e3aaa | |||
46ceb2cd61 | |||
979fd10b08 | |||
5f3bdde2dc | |||
22e97063ec | |||
1ffee9933a | |||
aaa23194c5 | |||
013d1fef3b | |||
35026dfa0f | |||
2095bc6889 | |||
634bc92665 | |||
0e1b1703f6 | |||
fc2a10eb6a | |||
ab1c6c4749 | |||
06d7148408 | |||
33875cb58b | |||
07070dd2d4 | |||
c3a7d1521a | |||
fc994ab758 | |||
605a730b59 | |||
3e15798afc | |||
cf697622cb | |||
05b0a2f514 | |||
c887fdac8a | |||
4b0d9595ac | |||
5ac318d1bf | |||
eaa8f1dd16 | |||
b88fffd959 | |||
858b9dfcfa | |||
bc8b631b84 | |||
52278f6726 | |||
29fd1bfb62 | |||
998000aa3a | |||
e66f4651d0 | |||
854d09f05c | |||
2d6a9acbb6 | |||
b7f0ad6c9a | |||
43f8c22570 | |||
3c7bd2e2cb | |||
5dd9834009 | |||
dadc72c8e0 | |||
7ee4ed0020 | |||
3d557f91d8 | |||
85edd0eab6 | |||
cedb63b87a | |||
14f1d1d37f | |||
8c24234126 | |||
e0d873d41c | |||
5728432b76 | |||
0030487613 | |||
f932f5ffb4 | |||
da83065024 | |||
a6614e76ce | |||
cdd67f4779 | |||
a845609660 | |||
de3b8f059e | |||
7b4af58544 | |||
f287348550 | |||
498b4435c7 | |||
a5e67d0ee8 | |||
9e30983b22 | |||
195a87b8ab | |||
dfbb1dea68 | |||
2597edd579 | |||
85a29372f4 | |||
a9f6a5d763 | |||
73180195fe | |||
10b689ca95 | |||
3796841961 | |||
854ed851b4 | |||
5c3b797a99 | |||
8a580e2fbb | |||
3cede91aa0 | |||
0610a6a64a | |||
26d07b06db | |||
fd0b210bbb | |||
268cbe137e | |||
31bb0d3e61 | |||
248f68f6a2 | |||
3b010bd16f | |||
7e285290fe | |||
5767834f71 | |||
53ce292e82 | |||
84bd24807d | |||
8d0518c2e3 | |||
6d150ba441 | |||
c737715c66 | |||
b640b5a06b | |||
1b9363e7b5 | |||
16d2238f35 | |||
19844a9423 | |||
19fd99f713 | |||
f22f523774 | |||
8b17ed195f | |||
def7fc1959 | |||
318be9cd62 | |||
2772c8ee69 | |||
eac2927379 | |||
77a0ae6acd | |||
7879a0927b | |||
88ea3e177d | |||
bc22451524 | |||
7b8e93eec3 | |||
71be5c3c6e | |||
2b8cee6a29 | |||
5bf4640d61 | |||
0e0e81720b | |||
592a4cb9cf | |||
93f60bd073 | |||
6a6de77ae9 | |||
89f065a610 | |||
52e95ca654 | |||
eaa316a2aa | |||
bdf4e60f2f | |||
2e3c779bec | |||
461a4f1aa7 | |||
78488daa9b | |||
22f2c8f514 | |||
e442191aad | |||
795ab2d4e1 | |||
0896038dd6 | |||
67c6f9adb0 | |||
6aac44cda9 | |||
4fb2b51b7d | |||
182d844e32 | |||
6f511016bc | |||
fb885b5c21 | |||
527a7c63f6 | |||
d21dbb43e2 | |||
7ac62274f4 | |||
4ec87337c8 | |||
20f7c6d011 | |||
24dc5a03f3 | |||
3d0863ff9a | |||
97aedca844 | |||
2e7d5538d1 | |||
1bfd04680e | |||
73d1d65142 | |||
f6e55851cc | |||
0b0245d844 | |||
d278391528 | |||
aa7a5d6013 | |||
84987216cb | |||
58e9fd5514 | |||
3d41eedf48 | |||
2bc30ffcdc | |||
e67d7d37b5 | |||
98ab974515 | |||
267f8dffc1 | |||
b38a1a2507 | |||
ee87dbc532 | |||
78c7ef5b46 | |||
47ad96e2b6 | |||
95ec596cfd | |||
396477f66b | |||
01edf9e76e | |||
bde0f2c7c3 | |||
83bbac2cd1 | |||
d5dede5a61 | |||
719400068a | |||
aaf8c6adc1 | |||
dc081ae2aa | |||
3cf3097094 | |||
a5093c4aa3 | |||
e801626232 | |||
c311bb5c95 | |||
887705969f | |||
316871523d | |||
a3d193516c | |||
6709dba0e7 | |||
a8d8613f2c | |||
aae086cc65 | |||
6ec6fe96e4 | |||
2d31b57097 | |||
b1d4848b81 | |||
3678301916 | |||
459ccf7d6b | |||
db54afd180 | |||
f4fe94dfe6 | |||
28b92b0f4c | |||
c966fc6954 | |||
d0761bf60e | |||
0f41ee6a2e | |||
0aeafec019 | |||
9a0df4f577 | |||
61714836bb | |||
cff0c100ec | |||
010c49d100 | |||
ff5dbaffc0 | |||
b56d581e4b | |||
aa661aaaa7 | |||
cc3f430bab | |||
139db5b03b | |||
7d0e5c80bd | |||
f716ad9dd1 | |||
671772a20e | |||
b0173f6d68 | |||
3da5872df8 | |||
3deb6e8469 | |||
0c674e0137 | |||
7948d820c3 | |||
5aac3422aa | |||
04b3382029 | |||
e8eaa7a232 | |||
7fe6df5889 | |||
2647c85323 | |||
93140231c6 | |||
e76e56e025 | |||
b1062e701e | |||
e72aebc043 | |||
865dfa994f | |||
25be42e308 | |||
c6a0df409d | |||
a15a9af2b3 | |||
ca6909b64a | |||
5af8cfa879 | |||
f701b7d2f8 | |||
852f2a6343 | |||
7359e30c3e | |||
61accfe184 | |||
5effe64474 | |||
b1fe064484 | |||
2f44996edc | |||
18ca88a0d4 | |||
565aa4b7eb | |||
b117da5ccf | |||
8eb4892b49 | |||
82fe4c3dd7 | |||
78b0e9a77f | |||
7fa6aa7ac2 | |||
20b4cdc5f1 | |||
7c576dd4d0 | |||
f6cda522ca | |||
3d2f5b644b | |||
9ace11a0e2 | |||
6104d3b6d1 | |||
f637c7c942 | |||
afb886ea7c | |||
74129cabef | |||
be8ceb861c | |||
da0f59a3f5 | |||
000254320e | |||
2fac7206d2 | |||
e8234f2a4a | |||
a0ba0b39d8 | |||
845967cf12 | |||
92b58cbfa9 | |||
5a0651eaf0 | |||
14fcaf1d7e | |||
5a0252d8d0 | |||
9c0ffd38ce | |||
b2ae9530a4 | |||
ae1fb0fde3 | |||
35ebbbef93 | |||
83e200df43 | |||
260d3b7818 | |||
4ebffd8c63 | |||
8923e09b36 | |||
ec4195f18a | |||
062ad7ae80 | |||
aad07611c7 | |||
0dcb66f143 | |||
331c25b0e6 | |||
e50844be06 | |||
4dd7c98c1a | |||
63bad2e99a | |||
9ddeea3d06 | |||
b95f0498b6 | |||
7495a50723 | |||
1cdde5170b | |||
4248d1d9ab | |||
4f02c2b55b | |||
05d1648209 | |||
fd9d14d00c | |||
4e4f62dd20 | |||
cdc4284cb5 | |||
bedbacddde | |||
32a8dba185 | |||
d6e5051b15 | |||
780a67a40d | |||
0c7fff3029 | |||
e7db39d20a | |||
869edb8d84 | |||
dce42b866a | |||
da19b0ac31 | |||
bc090bdaa8 | |||
2a5937652e | |||
b9d4f594ce | |||
c79068c561 | |||
e7095a1849 | |||
3f78e17888 | |||
897253e1d6 | |||
cd28b26761 | |||
a3126d581b | |||
1da4a12104 | |||
8725bafbdb | |||
c24dc45e93 | |||
62b00a4bd6 | |||
f1f67fe1ba | |||
621327bf55 | |||
9dabdd32fa | |||
b479db4989 | |||
8633c5eafd | |||
440489f228 | |||
bb824a9fb7 | |||
c98dd8a584 | |||
e12d7b1458 | |||
58edc97787 | |||
ca6853e2c0 | |||
fc90106d83 | |||
89bc11eca7 | |||
5c4c397f6c | |||
da774e10e8 | |||
2f8eca71a4 | |||
90ce4bda4e | |||
4afe39dacc | |||
dd316d2589 | |||
644725478f | |||
12e8b5d6c4 | |||
f5c7261805 | |||
73ee0f905b | |||
0b46b891c2 | |||
d131b5a02f | |||
9d9a486537 | |||
610ed10011 | |||
4edab11616 | |||
4d48f9d237 | |||
6df0417667 | |||
bd9bbf67d4 | |||
8cab1307ab | |||
5bfc429450 | |||
7a7b55bebf | |||
b4eda033c6 | |||
c9672bf352 | |||
5547ff6d2b | |||
ea8cc85c61 | |||
5ecec26731 | |||
01fddd19cd | |||
e362af8271 | |||
2dba4f8fbb | |||
bdfe44399a | |||
67653bbe50 | |||
a144459e8d | |||
d725ed8cd0 | |||
3cd551098b | |||
87d7eb69af | |||
95b77cb696 | |||
2e28ad7bb9 | |||
75f78f8c7f | |||
ef59386e5c | |||
c0b57c30bd | |||
42b3866753 | |||
aff239377d | |||
3aaa1b0350 | |||
823a4ae189 | |||
40cd04f9dd | |||
6a979d31a0 | |||
56f7db9ae6 | |||
d5e2dd2e1f | |||
93e5bb867b | |||
4cd295065b | |||
5a9aacc603 | |||
082c4febdf | |||
a848a01527 | |||
3a1c15f313 | |||
e92c7cbfa0 | |||
4d09e1fd4a | |||
07765b4ad7 | |||
88f6091665 | |||
f66b8d3ea2 | |||
a0122d38f2 | |||
e4d2987c54 | |||
dec0d4ec41 | |||
b8e444eaa8 | |||
b38ea75e56 | |||
8613511928 | |||
7650d0ff23 | |||
4ec6a26d91 | |||
efa781e9ba | |||
41d0fc02c3 | |||
227425b90e | |||
5568b70d31 | |||
5c7231b7a3 | |||
310a099f14 | |||
df9fc529e2 |
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
github: Green-Sky
|
442
.github/workflows/cd.yml
vendored
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
name: ContinuousDelivery
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUILD_TYPE: RelWithDebInfo
|
||||||
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
linux-ubuntu:
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: sudo apt update && sudo apt -y install libsodium-dev cmake libasound2-dev libpulse-dev libjack-dev libsndio-dev libpipewire-0.3-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev libwayland-dev libdecor-0-dev libvpx-dev libopus-dev liburing-dev
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DTOMATO_BREAKPAD=ON -DTOMATO_TOX_AV=ON -DCMAKE_EXE_LINKER_FLAGS=-gz
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
|
||||||
|
|
||||||
|
- name: Determine tag name
|
||||||
|
id: tag
|
||||||
|
shell: bash
|
||||||
|
# taken from llama.cpp
|
||||||
|
run: |
|
||||||
|
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
|
||||||
|
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Compress artifacts
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
tar -czvf ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu22.04-x86_64.tar.gz -C ${{github.workspace}}/build/bin/ .
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu22.04-x86_64
|
||||||
|
# TODO: do propper packing
|
||||||
|
path: |
|
||||||
|
${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu22.04-x86_64.tar.gz
|
||||||
|
|
||||||
|
android:
|
||||||
|
timeout-minutes: 30
|
||||||
|
# contains sections copied from sdl repo
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# vcpkg caching action
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- vcpkg_toolkit: arm-neon-android-23
|
||||||
|
ndk_abi: armeabi-v7a
|
||||||
|
- vcpkg_toolkit: arm64-android-23
|
||||||
|
ndk_abi: arm64-v8a
|
||||||
|
- vcpkg_toolkit: x64-android-23
|
||||||
|
ndk_abi: x86_64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'Green-Sky/vcpkg_android_triplets'
|
||||||
|
path: 'vcpkg_android_triplets'
|
||||||
|
|
||||||
|
- uses: nttld/setup-ndk@v1
|
||||||
|
id: setup_ndk
|
||||||
|
with:
|
||||||
|
local-cache: false # https://github.com/nttld/setup-ndk/issues/518
|
||||||
|
ndk-version: r26d
|
||||||
|
|
||||||
|
- uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Install Dependencies (host)
|
||||||
|
run: sudo apt update && sudo apt -y install cmake pkg-config nasm
|
||||||
|
|
||||||
|
- name: Restore vcpkg cache
|
||||||
|
id: vcpkg-cache
|
||||||
|
uses: TAServers/vcpkg-cache@v3
|
||||||
|
with:
|
||||||
|
token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
|
- name: Install Dependencies (target)
|
||||||
|
env:
|
||||||
|
ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}}
|
||||||
|
VCPKG_FEATURE_FLAGS: "binarycaching"
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
|
||||||
|
run: vcpkg install --overlay-triplets=vcpkg_android_triplets --triplet ${{matrix.platform.vcpkg_toolkit}} libsodium opus libvpx libpng libjpeg-turbo freetype
|
||||||
|
|
||||||
|
# vcpkg scripts root /usr/local/share/vcpkg/scripts
|
||||||
|
- name: Configure CMake
|
||||||
|
env:
|
||||||
|
ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}}
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=${{matrix.platform.vcpkg_toolkit}} -DANDROID=1 -DANDROID_PLATFORM=23 -DANDROID_ABI=${{matrix.platform.ndk_abi}} -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=${{steps.setup_ndk.outputs.ndk-path}}/build/cmake/android.toolchain.cmake -DSDL_ANDROID_JAR=ON -DSDLIMAGE_JPG_SHARED=OFF -DSDLIMAGE_PNG_SHARED=OFF -DTOMATO_MAIN_SO=ON -DTOMATO_TOX_AV=ON -DTOMATO_ANDROID_HAVE_DEBUG_KEYSTORE=ON -DCMAKE_EXE_LINKER_FLAGS=-gz
|
||||||
|
|
||||||
|
- name: Build (tomato)
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
|
||||||
|
|
||||||
|
- name: Build (SDL3-jar) (workaround)
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t SDL3-jar
|
||||||
|
|
||||||
|
- name: setup keystore
|
||||||
|
run: |
|
||||||
|
echo "${{secrets.ANDROID_DEBUG_KEYSTORE}}" | base64 -d > tomato-debug-keystore.keystore
|
||||||
|
ls -lAh
|
||||||
|
|
||||||
|
- name: Build (apk)
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato-apk
|
||||||
|
|
||||||
|
- name: cleanup keystore
|
||||||
|
run: rm -rf tomato-debug-keystore.keystore
|
||||||
|
|
||||||
|
- name: Determine tag name
|
||||||
|
id: tag
|
||||||
|
shell: bash
|
||||||
|
# taken from llama.cpp
|
||||||
|
run: |
|
||||||
|
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
|
||||||
|
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: rename apk
|
||||||
|
id: rename_apk
|
||||||
|
shell: bash
|
||||||
|
run: mv "${{github.workspace}}/build/android/tomato.apk" "${{github.workspace}}/build/android/${{github.event.repository.name}}-${{steps.tag.outputs.name}}-Android-${{matrix.platform.ndk_abi}}.apk"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{github.event.repository.name}}-${{steps.tag.outputs.name}}-${{runner.os}}-Android-${{matrix.platform.ndk_abi}}
|
||||||
|
path: |
|
||||||
|
${{github.workspace}}/build/android/${{github.event.repository.name}}-${{steps.tag.outputs.name}}-Android-${{matrix.platform.ndk_abi}}.apk
|
||||||
|
|
||||||
|
windows:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
runs-on: windows-2022
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# vcpkg caching action
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Restore vcpkg cache
|
||||||
|
id: vcpkg-cache
|
||||||
|
uses: TAServers/vcpkg-cache@v3
|
||||||
|
with:
|
||||||
|
token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
env:
|
||||||
|
VCPKG_FEATURE_FLAGS: "binarycaching"
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
|
||||||
|
run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static
|
||||||
|
|
||||||
|
# setup vs env
|
||||||
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
with:
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
## sdl_image vendored needs nasm for dav1d
|
||||||
|
#- uses: ilammy/setup-nasm@v1
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DTOMATO_DEP_LIBWEBP_USE_SYSTEM=ON -DSDLIMAGE_VENDORED=OFF -DSDLIMAGE_DEPS_SHARED=OFF -DSDLIMAGE_JXL=OFF -DSDLIMAGE_AVIF=OFF -DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe -DTOMATO_BREAKPAD=ON -DTOMATO_TOX_AV=ON
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -t tomato
|
||||||
|
|
||||||
|
- name: Determine tag name
|
||||||
|
id: tag
|
||||||
|
shell: bash
|
||||||
|
# taken from llama.cpp
|
||||||
|
run: |
|
||||||
|
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
|
||||||
|
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Clean temporary artifacts
|
||||||
|
# msvc sometimes produces .ilk files, which are used for linking only
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
Remove-Item "${{github.workspace}}/build/bin/*.ilk"
|
||||||
|
|
||||||
|
- name: Compress artifacts
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path ${{github.workspace}}/build/bin/* -Destination ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64.zip
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{github.event.repository.name}}-${{steps.tag.outputs.name}}-${{runner.os}}-msvc-x86_64
|
||||||
|
# TODO: do propper packing
|
||||||
|
path: |
|
||||||
|
${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64.zip
|
||||||
|
|
||||||
|
|
||||||
|
windows-asan:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
runs-on: windows-2022
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# vcpkg caching action
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Restore vcpkg cache
|
||||||
|
id: vcpkg-cache
|
||||||
|
uses: TAServers/vcpkg-cache@v3
|
||||||
|
with:
|
||||||
|
token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
env:
|
||||||
|
VCPKG_FEATURE_FLAGS: "binarycaching"
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
|
||||||
|
run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static
|
||||||
|
|
||||||
|
|
||||||
|
# setup vs env
|
||||||
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
with:
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
## sdl_image vendored needs nasm for dav1d
|
||||||
|
#- uses: ilammy/setup-nasm@v1
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DTOMATO_ASAN=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DTOMATO_DEP_LIBWEBP_USE_SYSTEM=ON -DSDLIMAGE_VENDORED=OFF -DSDLIMAGE_DEPS_SHARED=OFF -DSDLIMAGE_JXL=OFF -DSDLIMAGE_AVIF=OFF -DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe -DTOMATO_TOX_AV=ON
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
|
||||||
|
|
||||||
|
- name: Determine tag name
|
||||||
|
id: tag
|
||||||
|
shell: bash
|
||||||
|
# taken from llama.cpp
|
||||||
|
run: |
|
||||||
|
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
|
||||||
|
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Clean temporary artifacts
|
||||||
|
# msvc sometimes produces .ilk files, which are used for linking only
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
Remove-Item "${{github.workspace}}/build/bin/*.ilk"
|
||||||
|
|
||||||
|
- name: Compress artifacts
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path ${{github.workspace}}/build/bin/* -Destination ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-asan-x86_64.zip
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-asan-x86_64
|
||||||
|
# TODO: do propper packing
|
||||||
|
path: |
|
||||||
|
${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-asan-x86_64.zip
|
||||||
|
|
||||||
|
dumpsyms:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
needs:
|
||||||
|
- linux-ubuntu
|
||||||
|
- android
|
||||||
|
- windows
|
||||||
|
- windows-asan
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Determine tag name
|
||||||
|
id: tag
|
||||||
|
shell: bash
|
||||||
|
# taken from llama.cpp
|
||||||
|
run: |
|
||||||
|
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
|
||||||
|
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: sudo apt update && sudo apt -y install unar
|
||||||
|
|
||||||
|
- name: Install dump_syms
|
||||||
|
run: |
|
||||||
|
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/mozilla/dump_syms/releases/download/v2.3.4/dump_syms-installer.sh | sh
|
||||||
|
|
||||||
|
- name: Download artifacts
|
||||||
|
id: download-artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ./artifacts/
|
||||||
|
|
||||||
|
- name: Dump symbols
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir ./artifacts/extract
|
||||||
|
|
||||||
|
echo $(unar -D -o ./artifacts/extract/ ./artifacts/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-Linux-ubuntu22.04-x86_64/*)
|
||||||
|
dump_syms -s tomato-dev-ubuntu22.04-x86_64-sym ./artifacts/extract/tomato
|
||||||
|
rm -rf ./artifacts/extract/*
|
||||||
|
|
||||||
|
echo $(unar -D -o ./artifacts/extract/ ./artifacts/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-Windows-msvc-x86_64/*)
|
||||||
|
dump_syms -s tomato-dev-Windows-msvc-x86_64-sym ./artifacts/extract/tomato.pdb
|
||||||
|
rm -rf ./artifacts/extract/*
|
||||||
|
|
||||||
|
- name: Compress symbol stores
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
tar -czvf ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-Linux-ubuntu22.04-x86_64-symbol_store.tar.gz -C ./tomato-dev-ubuntu22.04-x86_64-sym .
|
||||||
|
tar -czvf ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-Windows-msvc-x86_64-symbol_store.tar.gz -C ./tomato-dev-Windows-msvc-x86_64-sym .
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-symbol_stores
|
||||||
|
path: |
|
||||||
|
${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-Linux-ubuntu22.04-x86_64-symbol_store.tar.gz
|
||||||
|
${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-Windows-msvc-x86_64-symbol_store.tar.gz
|
||||||
|
|
||||||
|
release:
|
||||||
|
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) }}
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
needs:
|
||||||
|
- linux-ubuntu
|
||||||
|
- android
|
||||||
|
- windows
|
||||||
|
- windows-asan
|
||||||
|
- dumpsyms
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Determine tag name
|
||||||
|
id: tag
|
||||||
|
shell: bash
|
||||||
|
# taken from llama.cpp
|
||||||
|
run: |
|
||||||
|
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
|
||||||
|
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download artifacts
|
||||||
|
id: download-artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ./artifacts/
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tag: ${{ steps.tag.outputs.name }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
gh release create "$tag" \
|
||||||
|
--repo="$GITHUB_REPOSITORY" \
|
||||||
|
--title="${tag#v}" \
|
||||||
|
--notes="preview build of the latest commit" \
|
||||||
|
--prerelease
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tag: ${{ steps.tag.outputs.name }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ls -laR ./artifacts
|
||||||
|
gh release upload "$tag" ./artifacts/*/* \
|
||||||
|
--repo="$GITHUB_REPOSITORY"
|
||||||
|
|
187
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
name: ContinuousIntegration
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUILD_TYPE: Debug
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
linux:
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: sudo apt update && sudo apt -y install libsodium-dev cmake libx11-dev libxext-dev libxrandr-dev
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2
|
||||||
|
with:
|
||||||
|
key: ${{github.event.repository.name}}-${{github.job}}
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
|
||||||
|
|
||||||
|
android:
|
||||||
|
timeout-minutes: 30
|
||||||
|
# contains sections copied from sdl repo
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# vcpkg caching action
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- vcpkg_toolkit: arm-neon-android-23
|
||||||
|
ndk_abi: armeabi-v7a
|
||||||
|
- vcpkg_toolkit: arm64-android-23
|
||||||
|
ndk_abi: arm64-v8a
|
||||||
|
- vcpkg_toolkit: x64-android-23
|
||||||
|
ndk_abi: x86_64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'Green-Sky/vcpkg_android_triplets'
|
||||||
|
path: 'vcpkg_android_triplets'
|
||||||
|
|
||||||
|
- uses: nttld/setup-ndk@v1
|
||||||
|
id: setup_ndk
|
||||||
|
with:
|
||||||
|
local-cache: false # https://github.com/nttld/setup-ndk/issues/518
|
||||||
|
ndk-version: r26d
|
||||||
|
|
||||||
|
- uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Install Dependencies (host)
|
||||||
|
run: sudo apt update && sudo apt -y install cmake pkg-config nasm
|
||||||
|
|
||||||
|
- name: Restore vcpkg cache
|
||||||
|
id: vcpkg-cache
|
||||||
|
uses: TAServers/vcpkg-cache@v3
|
||||||
|
with:
|
||||||
|
token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
|
- name: Install Dependencies (target)
|
||||||
|
env:
|
||||||
|
ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}}
|
||||||
|
VCPKG_FEATURE_FLAGS: "binarycaching"
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
|
||||||
|
run: vcpkg install --overlay-triplets=vcpkg_android_triplets --triplet ${{matrix.platform.vcpkg_toolkit}} libsodium opus libvpx libpng libjpeg-turbo freetype
|
||||||
|
|
||||||
|
# vcpkg scripts root /usr/local/share/vcpkg/scripts
|
||||||
|
- name: Configure CMake
|
||||||
|
env:
|
||||||
|
ANDROID_NDK_HOME: ${{steps.setup_ndk.outputs.ndk-path}}
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=${{matrix.platform.vcpkg_toolkit}} -DANDROID=1 -DANDROID_PLATFORM=23 -DANDROID_ABI=${{matrix.platform.ndk_abi}} -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=${{steps.setup_ndk.outputs.ndk-path}}/build/cmake/android.toolchain.cmake -DSDL_ANDROID_JAR=ON -DSDLIMAGE_JPG_SHARED=OFF -DSDLIMAGE_PNG_SHARED=OFF -DTOMATO_MAIN_SO=ON
|
||||||
|
|
||||||
|
- name: Build (tomato)
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
|
||||||
|
|
||||||
|
- name: Build (SDL3-jar) (workaround)
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t SDL3-jar
|
||||||
|
|
||||||
|
- name: Build (apk)
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato-apk
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.event.repository.name }}-${{matrix.platform.vcpkg_toolkit}}
|
||||||
|
# TODO: do propper packing
|
||||||
|
path: |
|
||||||
|
${{github.workspace}}/build/android/tomato.apk
|
||||||
|
|
||||||
|
macos:
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: brew install libsodium
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2
|
||||||
|
with:
|
||||||
|
key: ${{github.event.repository.name}}-${{github.job}}
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
|
||||||
|
|
||||||
|
windows:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# vcpkg caching action
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Restore vcpkg cache
|
||||||
|
id: vcpkg-cache
|
||||||
|
uses: TAServers/vcpkg-cache@v3
|
||||||
|
with:
|
||||||
|
token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
env:
|
||||||
|
VCPKG_FEATURE_FLAGS: "binarycaching"
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;files,${{steps.vcpkg-cache.outputs.path}},readwrite"
|
||||||
|
run: vcpkg install pkgconf:x64-windows libsodium:x64-windows-static pthreads:x64-windows-static opus:x64-windows-static libvpx:x64-windows-static zstd:x64-windows-static libwebp:x64-windows-static libpng:x64-windows-static libjpeg-turbo:x64-windows-static freetype:x64-windows-static
|
||||||
|
|
||||||
|
# setup vs env
|
||||||
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
with:
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
## sdl_image vendored needs nasm for dav1d
|
||||||
|
#- uses: ilammy/setup-nasm@v1
|
||||||
|
|
||||||
|
#- name: ccache
|
||||||
|
# uses: hendrikmuhs/ccache-action@v1.2
|
||||||
|
# with:
|
||||||
|
# variant: sccache
|
||||||
|
# key: ${{github.event.repository.name}}-${{github.job}}
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DTOMATO_DEP_LIBWEBP_USE_SYSTEM=ON -DSDLIMAGE_VENDORED=OFF -DSDLIMAGE_DEPS_SHARED=OFF -DSDLIMAGE_JXL=OFF -DSDLIMAGE_AVIF=OFF -DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4 -t tomato
|
||||||
|
|
37
.gitignore
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
.vs/
|
||||||
|
*.o
|
||||||
|
*.swp
|
||||||
|
~*
|
||||||
|
*~
|
||||||
|
.idea/
|
||||||
|
cmake-build-debug/
|
||||||
|
cmake-build-debugandtest/
|
||||||
|
cmake-build-release/
|
||||||
|
*.stackdump
|
||||||
|
*.coredump
|
||||||
|
compile_commands.json
|
||||||
|
/build*
|
||||||
|
/result*
|
||||||
|
.clangd
|
||||||
|
.cache
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
CMakeLists.txt.user*
|
||||||
|
CMakeCache.txt
|
||||||
|
|
||||||
|
*.tox
|
||||||
|
imgui.ini
|
||||||
|
|
||||||
|
*.wad
|
||||||
|
|
||||||
|
heaptrack/
|
||||||
|
crashes/
|
||||||
|
|
||||||
|
test_message_store/
|
||||||
|
test2_message_store/
|
||||||
|
tmp_avatar_dir/
|
||||||
|
tmp_save_dir/
|
||||||
|
tmp_send_files/
|
10
.gitmodules
vendored
@ -1,3 +1,7 @@
|
|||||||
|
[submodule "external/toxcore/c-toxcore/third_party/cmp"]
|
||||||
|
path = external/toxcore/c-toxcore/third_party/cmp
|
||||||
|
url = https://github.com/camgunz/cmp.git
|
||||||
|
shallow = true
|
||||||
[submodule "external/solanaceae_toxcore"]
|
[submodule "external/solanaceae_toxcore"]
|
||||||
path = external/solanaceae_toxcore
|
path = external/solanaceae_toxcore
|
||||||
url = https://github.com/Green-Sky/solanaceae_toxcore.git
|
url = https://github.com/Green-Sky/solanaceae_toxcore.git
|
||||||
@ -16,3 +20,9 @@
|
|||||||
[submodule "external/solanaceae_plugin"]
|
[submodule "external/solanaceae_plugin"]
|
||||||
path = external/solanaceae_plugin
|
path = external/solanaceae_plugin
|
||||||
url = https://github.com/Green-Sky/solanaceae_plugin.git
|
url = https://github.com/Green-Sky/solanaceae_plugin.git
|
||||||
|
[submodule "external/solanaceae_object_store"]
|
||||||
|
path = external/solanaceae_object_store
|
||||||
|
url = https://github.com/Green-Sky/solanaceae_object_store.git
|
||||||
|
[submodule "external/solanaceae_message_serializer"]
|
||||||
|
path = external/solanaceae_message_serializer
|
||||||
|
url = https://github.com/Green-Sky/solanaceae_message_serializer.git
|
||||||
|
145
CMakeLists.txt
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR)
|
||||||
|
|
||||||
|
# cmake setup begin
|
||||||
|
project(tomato
|
||||||
|
VERSION 0.3.1
|
||||||
|
HOMEPAGE_URL https://github.com/Green-Sky/tomato
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
# defaulting to debug mode, if not specified
|
||||||
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE "Debug")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# setup my vim ycm :D
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
# more paths
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
|
||||||
|
option(TOMATO_MAIN_SO "Build tomato as a shared object (for eg android apps)" ANDROID)
|
||||||
|
option(TOMATO_ASAN "Build tomato with asan (gcc/clang/msvc)" OFF)
|
||||||
|
option(TOMATO_BREAKPAD "Build tomato with breakpad crash dumping" OFF)
|
||||||
|
option(TOMATO_TOX_AV "Build tomato with ToxAV" OFF)
|
||||||
|
|
||||||
|
|
||||||
|
if (TOMATO_ASAN)
|
||||||
|
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||||
|
if (NOT WIN32) # exclude mingw
|
||||||
|
add_compile_options(-fno-omit-frame-pointer)
|
||||||
|
add_compile_options(-fsanitize=address,undefined)
|
||||||
|
#add_compile_options(-fsanitize=address,undefined,pointer-compare,pointer-subtract)
|
||||||
|
#add_compile_options(-fhardened)
|
||||||
|
#add_compile_options(-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -ftrivial-auto-var-init=zero -fPIE -pie -Wl,-z,relro,-z,now -fstack-protector-strong -fstack-clash-protection -fcf-protection=full)
|
||||||
|
|
||||||
|
add_link_options(-fno-omit-frame-pointer)
|
||||||
|
add_link_options(-fsanitize=address,undefined)
|
||||||
|
#add_link_options(-fsanitize=address,undefined,pointer-compare,pointer-subtract)
|
||||||
|
#add_link_options(-fhardened)
|
||||||
|
#add_link_options(-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -ftrivial-auto-var-init=zero -fPIE -pie -Wl,-z,relro,-z,now -fstack-protector-strong -fstack-clash-protection -fcf-protection=full)
|
||||||
|
|
||||||
|
link_libraries(-static-libasan) # make it "work" on nix
|
||||||
|
message("II enabled ASAN")
|
||||||
|
else()
|
||||||
|
message("!! can not enable ASAN on this platform (gcc/clang + win)")
|
||||||
|
endif()
|
||||||
|
elseif (MSVC)
|
||||||
|
add_compile_options("/fsanitize=address")
|
||||||
|
message("II enabled ASAN")
|
||||||
|
else()
|
||||||
|
message("!! can not enable ASAN on this platform")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message("II TOMATO_BREAKPAD: ${TOMATO_BREAKPAD}")
|
||||||
|
if (TOMATO_BREAKPAD)
|
||||||
|
if (LINUX) # TODO: test if android
|
||||||
|
# HACK: workaround an ugly cmake bug,
|
||||||
|
# where subdirs can now propergate enable_language upwards
|
||||||
|
enable_language(ASM)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message("II TOMATO_TOX_AV: ${TOMATO_TOX_AV}")
|
||||||
|
|
||||||
|
# uggly, but it needs to be defined for all of tomato.
|
||||||
|
# but this also means that we can not compile tomato in the same cmake as plugins
|
||||||
|
add_compile_definitions(ENTT_API_EXPORT)
|
||||||
|
|
||||||
|
# external libs
|
||||||
|
add_subdirectory(./external EXCLUDE_FROM_ALL) # before increasing warn levels, sad :(
|
||||||
|
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# bump up warning levels appropriately for clang, gcc & msvc
|
||||||
|
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||||
|
add_compile_options(
|
||||||
|
-Wall -Wextra # Reasonable and standard
|
||||||
|
-Wpedantic # Warn if non-standard C++ is used
|
||||||
|
-Wunused # Warn on anything being unused
|
||||||
|
#-Wconversion # Warn on type conversions that may lose data
|
||||||
|
#-Wsign-conversion # Warn on sign conversions
|
||||||
|
-Wshadow # Warn if a variable declaration shadows one from a parent context
|
||||||
|
)
|
||||||
|
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||||
|
if (MSVC)
|
||||||
|
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO: move to cmake include (maybe function)
|
||||||
|
set(TOMATO_GIT_DEPTH 0)
|
||||||
|
set(TOMATO_GIT_COMMIT "UNK")
|
||||||
|
|
||||||
|
find_package(Git QUIET)
|
||||||
|
if(NOT Git_FOUND)
|
||||||
|
find_program(GIT_EXECUTABLE NAMES git git.exe)
|
||||||
|
if(GIT_EXECUTABLE)
|
||||||
|
set(Git_FOUND TRUE)
|
||||||
|
message(STATUS "Found Git: ${GIT_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(Git_FOUND)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_HEAD
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
RESULT_VARIABLE RES
|
||||||
|
)
|
||||||
|
if (RES EQUAL 0)
|
||||||
|
set(TOMATO_GIT_COMMIT ${GIT_HEAD})
|
||||||
|
endif()
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_DEPTH
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
RESULT_VARIABLE RES
|
||||||
|
)
|
||||||
|
if (RES EQUAL 0)
|
||||||
|
set(TOMATO_GIT_DEPTH ${GIT_DEPTH})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "tomato version: ")
|
||||||
|
message(STATUS "${tomato_VERSION_MAJOR}.${tomato_VERSION_MINOR}.${tomato_VERSION_PATCH}-${TOMATO_GIT_DEPTH}+git.${TOMATO_GIT_COMMIT}")
|
||||||
|
|
||||||
|
# cmake setup end
|
||||||
|
|
||||||
|
add_subdirectory(./src)
|
||||||
|
|
||||||
|
# TODO: move to src
|
||||||
|
if (ANDROID AND TARGET SDL3::Jar)
|
||||||
|
message("II building for ANDROID!!!")
|
||||||
|
|
||||||
|
add_subdirectory(android)
|
||||||
|
endif()
|
||||||
|
|
43
README.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Tomato
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Highly experimental solanaceae client with Tox built-in
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
### Required system packages:
|
||||||
|
- libsodium
|
||||||
|
- freetype (optional)
|
||||||
|
- if `TOMATO_TOX_AV=ON`
|
||||||
|
- libopus
|
||||||
|
- libvpx
|
||||||
|
|
||||||
|
### Optional system packages (fetched otherwise):
|
||||||
|
- zstd
|
||||||
|
- with `TOMATO_DEP_XXX_USE_SYSTEM=ON`
|
||||||
|
- sdl3
|
||||||
|
- sdl3_image
|
||||||
|
- libwebp
|
||||||
|
- plutosvg
|
||||||
|
|
||||||
|
### submodule/subtree/fetched:
|
||||||
|
- toxcore
|
||||||
|
- solanaceae_*
|
||||||
|
- qoi
|
||||||
|
- entt
|
||||||
|
- nlohmann json
|
||||||
|
- imgui
|
||||||
|
- implot
|
||||||
|
- stb (for image, will be removed) (might keep for image resize)
|
||||||
|
- breakpad (if enabled)
|
||||||
|
|
||||||
|
|
||||||
|
### Components required during build on the host system:
|
||||||
|
- c/c++ compiler
|
||||||
|
- cmake
|
||||||
|
- make/ninja
|
||||||
|
- pkg-config (pkgconf on windows)
|
||||||
|
|
112
android/CMakeLists.txt
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR)
|
||||||
|
|
||||||
|
project(tomato_android)
|
||||||
|
|
||||||
|
# here be dragons
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${SDL3_SOURCE_DIR}/cmake/android")
|
||||||
|
|
||||||
|
find_package(SdlAndroid MODULE)
|
||||||
|
find_package(Java)
|
||||||
|
find_package(SdlAndroidPlatform MODULE)
|
||||||
|
# the existence of SDL3::Jar usually implies platform
|
||||||
|
if(SdlAndroid_FOUND)
|
||||||
|
include(TomatoAndroidFunctions)
|
||||||
|
include(SdlAndroidFunctions)
|
||||||
|
|
||||||
|
# TODO: make more generic
|
||||||
|
option(TOMATO_ANDROID_HAVE_DEBUG_KEYSTORE "we provide tomato-debug-keystore.keystore" OFF)
|
||||||
|
if (${TOMATO_ANDROID_HAVE_DEBUG_KEYSTORE})
|
||||||
|
tomato_load_android_keystore(tomato-debug-keystore)
|
||||||
|
else()
|
||||||
|
# fallback to generating a new keystore
|
||||||
|
sdl_create_android_debug_keystore(tomato-debug-keystore)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
sdl_android_compile_resources(tomato-resources RESFOLDER app/res)
|
||||||
|
|
||||||
|
|
||||||
|
set(ANDROID_MANIFEST_PACKAGE "org.libsdl.app.tomato")
|
||||||
|
set(generated_manifest_path "${CMAKE_CURRENT_BINARY_DIR}/app/AndroidManifest.xml")
|
||||||
|
configure_file("app/AndroidManifest.xml.in" "${generated_manifest_path}" @ONLY)
|
||||||
|
string(REPLACE "." "/" JAVA_PACKAGE_DIR "${ANDROID_MANIFEST_PACKAGE}")
|
||||||
|
#set(GENERATED_SRC_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/android/${TEST}-src")
|
||||||
|
#set(GENERATED_RES_FOLDER "${GENERATED_SRC_FOLDER}/res")
|
||||||
|
#set(JAVA_PACKAGE_DIR "${GENERATED_SRC_FOLDER}/${JAVA_PACKAGE_DIR}")
|
||||||
|
set(JAVA_PACKAGE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app/java/${JAVA_PACKAGE_DIR}")
|
||||||
|
|
||||||
|
sdl_android_link_resources(tomato-apk-linked
|
||||||
|
MANIFEST ${generated_manifest_path}
|
||||||
|
PACKAGE ${ANDROID_MANIFEST_PACKAGE}
|
||||||
|
RES_TARGETS tomato-resources
|
||||||
|
TARGET_SDK_VERSION 31
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding;utf-8")
|
||||||
|
set(classes_path "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tomato-java.dir/classes")
|
||||||
|
# Some CMake versions have a slow `cmake -E make_directory` implementation
|
||||||
|
if(NOT IS_DIRECTORY "${classes_path}")
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${classes_path}")
|
||||||
|
endif()
|
||||||
|
set(OUT_JAR "${CMAKE_CURRENT_BINARY_DIR}/tomato.jar")
|
||||||
|
# TODO: convert to cmake's add_jar
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${OUT_JAR}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E rm -rf "${classes_path}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${classes_path}"
|
||||||
|
COMMAND ${Java_JAVAC_EXECUTABLE}
|
||||||
|
-source 1.8 -target 1.8
|
||||||
|
-bootclasspath "$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>"
|
||||||
|
"${JAVA_PACKAGE_DIR}/TomatoActivity.java"
|
||||||
|
$<TARGET_PROPERTY:tomato-apk-linked,JAVA_R>
|
||||||
|
-cp "$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>:${SDL_ANDROID_PLATFORM_ANDROID_JAR}"
|
||||||
|
-d "${classes_path}"
|
||||||
|
COMMAND ${Java_JAR_EXECUTABLE} cf "${OUT_JAR}" -C "${classes_path}" .
|
||||||
|
DEPENDS $<TARGET_PROPERTY:tomato-apk-linked,OUTPUTS> "$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>"
|
||||||
|
)
|
||||||
|
add_custom_target(tomato-jar DEPENDS "${OUT_JAR}")
|
||||||
|
add_dependencies(tomato-jar SDL3::Jar) # HACK: somehow their jar is not registered as an output
|
||||||
|
set_property(TARGET tomato-jar PROPERTY OUTPUT "${OUT_JAR}")
|
||||||
|
|
||||||
|
set(dexworkdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tomato-dex.dir")
|
||||||
|
# Some CMake versions have a slow `cmake -E make_directory` implementation
|
||||||
|
if(NOT IS_DIRECTORY "${dexworkdir}")
|
||||||
|
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${dexworkdir}")
|
||||||
|
endif()
|
||||||
|
set(classes_dex_base_name "classes.dex")
|
||||||
|
set(classes_dex "${dexworkdir}/${classes_dex_base_name}")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${classes_dex}"
|
||||||
|
COMMAND SdlAndroid::d8
|
||||||
|
$<TARGET_PROPERTY:tomato-jar,OUTPUT>
|
||||||
|
$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>
|
||||||
|
--lib "${SDL_ANDROID_PLATFORM_ANDROID_JAR}"
|
||||||
|
--output "${dexworkdir}"
|
||||||
|
DEPENDS $<TARGET_PROPERTY:tomato-jar,OUTPUT> $<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>
|
||||||
|
)
|
||||||
|
add_custom_target(tomato-dex DEPENDS "${classes_dex}")
|
||||||
|
set_property(TARGET tomato-dex PROPERTY OUTPUT "${classes_dex}")
|
||||||
|
set_property(TARGET tomato-dex PROPERTY OUTPUT_BASE_NAME "${classes_dex_base_name}")
|
||||||
|
|
||||||
|
# file(GLOB RESOURCE_FILES *.bmp *.wav *.hex moose.dat utf8.txt)
|
||||||
|
|
||||||
|
sdl_add_to_apk_unaligned(tomato-unaligned-apk
|
||||||
|
APK_IN tomato-apk-linked
|
||||||
|
OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/intermediates"
|
||||||
|
#ASSETS ${RESOURCE_FILES}
|
||||||
|
#NATIVE_LIBS SDL3::SDL3-shared tomato
|
||||||
|
NATIVE_LIBS tomato
|
||||||
|
DEX tomato-dex
|
||||||
|
)
|
||||||
|
|
||||||
|
sdl_apk_align(tomato-aligned-apk tomato-unaligned-apk
|
||||||
|
OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/intermediates"
|
||||||
|
)
|
||||||
|
sdl_apk_sign(tomato-apk tomato-aligned-apk
|
||||||
|
KEYSTORE tomato-debug-keystore
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message("EE SdlAndroid module not found")
|
||||||
|
endif()
|
||||||
|
|
102
android/app/AndroidManifest.xml.in
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Replace com.test.game with the identifier of your game below, e.g.
|
||||||
|
com.gamemaker.game
|
||||||
|
-->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.libsdl.app.tomato"
|
||||||
|
android:versionCode="@TOMATO_GIT_DEPTH@"
|
||||||
|
android:versionName="@tomato_VERSION_MAJOR@.@tomato_VERSION_MINOR@.@tomato_VERSION_PATCH@-@TOMATO_GIT_DEPTH@+git.@TOMATO_GIT_COMMIT@"
|
||||||
|
android:installLocation="auto">
|
||||||
|
|
||||||
|
<!-- OpenGL ES 2.0 -->
|
||||||
|
<uses-feature android:glEsVersion="0x00020000" />
|
||||||
|
|
||||||
|
<!-- Touchscreen support -->
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<!-- Game controller support -->
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.bluetooth"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.gamepad"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.usb.host"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<!-- External mouse input events -->
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.type.pc"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<!-- Audio recording support -->
|
||||||
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.microphone"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<!-- Camera support -->
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.camera"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<!-- Allow downloading to the external storage on Android 5.1 and older -->
|
||||||
|
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="22" /> -->
|
||||||
|
|
||||||
|
<!-- Allow access to Bluetooth devices -->
|
||||||
|
<!-- Currently this is just for Steam Controller support and requires setting SDL_HINT_JOYSTICK_HIDAPI_STEAM -->
|
||||||
|
<!-- <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> -->
|
||||||
|
<!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> -->
|
||||||
|
|
||||||
|
<!-- Allow access to the vibrator -->
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
|
<!-- Create a Java class extending SDLActivity and place it in a
|
||||||
|
directory under app/src/main/java matching the package, e.g. app/src/main/java/com/gamemaker/game/MyGame.java
|
||||||
|
|
||||||
|
then replace "SDLActivity" with the name of your class (e.g. "MyGame")
|
||||||
|
in the XML below.
|
||||||
|
|
||||||
|
An example Java class can be found in README-android.md
|
||||||
|
-->
|
||||||
|
<application android:label="@string/app_name"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:appCategory="social"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
android:hardwareAccelerated="true" >
|
||||||
|
|
||||||
|
<!-- setting sdl hints. uses the string value -->
|
||||||
|
<meta-data android:name="SDL_ENV.SDL_ANDROID_BLOCK_ON_PAUSE" android:value="0"/>
|
||||||
|
|
||||||
|
<activity android:name="TomatoActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:alwaysRetainTaskState="true"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
|
||||||
|
android:preferMinimalPostProcessing="true"
|
||||||
|
android:exported="true"
|
||||||
|
>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
<!-- Let Android know that we can handle some USB devices and should receive this event -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
|
</intent-filter>
|
||||||
|
<!-- Drop file event -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="*/*" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
18
android/app/java/org/libsdl/app/tomato/TomatoActivity.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package org.libsdl.app.tomato;
|
||||||
|
|
||||||
|
import org.libsdl.app.SDLActivity;
|
||||||
|
|
||||||
|
public class TomatoActivity extends SDLActivity {
|
||||||
|
protected String[] getLibraries() {
|
||||||
|
return new String[] {
|
||||||
|
// "SDL3", // we link statically
|
||||||
|
// "SDL3_image",
|
||||||
|
// "SDL3_mixer",
|
||||||
|
// "SDL3_net",
|
||||||
|
// "SDL3_ttf",
|
||||||
|
// "main"
|
||||||
|
"tomato"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
BIN
android/app/play_store_512.png
Normal file
After Width: | Height: | Size: 94 KiB |
6
android/app/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
|
||||||
|
</adaptive-icon>
|
BIN
android/app/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
android/app/res/mipmap-hdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
android/app/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
android/app/res/mipmap-hdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
android/app/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
android/app/res/mipmap-mdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
android/app/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
android/app/res/mipmap-mdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
android/app/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
android/app/res/mipmap-xhdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
android/app/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
android/app/res/mipmap-xhdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
android/app/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
android/app/res/mipmap-xxhdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
android/app/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
android/app/res/mipmap-xxhdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
android/app/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
android/app/res/mipmap-xxxhdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
android/app/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
android/app/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 15 KiB |
6
android/app/res/values/colors.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#3F51B5</color>
|
||||||
|
<color name="colorPrimaryDark">#303F9F</color>
|
||||||
|
<color name="colorAccent">#FF4081</color>
|
||||||
|
</resources>
|
3
android/app/res/values/strings.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Tomato</string>
|
||||||
|
</resources>
|
10
android/app/res/values/styles.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<!-- <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar"> -->
|
||||||
|
<!--<style name="AppTheme" parent="android:Theme.AppCompat">-->
|
||||||
|
<style name="AppTheme" parent="android:Theme.NoTitleBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
9
android/cmake/TomatoAndroidFunctions.cmake
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# based on code from SDLAndroidFunctions.cmake
|
||||||
|
|
||||||
|
# target name is name of file without .keystore
|
||||||
|
function(tomato_load_android_keystore TARGET)
|
||||||
|
set(output "${CMAKE_SOURCE_DIR}/${TARGET}.keystore")
|
||||||
|
add_custom_target(${TARGET} DEPENDS "${output}")
|
||||||
|
set_property(TARGET ${TARGET} PROPERTY OUTPUT "${output}")
|
||||||
|
endfunction()
|
||||||
|
|
22
external/CMakeLists.txt
vendored
@ -1,10 +1,14 @@
|
|||||||
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR)
|
||||||
|
|
||||||
add_subdirectory(./entt)
|
add_subdirectory(./entt)
|
||||||
|
|
||||||
|
add_subdirectory(./json)
|
||||||
|
|
||||||
add_subdirectory(./solanaceae_util)
|
add_subdirectory(./solanaceae_util)
|
||||||
|
add_subdirectory(./solanaceae_object_store)
|
||||||
add_subdirectory(./solanaceae_contact)
|
add_subdirectory(./solanaceae_contact)
|
||||||
add_subdirectory(./solanaceae_message3)
|
add_subdirectory(./solanaceae_message3)
|
||||||
|
add_subdirectory(./solanaceae_message_serializer)
|
||||||
|
|
||||||
add_subdirectory(./solanaceae_plugin)
|
add_subdirectory(./solanaceae_plugin)
|
||||||
|
|
||||||
@ -12,3 +16,19 @@ add_subdirectory(./toxcore)
|
|||||||
add_subdirectory(./solanaceae_toxcore)
|
add_subdirectory(./solanaceae_toxcore)
|
||||||
add_subdirectory(./solanaceae_tox)
|
add_subdirectory(./solanaceae_tox)
|
||||||
|
|
||||||
|
add_subdirectory(./sdl)
|
||||||
|
add_subdirectory(./freetype)
|
||||||
|
add_subdirectory(./plutosvg)
|
||||||
|
add_subdirectory(./imgui)
|
||||||
|
add_subdirectory(./implot)
|
||||||
|
|
||||||
|
add_subdirectory(./stb)
|
||||||
|
add_subdirectory(./libwebp)
|
||||||
|
add_subdirectory(./qoi)
|
||||||
|
add_subdirectory(./libqoirdo)
|
||||||
|
add_subdirectory(./sdl_image)
|
||||||
|
|
||||||
|
if (TOMATO_BREAKPAD)
|
||||||
|
add_subdirectory(./breakpad)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
139
external/breakpad/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16...3.24 FATAL_ERROR)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
if (NOT TARGET breakpad_client)
|
||||||
|
|
||||||
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Android")
|
||||||
|
if (NOT TARGET lss)
|
||||||
|
FetchContent_Declare(lss
|
||||||
|
GIT_REPOSITORY https://chromium.googlesource.com/linux-syscall-support/
|
||||||
|
GIT_TAG 9719c1e1e676814c456b55f5f070eabad6709d31
|
||||||
|
|
||||||
|
FIND_PACKAGE_ARGS # for the future
|
||||||
|
)
|
||||||
|
FetchContent_GetProperties(lss)
|
||||||
|
if(NOT lss_POPULATED)
|
||||||
|
FetchContent_Populate(lss)
|
||||||
|
|
||||||
|
# HACK: breakpad expects this at a specific path
|
||||||
|
configure_file(
|
||||||
|
${lss_SOURCE_DIR}/linux_syscall_support.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/third_party/lss/linux_syscall_support.h
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(lss INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/third_party/lss/linux_syscall_support.h)
|
||||||
|
target_include_directories(lss INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
FetchContent_Declare(breakpad
|
||||||
|
GIT_REPOSITORY https://chromium.googlesource.com/breakpad/breakpad
|
||||||
|
GIT_TAG v2023.06.01
|
||||||
|
|
||||||
|
FIND_PACKAGE_ARGS # for the future
|
||||||
|
)
|
||||||
|
FetchContent_GetProperties(breakpad)
|
||||||
|
if(NOT breakpad_POPULATED)
|
||||||
|
FetchContent_Populate(breakpad)
|
||||||
|
|
||||||
|
add_library(breakpad_common STATIC
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/convert_UTF.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/convert_UTF.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/md5.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/md5.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/string_conversion.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/string_conversion.cc
|
||||||
|
)
|
||||||
|
target_include_directories(breakpad_common PUBLIC "${breakpad_SOURCE_DIR}/src")
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
target_sources(breakpad_common PUBLIC
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/windows/guid_string.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/windows/guid_string.cc
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(breakpad_client STATIC)
|
||||||
|
target_sources(breakpad_client
|
||||||
|
PUBLIC
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/windows/handler/exception_handler.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/windows/common/ipc_protocol.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/windows/crash_generation/crash_generation_client.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/windows/crash_generation/minidump_generator.h
|
||||||
|
PRIVATE
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/windows/handler/exception_handler.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/windows/crash_generation/crash_generation_client.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/windows/crash_generation/minidump_generator.cc
|
||||||
|
)
|
||||||
|
target_compile_definitions(breakpad_client PRIVATE UNICODE)
|
||||||
|
#elseif() # TODO: mac, ios and any other platform
|
||||||
|
else() # assume linux
|
||||||
|
enable_language(ASM) # mostly to document, needs to be set in parent
|
||||||
|
target_sources(breakpad_common PUBLIC
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/elf_core_dump.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/elfutils.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/elfutils.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/file_id.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/file_id.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/guid_creator.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/guid_creator.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/linux_libc_support.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/memory_mapped_file.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/safe_readlink.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/breakpad_getcontext.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/common/linux/breakpad_getcontext.S
|
||||||
|
)
|
||||||
|
#set_property(SOURCE ${breakpad_SOURCE_DIR}/src/common/linux/breakpad_getcontext.S APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp")
|
||||||
|
|
||||||
|
add_library(breakpad_client STATIC)
|
||||||
|
target_sources(breakpad_client
|
||||||
|
PUBLIC
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/handler/exception_handler.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/handler/minidump_descriptor.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/crash_generation/crash_generation_client.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/log/log.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/microdump_writer/microdump_writer.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/minidump_writer.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/pe_file.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/pe_structs.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/proc_cpuinfo_reader.h
|
||||||
|
PRIVATE
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/handler/exception_handler.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/handler/minidump_descriptor.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/crash_generation/crash_generation_client.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/crash_generation/crash_generation_server.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/log/log.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/microdump_writer/microdump_writer.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/dump_writer_common/thread_info.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/dump_writer_common/ucontext_reader.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/minidump_writer.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/linux_core_dumper.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/linux_dumper.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/pe_file.cc
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (TARGET lss)
|
||||||
|
target_link_libraries(breakpad_common PUBLIC lss)
|
||||||
|
target_link_libraries(breakpad_client PUBLIC lss)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (TARGET breakpad_client)
|
||||||
|
if (NOT WIN32)
|
||||||
|
target_sources(breakpad_client PUBLIC
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/minidump_file_writer-inl.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/minidump_file_writer.h
|
||||||
|
${breakpad_SOURCE_DIR}/src/client/minidump_file_writer.cc
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(breakpad_client PUBLIC breakpad_common)
|
||||||
|
target_include_directories(breakpad_client PUBLIC "${breakpad_SOURCE_DIR}/src")
|
||||||
|
target_compile_features(breakpad_client PUBLIC cxx_std_11)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
#FetchContent_MakeAvailable(breakpad)
|
||||||
|
endif()
|
||||||
|
|
41
external/entt/entt/.clang-format
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
BasedOnStyle: llvm
|
||||||
|
---
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
ColumnLimit: 0
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '<[[:alnum:]_]+>'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '<(gtest|gmock)/'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '<[[:alnum:]_./]+>'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '<entt/'
|
||||||
|
Priority: 4
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 5
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentWidth: 4
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
Language: Cpp
|
||||||
|
PointerAlignment: Right
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceAroundPointerQualifiers: After
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCtorInitializerColon: false
|
||||||
|
SpaceBeforeInheritanceColon: false
|
||||||
|
SpaceBeforeParens: Never
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: false
|
||||||
|
Standard: Latest
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
4
external/entt/entt/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: skypjack
|
||||||
|
custom: https://www.paypal.me/skypjack
|
61
external/entt/entt/.github/workflows/analyzer.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
name: analyzer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- wip
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
iwyu:
|
||||||
|
timeout-minutes: 30
|
||||||
|
|
||||||
|
env:
|
||||||
|
IWYU: 0.19
|
||||||
|
LLVM: 15
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install llvm/clang
|
||||||
|
# see: https://apt.llvm.org/
|
||||||
|
run: |
|
||||||
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
|
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM main"
|
||||||
|
sudo apt update
|
||||||
|
sudo apt remove -y "llvm*"
|
||||||
|
sudo apt remove -y "libclang-dev*"
|
||||||
|
sudo apt remove -y "clang*"
|
||||||
|
sudo apt install -y llvm-$LLVM-dev
|
||||||
|
sudo apt install -y libclang-$LLVM-dev
|
||||||
|
sudo apt install -y clang-$LLVM
|
||||||
|
- name: Compile iwyu
|
||||||
|
# see: https://github.com/include-what-you-use/include-what-you-use
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/include-what-you-use/include-what-you-use.git --branch $IWYU --depth 1
|
||||||
|
mkdir include-what-you-use/build
|
||||||
|
cd include-what-you-use/build
|
||||||
|
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=./ \
|
||||||
|
..
|
||||||
|
make -j4
|
||||||
|
bin/include-what-you-use --version
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
export PATH=$PATH:${GITHUB_WORKSPACE}/build/include-what-you-use/build/bin
|
||||||
|
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||||
|
-DENTT_BUILD_TESTING=ON \
|
||||||
|
-DENTT_BUILD_BENCHMARK=ON \
|
||||||
|
-DENTT_BUILD_EXAMPLE=ON \
|
||||||
|
-DENTT_BUILD_LIB=ON \
|
||||||
|
-DENTT_BUILD_SNAPSHOT=ON \
|
||||||
|
-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/entt.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" \
|
||||||
|
..
|
||||||
|
make -j4
|
144
external/entt/entt/.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
name: build
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
linux:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, ubuntu-20.04]
|
||||||
|
compiler:
|
||||||
|
- { pkg: g++, exe: 'g++', version: 7 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 8 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 9 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 10 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 11 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 12 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 8 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 9 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 10 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 11 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 12 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 13 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 14 }
|
||||||
|
exclude:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
compiler: { pkg: g++, exe: 'g++', version: 7 }
|
||||||
|
- os: ubuntu-latest
|
||||||
|
compiler: { pkg: g++, exe: 'g++', version: 8 }
|
||||||
|
- os: ubuntu-latest
|
||||||
|
compiler: { pkg: g++, exe: 'g++', version: 9 }
|
||||||
|
- os: ubuntu-latest
|
||||||
|
compiler: { pkg: clang, exe: 'clang++', version: 8 }
|
||||||
|
- os: ubuntu-latest
|
||||||
|
compiler: { pkg: clang, exe: 'clang++', version: 9 }
|
||||||
|
- os: ubuntu-latest
|
||||||
|
compiler: { pkg: clang, exe: 'clang++', version: 10 }
|
||||||
|
- os: ubuntu-latest
|
||||||
|
compiler: { pkg: clang, exe: 'clang++', version: 11 }
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
compiler: { pkg: g++, exe: 'g++', version: 10 }
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
compiler: { pkg: g++, exe: 'g++', version: 11 }
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
compiler: { pkg: g++, exe: 'g++', version: 12 }
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
compiler: { pkg: clang, exe: 'clang++', version: 12 }
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
compiler: { pkg: clang, exe: 'clang++', version: 13 }
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
compiler: { pkg: clang, exe: 'clang++', version: 14 }
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install compiler
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }}
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }}
|
||||||
|
run: |
|
||||||
|
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||||
|
make -j4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 30 -C Debug -j4
|
||||||
|
|
||||||
|
windows:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
toolset: [default, v141, v142, clang-cl]
|
||||||
|
include:
|
||||||
|
- toolset: v141
|
||||||
|
toolset_option: -T"v141"
|
||||||
|
- toolset: v142
|
||||||
|
toolset_option: -T"v142"
|
||||||
|
- toolset: clang-cl
|
||||||
|
toolset_option: -T"ClangCl"
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.toolset_option }} ..
|
||||||
|
cmake --build . -j 4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 30 -C Debug -j4
|
||||||
|
|
||||||
|
macos:
|
||||||
|
timeout-minutes: 15
|
||||||
|
runs-on: macOS-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||||
|
make -j4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 30 -C Debug -j4
|
||||||
|
|
||||||
|
extra:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [windows-latest, macOS-latest, ubuntu-latest]
|
||||||
|
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||||
|
cxx_std: [cxx_std_17, cxx_std_20]
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cmake -DENTT_BUILD_TESTING=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} ..
|
||||||
|
cmake --build . -j 4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 30 -C Debug -j4
|
38
external/entt/entt/.github/workflows/coverage.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: coverage
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
codecov:
|
||||||
|
timeout-minutes: 15
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CXXFLAGS: "--coverage -fno-elide-constructors -fno-inline -fno-default-inline"
|
||||||
|
CXX: g++
|
||||||
|
run: |
|
||||||
|
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||||
|
make -j4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 30 -C Debug -j4
|
||||||
|
- name: Collect data
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
sudo apt install lcov
|
||||||
|
lcov -c -d . -o coverage.info
|
||||||
|
lcov -l coverage.info
|
||||||
|
- name: Upload coverage to Codecov
|
||||||
|
uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
files: build/coverage.info
|
||||||
|
name: EnTT
|
||||||
|
fail_ci_if_error: true
|
39
external/entt/entt/.github/workflows/deploy.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
name: deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: published
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
homebrew-entt:
|
||||||
|
timeout-minutes: 5
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
GH_REPO: homebrew-entt
|
||||||
|
FORMULA: entt.rb
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Clone repository
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||||
|
run: git clone https://$GITHUB_ACTOR:$PERSONAL_ACCESS_TOKEN@github.com/$GITHUB_ACTOR/$GH_REPO.git
|
||||||
|
- name: Prepare formula
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cd $GH_REPO
|
||||||
|
curl "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" --location --fail --silent --show-error --output archive.tar.gz
|
||||||
|
sed -i -e '/url/s/".*"/"'$(echo "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" | sed -e 's/[\/&]/\\&/g')'"/' $FORMULA
|
||||||
|
sed -i -e '/sha256/s/".*"/"'$(openssl sha256 archive.tar.gz | cut -d " " -f 2)'"/' $FORMULA
|
||||||
|
- name: Update remote
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cd $GH_REPO
|
||||||
|
git config --local user.email "action@github.com"
|
||||||
|
git config --local user.name "$GITHUB_ACTOR"
|
||||||
|
git add $FORMULA
|
||||||
|
git commit -m "Update to ${{ github.ref }}"
|
||||||
|
git push origin master
|
31
external/entt/entt/.github/workflows/sanitizer.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
name: sanitizer
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
clang:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler: [clang++]
|
||||||
|
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||||
|
cxx_std: [cxx_std_17, cxx_std_20]
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CXX: ${{ matrix.compiler }}
|
||||||
|
run: |
|
||||||
|
cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} ..
|
||||||
|
make -j4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 30 -C Debug -j4
|
13
external/entt/entt/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Conan
|
||||||
|
conan/test_package/build
|
||||||
|
|
||||||
|
# IDEs
|
||||||
|
*.user
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
.vs
|
||||||
|
CMakeSettings.json
|
||||||
|
cpp.hint
|
||||||
|
|
||||||
|
# Bazel
|
||||||
|
/bazel-*
|
56
external/entt/entt/AUTHORS
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# Author
|
||||||
|
|
||||||
|
skypjack
|
||||||
|
|
||||||
|
# Contributors
|
||||||
|
|
||||||
|
alexames
|
||||||
|
BenediktConze
|
||||||
|
bjadamson
|
||||||
|
ceeac
|
||||||
|
ColinH
|
||||||
|
corystegel
|
||||||
|
Croydon
|
||||||
|
cschreib
|
||||||
|
cugone
|
||||||
|
dbacchet
|
||||||
|
dBagrat
|
||||||
|
djarek
|
||||||
|
DNKpp
|
||||||
|
DonKult
|
||||||
|
drglove
|
||||||
|
eliasdaler
|
||||||
|
erez-o
|
||||||
|
eugeneko
|
||||||
|
gale83
|
||||||
|
ghost
|
||||||
|
grdowns
|
||||||
|
Green-Sky
|
||||||
|
Innokentiy-Alaytsev
|
||||||
|
Kerndog73
|
||||||
|
Koward
|
||||||
|
Lawrencemm
|
||||||
|
markand
|
||||||
|
mhammerc
|
||||||
|
Milerius
|
||||||
|
Minimonium
|
||||||
|
morbo84
|
||||||
|
m-waka
|
||||||
|
netpoetica
|
||||||
|
NixAJ
|
||||||
|
Oortonaut
|
||||||
|
Paolo-Oliverio
|
||||||
|
pgruenbacher
|
||||||
|
prowolf
|
||||||
|
Qix-
|
||||||
|
stefanofiorentino
|
||||||
|
suVrik
|
||||||
|
szunhammer
|
||||||
|
The5-1
|
||||||
|
vblanco20-1
|
||||||
|
willtunnels
|
||||||
|
WizardIke
|
||||||
|
WoLfulus
|
||||||
|
w1th0utnam3
|
||||||
|
xissburg
|
||||||
|
zaucy
|
14
external/entt/entt/BUILD.bazel
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
_msvc_copts = ["/std:c++17"]
|
||||||
|
_gcc_copts = ["-std=c++17"]
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "entt",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
strip_include_prefix = "src",
|
||||||
|
hdrs = glob(["src/**/*.h", "src/**/*.hpp"]),
|
||||||
|
copts = select({
|
||||||
|
"@bazel_tools//src/conditions:windows": _msvc_copts,
|
||||||
|
"@bazel_tools//src/conditions:windows_msvc": _msvc_copts,
|
||||||
|
"//conditions:default": _gcc_copts,
|
||||||
|
}),
|
||||||
|
)
|
325
external/entt/entt/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
#
|
||||||
|
# EnTT
|
||||||
|
#
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.15.7)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Read project version
|
||||||
|
#
|
||||||
|
|
||||||
|
set(ENTT_VERSION_REGEX "#define ENTT_VERSION_.*[ \t]+(.+)")
|
||||||
|
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/entt/config/version.h" ENTT_VERSION REGEX ${ENTT_VERSION_REGEX})
|
||||||
|
list(TRANSFORM ENTT_VERSION REPLACE ${ENTT_VERSION_REGEX} "\\1")
|
||||||
|
string(JOIN "." ENTT_VERSION ${ENTT_VERSION})
|
||||||
|
|
||||||
|
#
|
||||||
|
# Project configuration
|
||||||
|
#
|
||||||
|
|
||||||
|
project(
|
||||||
|
EnTT
|
||||||
|
VERSION ${ENTT_VERSION}
|
||||||
|
DESCRIPTION "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more"
|
||||||
|
HOMEPAGE_URL "https://github.com/skypjack/entt"
|
||||||
|
LANGUAGES C CXX
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(VERBOSE "*")
|
||||||
|
message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||||
|
message(VERBOSE "* Copyright (c) 2017-2023 Michele Caini <michele.caini@gmail.com>")
|
||||||
|
message(VERBOSE "*")
|
||||||
|
|
||||||
|
#
|
||||||
|
# CMake stuff
|
||||||
|
#
|
||||||
|
|
||||||
|
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Compiler stuff
|
||||||
|
#
|
||||||
|
|
||||||
|
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." OFF)
|
||||||
|
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if available." OFF)
|
||||||
|
|
||||||
|
if(ENTT_USE_LIBCPP)
|
||||||
|
if(NOT WIN32)
|
||||||
|
include(CheckCXXSourceCompiles)
|
||||||
|
include(CMakePushCheckState)
|
||||||
|
|
||||||
|
cmake_push_check_state()
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||||
|
|
||||||
|
check_cxx_source_compiles("
|
||||||
|
#include<type_traits>
|
||||||
|
int main() { return std::is_same_v<int, char>; }
|
||||||
|
" ENTT_HAS_LIBCPP)
|
||||||
|
|
||||||
|
cmake_pop_check_state()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT ENTT_HAS_LIBCPP)
|
||||||
|
message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available. The flag will not be added to the target.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENTT_USE_SANITIZER)
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||||
|
set(ENTT_HAS_SANITIZER TRUE CACHE BOOL "" FORCE)
|
||||||
|
mark_as_advanced(ENTT_HAS_SANITIZER)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT ENTT_HAS_SANITIZER)
|
||||||
|
message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available. The flags will not be added to the target.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add EnTT target
|
||||||
|
#
|
||||||
|
|
||||||
|
option(ENTT_INCLUDE_HEADERS "Add all EnTT headers to the EnTT target." OFF)
|
||||||
|
option(ENTT_INCLUDE_NATVIS "Add EnTT natvis files to the EnTT target." OFF)
|
||||||
|
|
||||||
|
if(ENTT_INCLUDE_NATVIS)
|
||||||
|
if(MSVC)
|
||||||
|
set(ENTT_HAS_NATVIS TRUE CACHE BOOL "" FORCE)
|
||||||
|
mark_as_advanced(ENTT_HAS_NATVIS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT ENTT_HAS_NATVIS)
|
||||||
|
message(VERBOSE "The option ENTT_INCLUDE_NATVIS is set but natvis files are not supported. They will not be added to the target.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
add_library(EnTT INTERFACE)
|
||||||
|
add_library(EnTT::EnTT ALIAS EnTT)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
EnTT
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_features(EnTT INTERFACE cxx_std_17)
|
||||||
|
|
||||||
|
if(ENTT_INCLUDE_HEADERS)
|
||||||
|
target_sources(
|
||||||
|
EnTT
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/config.h>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/macro.h>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/version.h>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_map.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_set.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/algorithm.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/any.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/attribute.h>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/compressed_pair.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/enum.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/family.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/hashed_string.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/ident.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/iterator.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/memory.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/monostate.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/tuple.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_info.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_traits.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/utility.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/component.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/entity.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/group.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/handle.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/mixin.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/helper.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/observer.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/organizer.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/registry.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/runtime_view.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/snapshot.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/adjacency_matrix.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/dot.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/flow.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/context.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/factory.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/meta.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/node.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/pointer.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/policy.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/range.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/resolve.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/template.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/type_traits.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/utility.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/platform/android-ndk-r17.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/poly.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/process.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/scheduler.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/cache.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/loader.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/resource.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/delegate.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/dispatcher.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/emitter.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/fwd.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/sigh.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entt.hpp>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/fwd.hpp>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENTT_HAS_NATVIS)
|
||||||
|
target_sources(
|
||||||
|
EnTT
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/config.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/container.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/core.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/entity.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/graph.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/locator.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/meta.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/platform.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/poly.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/process.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/resource.natvis>
|
||||||
|
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/signal.natvis>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENTT_HAS_SANITIZER)
|
||||||
|
target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
|
||||||
|
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENTT_HAS_LIBCPP)
|
||||||
|
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Install pkg-config file
|
||||||
|
#
|
||||||
|
|
||||||
|
include(JoinPaths)
|
||||||
|
|
||||||
|
set(EnTT_PKGCONFIG ${CMAKE_CURRENT_BINARY_DIR}/entt.pc)
|
||||||
|
|
||||||
|
join_paths(EnTT_PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${EnTT_SOURCE_DIR}/cmake/in/entt.pc.in
|
||||||
|
${EnTT_PKGCONFIG}
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES ${EnTT_PKGCONFIG}
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||||
|
)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Install EnTT
|
||||||
|
#
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS EnTT
|
||||||
|
EXPORT EnTTTargets
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
EnTTConfigVersion.cmake
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
${EnTT_SOURCE_DIR}/cmake/in/EnTTConfig.cmake.in
|
||||||
|
EnTTConfig.cmake
|
||||||
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||||
|
)
|
||||||
|
|
||||||
|
export(
|
||||||
|
EXPORT EnTTTargets
|
||||||
|
FILE ${CMAKE_CURRENT_BINARY_DIR}/EnTTTargets.cmake
|
||||||
|
NAMESPACE EnTT::
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT EnTTTargets
|
||||||
|
FILE EnTTTargets.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||||
|
NAMESPACE EnTT::
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
${PROJECT_BINARY_DIR}/EnTTConfig.cmake
|
||||||
|
${PROJECT_BINARY_DIR}/EnTTConfigVersion.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||||
|
)
|
||||||
|
|
||||||
|
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
||||||
|
export(PACKAGE EnTT)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tests
|
||||||
|
#
|
||||||
|
|
||||||
|
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
|
||||||
|
|
||||||
|
if(ENTT_BUILD_TESTING)
|
||||||
|
option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
|
||||||
|
option(ENTT_BUILD_BENCHMARK "Build benchmark." OFF)
|
||||||
|
option(ENTT_BUILD_EXAMPLE "Build examples." OFF)
|
||||||
|
option(ENTT_BUILD_LIB "Build lib tests." OFF)
|
||||||
|
option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF)
|
||||||
|
|
||||||
|
set(ENTT_ID_TYPE std::uint32_t CACHE STRING "Type of identifiers to use for the tests")
|
||||||
|
set(ENTT_CXX_STD cxx_std_17 CACHE STRING "C++ standard revision to use for the tests")
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
option(ENTT_BUILD_DOCS "Enable building with documentation." OFF)
|
||||||
|
|
||||||
|
if(ENTT_BUILD_DOCS)
|
||||||
|
find_package(Doxygen 1.8)
|
||||||
|
|
||||||
|
if(DOXYGEN_FOUND)
|
||||||
|
add_subdirectory(docs)
|
||||||
|
endif()
|
||||||
|
endif()
|
43
external/entt/entt/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
First of all, thank you very much for taking the time to contribute to the
|
||||||
|
`EnTT` library.<br/>
|
||||||
|
How to do it mostly depends on the type of contribution:
|
||||||
|
|
||||||
|
* If you have a question, **please** ensure there isn't already an answer for
|
||||||
|
you by searching on GitHub under
|
||||||
|
[issues](https://github.com/skypjack/entt/issues). Do not forget to search
|
||||||
|
also through the closed ones. If you are unable to find a proper answer, feel
|
||||||
|
free to [open a new issue](https://github.com/skypjack/entt/issues/new).
|
||||||
|
Usually, questions are marked as such and closed in a few days.
|
||||||
|
|
||||||
|
* If you want to fix a typo in the inline documentation or in the README file,
|
||||||
|
if you want to add some new sections or if you want to help me with the
|
||||||
|
language by reviewing what I wrote so far (I'm not a native speaker after
|
||||||
|
all), **please** open a new
|
||||||
|
[pull request](https://github.com/skypjack/entt/pulls) with your changes.
|
||||||
|
|
||||||
|
* If you found a bug, **please** ensure there isn't already an answer for you by
|
||||||
|
searching on GitHub under [issues](https://github.com/skypjack/entt/issues).
|
||||||
|
If you are unable to find an open issue addressing the problem, feel free to
|
||||||
|
[open a new one](https://github.com/skypjack/entt/issues/new). **Please**, do
|
||||||
|
not forget to carefully describe how to reproduce the problem, then add all
|
||||||
|
the information about the system on which you are experiencing it and point
|
||||||
|
out the version of `EnTT` you are using (tag or commit).
|
||||||
|
|
||||||
|
* If you found a bug and you wrote a patch to fix it, open a new
|
||||||
|
[pull request](https://github.com/skypjack/entt/pulls) with your code.
|
||||||
|
**Please**, add some tests to avoid regressions in future if possible, it
|
||||||
|
would be really appreciated. Note that the `EnTT` library has a
|
||||||
|
[coverage at 100%](https://coveralls.io/github/skypjack/entt?branch=master)
|
||||||
|
(at least it was at 100% at the time I wrote this file) and this is the reason
|
||||||
|
for which you can be confident with using it in a production environment.
|
||||||
|
|
||||||
|
* If you want to propose a new feature and you know how to code it, **please**
|
||||||
|
do not issue directly a pull request. Before to do it,
|
||||||
|
[create a new issue](https://github.com/skypjack/entt/issues/new) to discuss
|
||||||
|
your proposal. Other users could be interested in your idea and the discussion
|
||||||
|
that will follow can refine it and therefore give us a better solution.
|
||||||
|
|
||||||
|
* If you want to request a new feature, I'm available for hiring. Take a look at
|
||||||
|
[my profile](https://github.com/skypjack) and feel free to write me.
|
21
external/entt/entt/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017-2023 Michele Caini, author of EnTT
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copy of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copy or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
428
external/entt/entt/README.md
vendored
Normal file
@ -0,0 +1,428 @@
|
|||||||
|

|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
[](https://github.com/skypjack/entt/actions)
|
||||||
|
[](https://codecov.io/gh/skypjack/entt)
|
||||||
|
[](https://godbolt.org/z/zxW73f)
|
||||||
|
[](https://vcpkg.link/ports/entt)
|
||||||
|
[](https://skypjack.github.io/entt/)
|
||||||
|
[](https://gitter.im/skypjack/entt)
|
||||||
|
[](https://discord.gg/5BjPWBd)
|
||||||
|
[](https://www.paypal.me/skypjack)
|
||||||
|
|
||||||
|
> `EnTT` has been a dream so far, we haven't found a single bug to date and it's
|
||||||
|
> super easy to work with
|
||||||
|
>
|
||||||
|
> -- Every EnTT User Ever
|
||||||
|
|
||||||
|
`EnTT` is a header-only, tiny and easy to use library for game programming and
|
||||||
|
much more written in **modern C++**.<br/>
|
||||||
|
[Among others](https://github.com/skypjack/entt/wiki/EnTT-in-Action), it's used
|
||||||
|
in [**Minecraft**](https://minecraft.net/en-us/attribution/) by Mojang, the
|
||||||
|
[**ArcGIS Runtime SDKs**](https://developers.arcgis.com/arcgis-runtime/) by Esri
|
||||||
|
and the amazing [**Ragdoll**](https://ragdolldynamics.com/).<br/>
|
||||||
|
If you don't see your project in the list, please open an issue, submit a PR or
|
||||||
|
add the [#entt](https://github.com/topics/entt) tag to your _topics_! :+1:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Do you want to **keep up with changes** or do you have a **question** that
|
||||||
|
doesn't require you to open an issue?<br/>
|
||||||
|
Join the [gitter channel](https://gitter.im/skypjack/entt) and the
|
||||||
|
[discord server](https://discord.gg/5BjPWBd), meet other users like you. The
|
||||||
|
more we are, the better for everyone.<br/>
|
||||||
|
Don't forget to check the
|
||||||
|
[FAQs](https://github.com/skypjack/entt/wiki/Frequently-Asked-Questions) and the
|
||||||
|
[wiki](https://github.com/skypjack/entt/wiki) too. Your answers may already be
|
||||||
|
there.
|
||||||
|
|
||||||
|
Do you want to support `EnTT`? Consider becoming a
|
||||||
|
[**sponsor**](https://github.com/users/skypjack/sponsorship).
|
||||||
|
Many thanks to [these people](https://skypjack.github.io/sponsorship/) and
|
||||||
|
**special** thanks to:
|
||||||
|
|
||||||
|
[](https://mojang.com)
|
||||||
|
[](https://img.ly/)
|
||||||
|
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Code Example](#code-example)
|
||||||
|
* [Motivation](#motivation)
|
||||||
|
* [Performance](#performance)
|
||||||
|
* [Integration](#integration)
|
||||||
|
* [Requirements](#requirements)
|
||||||
|
* [CMake](#cmake)
|
||||||
|
* [Natvis support](#natvis-support)
|
||||||
|
* [Packaging Tools](#packaging-tools)
|
||||||
|
* [pkg-config](#pkg-config)
|
||||||
|
* [Documentation](#documentation)
|
||||||
|
* [Tests](#tests)
|
||||||
|
* [EnTT in Action](#entt-in-action)
|
||||||
|
* [Contributors](#contributors)
|
||||||
|
* [License](#license)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
The entity-component-system (also known as _ECS_) is an architectural pattern
|
||||||
|
used mostly in game development. For further details:
|
||||||
|
|
||||||
|
* [Entity Systems Wiki](http://entity-systems.wikidot.com/)
|
||||||
|
* [Evolve Your Hierarchy](http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/)
|
||||||
|
* [ECS on Wikipedia](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system)
|
||||||
|
|
||||||
|
This project started off as a pure entity-component system. Over time the
|
||||||
|
codebase has grown as more and more classes and functionalities were added.<br/>
|
||||||
|
Here is a brief, yet incomplete list of what it offers today:
|
||||||
|
|
||||||
|
* Built-in **RTTI system** mostly similar to the standard one.
|
||||||
|
* A `constexpr` utility for human-readable **resource names**.
|
||||||
|
* Minimal **configuration system** built using the monostate pattern.
|
||||||
|
* Incredibly fast **entity-component system** with its own _pay for what you
|
||||||
|
use_ policy, unconstrained component types with optional pointer stability and
|
||||||
|
hooks for storage customization.
|
||||||
|
* Views and groups to iterate entities and components and allow different access
|
||||||
|
patterns, from **perfect SoA** to fully random.
|
||||||
|
* A lot of **facilities** built on top of the entity-component system to help
|
||||||
|
the users and avoid reinventing the wheel.
|
||||||
|
* General purpose **execution graph builder** for optimal scheduling.
|
||||||
|
* The smallest and most basic implementation of a **service locator** ever seen.
|
||||||
|
* A built-in, non-intrusive and macro-free runtime **reflection system**.
|
||||||
|
* **Static polymorphism** made simple and within everyone's reach.
|
||||||
|
* A few homemade containers, like a sparse set based **hash map**.
|
||||||
|
* A **cooperative scheduler** for processes of any type.
|
||||||
|
* All that is needed for **resource management** (cache, loaders, handles).
|
||||||
|
* Delegates, **signal handlers** and a tiny event dispatcher.
|
||||||
|
* A general purpose **event emitter** as a CRTP idiom based class template.
|
||||||
|
* And **much more**! Check out the
|
||||||
|
[**wiki**](https://github.com/skypjack/entt/wiki).
|
||||||
|
|
||||||
|
Consider this list a work in progress as well as the project. The whole API is
|
||||||
|
fully documented in-code for those who are brave enough to read it.<br/>
|
||||||
|
Please, do note that all tools are also DLL-friendly now and run smoothly across
|
||||||
|
boundaries.
|
||||||
|
|
||||||
|
One thing known to most is that `EnTT` is also used in **Minecraft**.<br/>
|
||||||
|
Given that the game is available literally everywhere, I can confidently say
|
||||||
|
that the library has been sufficiently tested on every platform that can come to
|
||||||
|
mind.
|
||||||
|
|
||||||
|
## Code Example
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
|
||||||
|
struct position {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct velocity {
|
||||||
|
float dx;
|
||||||
|
float dy;
|
||||||
|
};
|
||||||
|
|
||||||
|
void update(entt::registry ®istry) {
|
||||||
|
auto view = registry.view<const position, velocity>();
|
||||||
|
|
||||||
|
// use a callback
|
||||||
|
view.each([](const auto &pos, auto &vel) { /* ... */ });
|
||||||
|
|
||||||
|
// use an extended callback
|
||||||
|
view.each([](const auto entity, const auto &pos, auto &vel) { /* ... */ });
|
||||||
|
|
||||||
|
// use a range-for
|
||||||
|
for(auto [entity, pos, vel]: view.each()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// use forward iterators and get only the components of interest
|
||||||
|
for(auto entity: view) {
|
||||||
|
auto &vel = view.get<velocity>(entity);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
entt::registry registry;
|
||||||
|
|
||||||
|
for(auto i = 0u; i < 10u; ++i) {
|
||||||
|
const auto entity = registry.create();
|
||||||
|
registry.emplace<position>(entity, i * 1.f, i * 1.f);
|
||||||
|
if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
update(registry);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
I started developing `EnTT` for the _wrong_ reason: my goal was to design an
|
||||||
|
entity-component system to beat another well known open source library both in
|
||||||
|
terms of performance and possibly memory usage.<br/>
|
||||||
|
In the end, I did it, but it wasn't very satisfying. Actually it wasn't
|
||||||
|
satisfying at all. The fastest and nothing more, fairly little indeed. When I
|
||||||
|
realized it, I tried hard to keep intact the great performance of `EnTT` and to
|
||||||
|
add all the features I wanted to see in *my own library* at the same time.
|
||||||
|
|
||||||
|
Nowadays, `EnTT` is finally what I was looking for: still faster than its
|
||||||
|
_competitors_, lower memory usage in the average case, a really good API and an
|
||||||
|
amazing set of features. And even more, of course.
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
The proposed entity-component system is incredibly fast to iterate entities and
|
||||||
|
components, this is a fact. Some compilers make a lot of optimizations because
|
||||||
|
of how `EnTT` works, some others aren't that good. In general, if we consider
|
||||||
|
real world cases, `EnTT` is somewhere between a bit and much faster than many of
|
||||||
|
the other solutions around, although I couldn't check them all for obvious
|
||||||
|
reasons.
|
||||||
|
|
||||||
|
If you are interested, you can compile the `benchmark` test in release mode (to
|
||||||
|
enable compiler optimizations, otherwise it would make little sense) by setting
|
||||||
|
the `ENTT_BUILD_BENCHMARK` option of `CMake` to `ON`, then evaluate yourself
|
||||||
|
whether you're satisfied with the results or not.
|
||||||
|
|
||||||
|
Honestly I got tired of updating the README file whenever there is an
|
||||||
|
improvement.<br/>
|
||||||
|
There are already a lot of projects out there that use `EnTT` as a basis for
|
||||||
|
comparison (this should already tell you a lot). Many of these benchmarks are
|
||||||
|
completely wrong, many others are simply incomplete, good at omitting some
|
||||||
|
information and using the wrong function to compare a given feature. Certainly
|
||||||
|
there are also good ones but they age quickly if nobody updates them, especially
|
||||||
|
when the library they are dealing with is actively developed.
|
||||||
|
|
||||||
|
The choice to use `EnTT` should be based on its carefully designed API, its
|
||||||
|
set of features and the general performance, **not** because some single
|
||||||
|
benchmark shows it to be the fastest tool available.
|
||||||
|
|
||||||
|
In the future I'll likely try to get even better performance while still adding
|
||||||
|
new features, mainly for fun.<br/>
|
||||||
|
If you want to contribute and/or have suggestions, feel free to make a PR or
|
||||||
|
open an issue to discuss your idea.
|
||||||
|
|
||||||
|
# Integration
|
||||||
|
|
||||||
|
`EnTT` is a header-only library. This means that including the `entt.hpp` header
|
||||||
|
is enough to include the library as a whole and use it. For those who are
|
||||||
|
interested only in the entity-component system, consider to include the sole
|
||||||
|
`entity/registry.hpp` header instead.<br/>
|
||||||
|
It's a matter of adding the following line to the top of a file:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the line below to include only the entity-component system instead:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <entt/entity/registry.hpp>
|
||||||
|
```
|
||||||
|
|
||||||
|
Then pass the proper `-I` argument to the compiler to add the `src` directory to
|
||||||
|
the include paths.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
To be able to use `EnTT`, users must provide a full-featured compiler that
|
||||||
|
supports at least C++17.<br/>
|
||||||
|
The requirements below are mandatory to compile the tests and to extract the
|
||||||
|
documentation:
|
||||||
|
|
||||||
|
* `CMake` version 3.7 or later.
|
||||||
|
* `Doxygen` version 1.8 or later.
|
||||||
|
|
||||||
|
Alternatively, [Bazel](https://bazel.build) is also supported as a build system
|
||||||
|
(credits to [zaucy](https://github.com/zaucy) who offered to maintain it).<br/>
|
||||||
|
In the documentation below I'll still refer to `CMake`, this being the official
|
||||||
|
build system of the library.
|
||||||
|
|
||||||
|
## CMake
|
||||||
|
|
||||||
|
To use `EnTT` from a `CMake` project, just link an existing target to the
|
||||||
|
`EnTT::EnTT` alias.<br/>
|
||||||
|
The library offers everything you need for locating (as in `find_package`),
|
||||||
|
embedding (as in `add_subdirectory`), fetching (as in `FetchContent`) or using
|
||||||
|
it in many of the ways that you can think of and that involve `CMake`.<br/>
|
||||||
|
Covering all possible cases would require a treaty and not a simple README file,
|
||||||
|
but I'm confident that anyone reading this section also knows what it's about
|
||||||
|
and can use `EnTT` from a `CMake` project without problems.
|
||||||
|
|
||||||
|
## Natvis support
|
||||||
|
|
||||||
|
When using `CMake`, just enable the option `ENTT_INCLUDE_NATVIS` and enjoy
|
||||||
|
it.<br/>
|
||||||
|
Otherwise, most of the tools are covered via Natvis and all files can be found
|
||||||
|
in the `natvis` directory, divided by module.<br/>
|
||||||
|
If you spot errors or have suggestions, any contribution is welcome!
|
||||||
|
|
||||||
|
## Packaging Tools
|
||||||
|
|
||||||
|
`EnTT` is available for some of the most known packaging tools. In particular:
|
||||||
|
|
||||||
|
* [`Conan`](https://github.com/conan-io/conan-center-index), the C/C++ Package
|
||||||
|
Manager for Developers.
|
||||||
|
|
||||||
|
* [`vcpkg`](https://github.com/Microsoft/vcpkg), Microsoft VC++ Packaging
|
||||||
|
Tool.<br/>
|
||||||
|
You can download and install `EnTT` in just a few simple steps:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git clone https://github.com/Microsoft/vcpkg.git
|
||||||
|
$ cd vcpkg
|
||||||
|
$ ./bootstrap-vcpkg.sh
|
||||||
|
$ ./vcpkg integrate install
|
||||||
|
$ vcpkg install entt
|
||||||
|
```
|
||||||
|
|
||||||
|
Or you can use the `experimental` feature to test the latest changes:
|
||||||
|
|
||||||
|
```
|
||||||
|
vcpkg install entt[experimental] --head
|
||||||
|
```
|
||||||
|
|
||||||
|
The `EnTT` port in `vcpkg` is kept up to date by Microsoft team members and
|
||||||
|
community contributors.<br/>
|
||||||
|
If the version is out of date, please
|
||||||
|
[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the
|
||||||
|
`vcpkg` repository.
|
||||||
|
|
||||||
|
* [`Homebrew`](https://github.com/skypjack/homebrew-entt), the missing package
|
||||||
|
manager for macOS.<br/>
|
||||||
|
Available as a homebrew formula. Just type the following to install it:
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install skypjack/entt/entt
|
||||||
|
```
|
||||||
|
|
||||||
|
* [`build2`](https://build2.org), build toolchain for developing and packaging C
|
||||||
|
and C++ code.<br/>
|
||||||
|
In order to use the [`entt`](https://cppget.org/entt) package in a `build2`
|
||||||
|
project, add the following line or a similar one to the `manifest` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
depends: entt ^3.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Also check that the configuration refers to a valid repository, so that the
|
||||||
|
package can be found by `build2`:
|
||||||
|
|
||||||
|
* [`cppget.org`](https://cppget.org), the open-source community central
|
||||||
|
repository, accessible as `https://pkg.cppget.org/1/stable`.
|
||||||
|
|
||||||
|
* [Package source repository](https://github.com/build2-packaging/entt):
|
||||||
|
accessible as either `https://github.com/build2-packaging/entt.git` or
|
||||||
|
`ssh://git@github.com/build2-packaging/entt.git`.
|
||||||
|
Feel free to [report issues](https://github.com/build2-packaging/entt) with
|
||||||
|
this package.
|
||||||
|
|
||||||
|
Both can be used with `bpkg add-repo` or added in a project
|
||||||
|
`repositories.manifest`. See the official
|
||||||
|
[documentation](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-repositories)
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
Consider this list a work in progress and help me to make it longer if you like.
|
||||||
|
|
||||||
|
## pkg-config
|
||||||
|
|
||||||
|
`EnTT` also supports `pkg-config` (for some definition of _supports_ at least).
|
||||||
|
A suitable file called `entt.pc` is generated and installed in a proper
|
||||||
|
directory when running `CMake`.<br/>
|
||||||
|
This should also make it easier to use with tools such as `Meson` or similar.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
The documentation is based on [doxygen](http://www.doxygen.nl/). To build it:
|
||||||
|
|
||||||
|
$ cd build
|
||||||
|
$ cmake .. -DENTT_BUILD_DOCS=ON
|
||||||
|
$ make
|
||||||
|
|
||||||
|
The API reference is created in HTML format in the `build/docs/html` directory.
|
||||||
|
To navigate it with your favorite browser:
|
||||||
|
|
||||||
|
$ cd build
|
||||||
|
$ your_favorite_browser docs/html/index.html
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
The same version is also available [online](https://skypjack.github.io/entt/)
|
||||||
|
for the latest release, that is the last stable tag.<br/>
|
||||||
|
Moreover, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated
|
||||||
|
to the project where users can find all related documentation pages.
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
|
||||||
|
To compile and run the tests, `EnTT` requires *googletest*.<br/>
|
||||||
|
`cmake` downloads and compiles the library before compiling anything else. In
|
||||||
|
order to build the tests, set the `CMake` option `ENTT_BUILD_TESTING` to `ON`.
|
||||||
|
|
||||||
|
To build the most basic set of tests:
|
||||||
|
|
||||||
|
* `$ cd build`
|
||||||
|
* `$ cmake -DENTT_BUILD_TESTING=ON ..`
|
||||||
|
* `$ make`
|
||||||
|
* `$ make test`
|
||||||
|
|
||||||
|
Note that benchmarks are not part of this set.
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# EnTT in Action
|
||||||
|
|
||||||
|
`EnTT` is widely used in private and commercial applications. I cannot even
|
||||||
|
mention most of them because of some signatures I put on some documents time
|
||||||
|
ago. Fortunately, there are also people who took the time to implement open
|
||||||
|
source projects based on `EnTT` and did not hold back when it came to
|
||||||
|
documenting them.
|
||||||
|
|
||||||
|
[Here](https://github.com/skypjack/entt/wiki/EnTT-in-Action) you can find an
|
||||||
|
incomplete list of games, applications and articles that can be used as a
|
||||||
|
reference.
|
||||||
|
|
||||||
|
If you know of other resources out there that are about `EnTT`, feel free to
|
||||||
|
open an issue or a PR and I'll be glad to add them to the list.
|
||||||
|
|
||||||
|
# Contributors
|
||||||
|
|
||||||
|
Requests for features, PRs, suggestions ad feedback are highly appreciated.
|
||||||
|
|
||||||
|
If you find you can help and want to contribute to the project with your
|
||||||
|
experience or you do want to get part of the project for some other reason, feel
|
||||||
|
free to contact me directly (you can find the mail in the
|
||||||
|
[profile](https://github.com/skypjack)).<br/>
|
||||||
|
I can't promise that each and every contribution will be accepted, but I can
|
||||||
|
assure that I'll do my best to take them all as soon as possible.
|
||||||
|
|
||||||
|
If you decide to participate, please see the guidelines for
|
||||||
|
[contributing](CONTRIBUTING.md) before to create issues or pull
|
||||||
|
requests.<br/>
|
||||||
|
Take also a look at the
|
||||||
|
[contributors list](https://github.com/skypjack/entt/blob/master/AUTHORS) to
|
||||||
|
know who has participated so far.
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
Code and documentation Copyright (c) 2017-2023 Michele Caini.<br/>
|
||||||
|
Colorful logo Copyright (c) 2018-2021 Richard Caseres.
|
||||||
|
|
||||||
|
Code released under
|
||||||
|
[the MIT license](https://github.com/skypjack/entt/blob/master/LICENSE).<br/>
|
||||||
|
Documentation released under
|
||||||
|
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).<br/>
|
||||||
|
All logos released under
|
||||||
|
[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
26
external/entt/entt/TODO
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
EXAMPLES
|
||||||
|
* filter on runtime values/variables (not only types)
|
||||||
|
* support to polymorphic types (see #859)
|
||||||
|
|
||||||
|
DOC:
|
||||||
|
* custom storage/view
|
||||||
|
* examples (and credits) from @alanjfs :)
|
||||||
|
* update entity doc when the storage based model is in place
|
||||||
|
* in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
|
||||||
|
|
||||||
|
TODO (high prio):
|
||||||
|
* check natvis files (periodically :)
|
||||||
|
* resource cache: avoid using shared ptr with loader and the others
|
||||||
|
* further optimize exclusion lists in multi type views (no existence check)
|
||||||
|
* further improve the snapshot stuff, ie component functions
|
||||||
|
* use fixture for storage tests to reduce loc number and duplication as much as possible
|
||||||
|
* basic_view<...>::reach(...)
|
||||||
|
* doc: bump entities
|
||||||
|
|
||||||
|
WIP:
|
||||||
|
* get rid of observers, storage based views made them pointless - document alternatives
|
||||||
|
* exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
|
||||||
|
* process scheduler: reviews, use free lists internally
|
||||||
|
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
|
||||||
|
* bring nested groups back in place (see bd34e7f)
|
||||||
|
* work stealing job system (see #100) + mt scheduler based on const awareness for types
|
1
external/entt/entt/WORKSPACE
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
workspace(name = "com_github_skypjack_entt")
|
2
external/entt/entt/build/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
5
external/entt/entt/cmake/in/EnTTConfig.cmake.in
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
set(EnTT_VERSION "@PROJECT_VERSION@")
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
|
||||||
|
check_required_components("@PROJECT_NAME@")
|
8
external/entt/entt/cmake/in/entt.pc.in
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
includedir=@EnTT_PKGCONFIG_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: EnTT
|
||||||
|
Description: Gaming meets modern C++
|
||||||
|
Url: https://github.com/skypjack/entt
|
||||||
|
Version: @ENTT_VERSION@
|
||||||
|
Cflags: -I${includedir}
|
23
external/entt/entt/cmake/modules/JoinPaths.cmake
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# This module provides function for joining paths
|
||||||
|
# known from most languages
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (MIT OR CC0-1.0)
|
||||||
|
# Copyright 2020 Jan Tojnar
|
||||||
|
# https://github.com/jtojnar/cmake-snips
|
||||||
|
#
|
||||||
|
# Modelled after Python<6F>s os.path.join
|
||||||
|
# https://docs.python.org/3.7/library/os.path.html#os.path.join
|
||||||
|
# Windows not supported
|
||||||
|
function(join_paths joined_path first_path_segment)
|
||||||
|
set(temp_path "${first_path_segment}")
|
||||||
|
foreach(current_segment IN LISTS ARGN)
|
||||||
|
if(NOT ("${current_segment}" STREQUAL ""))
|
||||||
|
if(IS_ABSOLUTE "${current_segment}")
|
||||||
|
set(temp_path "${current_segment}")
|
||||||
|
else()
|
||||||
|
set(temp_path "${temp_path}/${current_segment}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
37
external/entt/entt/conan/build.py
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from cpt.packager import ConanMultiPackager
|
||||||
|
import os
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
username = os.getenv("GITHUB_ACTOR")
|
||||||
|
tag_version = os.getenv("GITHUB_REF")
|
||||||
|
tag_package = os.getenv("GITHUB_REPOSITORY")
|
||||||
|
login_username = os.getenv("CONAN_LOGIN_USERNAME")
|
||||||
|
package_version = tag_version.replace("refs/tags/v", "")
|
||||||
|
package_name = tag_package.replace("skypjack/", "")
|
||||||
|
reference = "{}/{}".format(package_name, package_version)
|
||||||
|
channel = os.getenv("CONAN_CHANNEL", "stable")
|
||||||
|
upload = os.getenv("CONAN_UPLOAD")
|
||||||
|
stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*")
|
||||||
|
test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package"))
|
||||||
|
upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
|
||||||
|
disable_shared = os.getenv("CONAN_DISABLE_SHARED_BUILD", "False")
|
||||||
|
|
||||||
|
builder = ConanMultiPackager(username=username,
|
||||||
|
reference=reference,
|
||||||
|
channel=channel,
|
||||||
|
login_username=login_username,
|
||||||
|
upload=upload,
|
||||||
|
stable_branch_pattern=stable_branch_pattern,
|
||||||
|
upload_only_when_stable=upload_only_when_stable,
|
||||||
|
test_folder=test_folder)
|
||||||
|
builder.add()
|
||||||
|
|
||||||
|
filtered_builds = []
|
||||||
|
for settings, options, env_vars, build_requires, reference in builder.items:
|
||||||
|
if disable_shared == "False" or not options["{}:shared".format(package_name)]:
|
||||||
|
filtered_builds.append([settings, options, env_vars, build_requires])
|
||||||
|
builder.builds = filtered_builds
|
||||||
|
|
||||||
|
builder.run()
|
7
external/entt/entt/conan/ci/build.sh
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
conan user
|
||||||
|
python conan/build.py
|
6
external/entt/entt/conan/ci/install.sh
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
pip install -U conan_package_tools conan
|
13
external/entt/entt/conan/test_package/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.7.2)
|
||||||
|
project(test_package)
|
||||||
|
|
||||||
|
set(CMAKE_VERBOSE_MAKEFILE TRUE)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||||
|
conan_basic_setup()
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME} test_package.cpp)
|
||||||
|
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
|
19
external/entt/entt/conan/test_package/conanfile.py
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from conans import ConanFile, CMake
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class TestPackageConan(ConanFile):
|
||||||
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
|
generators = "cmake"
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
cmake = CMake(self)
|
||||||
|
cmake.configure()
|
||||||
|
cmake.build()
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
bin_path = os.path.join("bin", "test_package")
|
||||||
|
self.run(bin_path, run_environment=True)
|
56
external/entt/entt/conan/test_package/test_package.cpp
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include <entt/entt.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
struct position {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct velocity {
|
||||||
|
float dx;
|
||||||
|
float dy;
|
||||||
|
};
|
||||||
|
|
||||||
|
void update(entt::registry ®istry) {
|
||||||
|
auto view = registry.view<position, velocity>();
|
||||||
|
|
||||||
|
for(auto entity: view) {
|
||||||
|
// gets only the components that are going to be used ...
|
||||||
|
|
||||||
|
auto &vel = view.get<velocity>(entity);
|
||||||
|
|
||||||
|
vel.dx = 0.;
|
||||||
|
vel.dy = 0.;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(std::uint64_t dt, entt::registry ®istry) {
|
||||||
|
registry.view<position, velocity>().each([dt](auto &pos, auto &vel) {
|
||||||
|
// gets all the components of the view at once ...
|
||||||
|
|
||||||
|
pos.x += vel.dx * dt;
|
||||||
|
pos.y += vel.dy * dt;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
entt::registry registry;
|
||||||
|
std::uint64_t dt = 16;
|
||||||
|
|
||||||
|
for(auto i = 0; i < 10; ++i) {
|
||||||
|
auto entity = registry.create();
|
||||||
|
registry.emplace<position>(entity, i * 1.f, i * 1.f);
|
||||||
|
if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
update(dt, registry);
|
||||||
|
update(registry);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
27
external/entt/entt/conanfile.py
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from conans import ConanFile
|
||||||
|
|
||||||
|
|
||||||
|
class EnttConan(ConanFile):
|
||||||
|
name = "entt"
|
||||||
|
description = "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more "
|
||||||
|
topics = ("conan," "entt", "gaming", "entity", "ecs")
|
||||||
|
url = "https://github.com/skypjack/entt"
|
||||||
|
homepage = url
|
||||||
|
author = "Michele Caini <michele.caini@gmail.com>"
|
||||||
|
license = "MIT"
|
||||||
|
exports = ["LICENSE"]
|
||||||
|
exports_sources = ["src/*"]
|
||||||
|
no_copy_source = True
|
||||||
|
|
||||||
|
def package(self):
|
||||||
|
self.copy(pattern="LICENSE", dst="licenses")
|
||||||
|
self.copy(pattern="*", dst="include", src="src", keep_path=True)
|
||||||
|
|
||||||
|
def package_info(self):
|
||||||
|
if not self.in_local_cache:
|
||||||
|
self.cpp_info.includedirs = ["src"]
|
||||||
|
|
||||||
|
def package_id(self):
|
||||||
|
self.info.header_only()
|
54
external/entt/entt/docs/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#
|
||||||
|
# Doxygen configuration (documentation)
|
||||||
|
#
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
doxygen-awesome-css
|
||||||
|
GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css
|
||||||
|
GIT_TAG main
|
||||||
|
GIT_SHALLOW 1
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_GetProperties(doxygen-awesome-css)
|
||||||
|
|
||||||
|
if(NOT doxygen-awesome-css_POPULATED)
|
||||||
|
FetchContent_Populate(doxygen-awesome-css)
|
||||||
|
set(doxygen-awesome-css_INCLUDE_DIR ${doxygen-awesome-css_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
|
||||||
|
set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_INCLUDE_DIR})
|
||||||
|
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
configure_file(doxy.in doxy.cfg @ONLY)
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
docs ALL
|
||||||
|
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
|
||||||
|
WORKING_DIRECTORY ${EnTT_SOURCE_DIR}
|
||||||
|
VERBATIM
|
||||||
|
SOURCES
|
||||||
|
dox/extra.dox
|
||||||
|
md/config.md
|
||||||
|
md/container.md
|
||||||
|
md/core.md
|
||||||
|
md/entity.md
|
||||||
|
md/faq.md
|
||||||
|
md/lib.md
|
||||||
|
md/links.md
|
||||||
|
md/locator.md
|
||||||
|
md/meta.md
|
||||||
|
md/poly.md
|
||||||
|
md/process.md
|
||||||
|
md/reference.md
|
||||||
|
md/resource.md
|
||||||
|
md/signal.md
|
||||||
|
md/unreal.md
|
||||||
|
doxy.in
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY ${DOXY_OUTPUT_DIRECTORY}/html
|
||||||
|
DESTINATION share/${PROJECT_NAME}-${PROJECT_VERSION}/
|
||||||
|
)
|
5
external/entt/entt/docs/dox/extra.dox
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* @namespace entt
|
||||||
|
*
|
||||||
|
* @brief `EnTT` default namespace.
|
||||||
|
*/
|
2726
external/entt/entt/docs/doxy.in
vendored
Normal file
120
external/entt/entt/docs/md/config.md
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# Crash Course: configuration
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Definitions](#definitions)
|
||||||
|
* [ENTT_NOEXCEPTION](#entt_noexception)
|
||||||
|
* [ENTT_USE_ATOMIC](#entt_use_atomic)
|
||||||
|
* [ENTT_ID_TYPE](#entt_id_type)
|
||||||
|
* [ENTT_SPARSE_PAGE](#entt_sparse_page)
|
||||||
|
* [ENTT_PACKED_PAGE](#entt_packed_page)
|
||||||
|
* [ENTT_ASSERT](#entt_assert)
|
||||||
|
* [ENTT_ASSERT_CONSTEXPR](#entt_assert_constexpr)
|
||||||
|
* [ENTT_DISABLE_ASSERT](#entt_disable_assert)
|
||||||
|
* [ENTT_NO_ETO](#entt_no_eto)
|
||||||
|
* [ENTT_STANDARD_CPP](#entt_standard_cpp)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
`EnTT` has become almost completely customizable over time, in many
|
||||||
|
respects. These variables are just one of the many ways to customize how it
|
||||||
|
works.<br/>
|
||||||
|
In the vast majority of cases, users will have no interest in changing the
|
||||||
|
default parameters. For all other cases, the list of possible configurations
|
||||||
|
with which it's possible to adjust the behavior of the library at runtime can be
|
||||||
|
found below.
|
||||||
|
|
||||||
|
# Definitions
|
||||||
|
|
||||||
|
All options are intended as parameters to the compiler (or user-defined macros
|
||||||
|
within the compilation units, if preferred).<br/>
|
||||||
|
Each parameter can result in internal library definitions. It's not recommended
|
||||||
|
to try to also modify these definitions, since there is no guarantee that they
|
||||||
|
will remain stable over time unlike the options below.
|
||||||
|
|
||||||
|
## ENTT_NOEXCEPTION
|
||||||
|
|
||||||
|
Define this variable without assigning any value to it to turn off exception
|
||||||
|
handling in `EnTT`.<br/>
|
||||||
|
This is roughly equivalent to setting the compiler flag `-fno-exceptions` but is
|
||||||
|
also limited to this library only.
|
||||||
|
|
||||||
|
## ENTT_USE_ATOMIC
|
||||||
|
|
||||||
|
In general, `EnTT` doesn't offer primitives to support multi-threading. Many of
|
||||||
|
the features can be split over multiple threads without any explicit control and
|
||||||
|
the user is the one who knows if a synchronization point is required.<br/>
|
||||||
|
However, some features aren't easily accessible to users and are made
|
||||||
|
thread-safe by means of this definition.
|
||||||
|
|
||||||
|
## ENTT_ID_TYPE
|
||||||
|
|
||||||
|
`entt::id_type` is directly controlled by this definition and widely used within
|
||||||
|
the library.<br/>
|
||||||
|
By default, its type is `std::uint32_t`. However, users can define a different
|
||||||
|
default type if necessary.
|
||||||
|
|
||||||
|
## ENTT_SPARSE_PAGE
|
||||||
|
|
||||||
|
It's known that the ECS module of `EnTT` is based on _sparse sets_. What is less
|
||||||
|
known perhaps is that the sparse arrays are paged to reduce memory usage.<br/>
|
||||||
|
Default size of pages (that is, the number of elements they contain) is 4096 but
|
||||||
|
users can adjust it if appropriate. In all case, the chosen value **must** be a
|
||||||
|
power of 2.
|
||||||
|
|
||||||
|
## ENTT_PACKED_PAGE
|
||||||
|
|
||||||
|
As it happens with sparse arrays, packed arrays are also paginated. However, in
|
||||||
|
this case the aim isn't to reduce memory usage but to have pointer stability
|
||||||
|
upon component creation.<br/>
|
||||||
|
Default size of pages (that is, the number of elements they contain) is 1024 but
|
||||||
|
users can adjust it if appropriate. In all case, the chosen value **must** be a
|
||||||
|
power of 2.
|
||||||
|
|
||||||
|
## ENTT_ASSERT
|
||||||
|
|
||||||
|
For performance reasons, `EnTT` doesn't use exceptions or any other control
|
||||||
|
structures. In fact, it offers many features that result in undefined behavior
|
||||||
|
if not used correctly.<br/>
|
||||||
|
To get around this, the library relies on a lot of asserts for the purpose of
|
||||||
|
detecting errors in debug builds. By default, it uses `assert` internally. Users
|
||||||
|
are allowed to overwrite its behavior by setting this variable.
|
||||||
|
|
||||||
|
### ENTT_ASSERT_CONSTEXPR
|
||||||
|
|
||||||
|
Usually, an assert within a `constexpr` function isn't a big deal. However, in
|
||||||
|
case of extreme customizations, it might be useful to differentiate.<br/>
|
||||||
|
For this purpose, `EnTT` introduces an admittedly badly named variable to make
|
||||||
|
the job easier in this regard. By default, this variable forwards its arguments
|
||||||
|
to `ENTT_ASSERT`.
|
||||||
|
|
||||||
|
### ENTT_DISABLE_ASSERT
|
||||||
|
|
||||||
|
Assertions may in turn affect performance to an extent when enabled. Whether
|
||||||
|
`ENTT_ASSERT` and `ENTT_ASSERT_CONSTEXPR` are redefined or not, all asserts can
|
||||||
|
be disabled at once by means of this definition.<br/>
|
||||||
|
Note that `ENTT_DISABLE_ASSERT` takes precedence over the redefinition of the
|
||||||
|
other variables and is therefore meant to disable all controls no matter what.
|
||||||
|
|
||||||
|
## ENTT_NO_ETO
|
||||||
|
|
||||||
|
In order to reduce memory consumption and increase performance, empty types are
|
||||||
|
never instantiated nor stored by the ECS module of `EnTT`.<br/>
|
||||||
|
Use this variable to treat these types like all others and therefore to create a
|
||||||
|
dedicated storage for them.
|
||||||
|
|
||||||
|
## ENTT_STANDARD_CPP
|
||||||
|
|
||||||
|
`EnTT` mixes non-standard language features with others that are perfectly
|
||||||
|
compliant to offer some of its functionalities.<br/>
|
||||||
|
This definition prevents the library from using non-standard techniques, that
|
||||||
|
is, functionalities that aren't fully compliant with the standard C++.<br/>
|
||||||
|
While there are no known portability issues at the time of this writing, this
|
||||||
|
should make the library fully portable anyway if needed.
|
66
external/entt/entt/docs/md/container.md
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Crash Course: containers
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Containers](#containers)
|
||||||
|
* [Dense map](#dense-map)
|
||||||
|
* [Dense set](#dense-set)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
The standard C++ library offers a wide range of containers and it's really
|
||||||
|
difficult to do better (although it's very easy to do worse, as many examples
|
||||||
|
available online demonstrate).<br/>
|
||||||
|
`EnTT` doesn't try in any way to replace what is offered by the standard. Quite
|
||||||
|
the opposite, given the widespread use that is made of standard containers.<br/>
|
||||||
|
However, the library also tries to fill a gap in features and functionalities by
|
||||||
|
making available some containers initially developed for internal use.
|
||||||
|
|
||||||
|
This section of the library is likely to grow larger over time. However, for the
|
||||||
|
moment it's quite small and mainly aimed at satisfying some internal needs.<br/>
|
||||||
|
For all containers made available, full test coverage and stability over time is
|
||||||
|
guaranteed as usual.
|
||||||
|
|
||||||
|
# Containers
|
||||||
|
|
||||||
|
## Dense map
|
||||||
|
|
||||||
|
The dense map made available in `EnTT` is a hash map that aims to return a
|
||||||
|
packed array of elements, so as to reduce the number of jumps in memory during
|
||||||
|
iterations.<br/>
|
||||||
|
The implementation is based on _sparse sets_ and each bucket is identified by an
|
||||||
|
implicit list within the packed array itself.
|
||||||
|
|
||||||
|
The interface is very close to its counterpart in the standard library, that is,
|
||||||
|
the `std::unordered_map` class.<br/>
|
||||||
|
However, both local and non-local iterators returned by a dense map belong to
|
||||||
|
the input iterator category although they respectively model the concepts of a
|
||||||
|
_forward iterator_ type and a _random access iterator_ type.<br/>
|
||||||
|
This is because they return a pair of references rather than a reference to a
|
||||||
|
pair. In other words, dense maps return a so called _proxy iterator_ the value
|
||||||
|
type of which is:
|
||||||
|
|
||||||
|
* `std::pair<const Key &, Type &>` for non-const iterator types.
|
||||||
|
* `std::pair<const Key &, const Type &>` for const iterator types.
|
||||||
|
|
||||||
|
This is quite different from what any standard library map returns and should be
|
||||||
|
taken into account when looking for a drop-in replacement.
|
||||||
|
|
||||||
|
## Dense set
|
||||||
|
|
||||||
|
The dense set made available in `EnTT` is a hash set that aims to return a
|
||||||
|
packed array of elements, so as to reduce the number of jumps in memory during
|
||||||
|
iterations.<br/>
|
||||||
|
The implementation is based on _sparse sets_ and each bucket is identified by an
|
||||||
|
implicit list within the packed array itself.
|
||||||
|
|
||||||
|
The interface is in all respects similar to its counterpart in the standard
|
||||||
|
library, that is, the `std::unordered_set` class.<br/>
|
||||||
|
Therefore, there is no need to go into the API description.
|
986
external/entt/entt/docs/md/core.md
vendored
Normal file
@ -0,0 +1,986 @@
|
|||||||
|
# Crash Course: core functionalities
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Any as in any type](#any-as-in-any-type)
|
||||||
|
* [Small buffer optimization](#small-buffer-optimization)
|
||||||
|
* [Alignment requirement](#alignment-requirement)
|
||||||
|
* [Compressed pair](#compressed-pair)
|
||||||
|
* [Enum as bitmask](#enum-as-bitmask)
|
||||||
|
* [Hashed strings](#hashed-strings)
|
||||||
|
* [Wide characters](wide-characters)
|
||||||
|
* [Conflicts](#conflicts)
|
||||||
|
* [Iterators](#iterators)
|
||||||
|
* [Input iterator pointer](#input-iterator-pointer)
|
||||||
|
* [Iota iterator](#iota-iterator)
|
||||||
|
* [Iterable adaptor](#iterable-adaptor)
|
||||||
|
* [Memory](#memory)
|
||||||
|
* [Power of two and fast modulus](#power-of-two-and-fast-modulus)
|
||||||
|
* [Allocator aware unique pointers](#allocator-aware-unique-pointers)
|
||||||
|
* [Monostate](#monostate)
|
||||||
|
* [Type support](#type-support)
|
||||||
|
* [Built-in RTTI support](#built-in-rtti-support)
|
||||||
|
* [Type info](#type-info)
|
||||||
|
* [Almost unique identifiers](#almost-unique-identifiers)
|
||||||
|
* [Type traits](#type-traits)
|
||||||
|
* [Size of](#size-of)
|
||||||
|
* [Is applicable](#is-applicable)
|
||||||
|
* [Constness as](#constness-as)
|
||||||
|
* [Member class type](#member-class-type)
|
||||||
|
* [N-th argument](#n-th-argument)
|
||||||
|
* [Integral constant](#integral-constant)
|
||||||
|
* [Tag](#tag)
|
||||||
|
* [Type list and value list](#type-list-and-value-list)
|
||||||
|
* [Unique sequential identifiers](#unique-sequential-identifiers)
|
||||||
|
* [Compile-time generator](#compile-time-generator)
|
||||||
|
* [Runtime generator](#runtime-generator)
|
||||||
|
* [Utilities](#utilities)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
`EnTT` comes with a bunch of core functionalities mostly used by the other parts
|
||||||
|
of the library.<br/>
|
||||||
|
Many of these tools are also useful in everyday work. Therefore, it's worth
|
||||||
|
describing them so as not to reinvent the wheel in case of need.
|
||||||
|
|
||||||
|
# Any as in any type
|
||||||
|
|
||||||
|
`EnTT` offers its own `any` type. It may seem redundant considering that C++17
|
||||||
|
introduced `std::any`, but it is not (hopefully).<br/>
|
||||||
|
First of all, the _type_ returned by an `std::any` is a const reference to an
|
||||||
|
`std::type_info`, an implementation defined class that's not something everyone
|
||||||
|
wants to see in a software. Furthermore, there is no way to bind it to the type
|
||||||
|
system of the library and therefore with its integrated RTTI support.
|
||||||
|
|
||||||
|
The `any` API is very similar to that of its most famous counterpart, mainly
|
||||||
|
because this class serves the same purpose of being an opaque container for any
|
||||||
|
type of value.<br/>
|
||||||
|
Instances also minimize the number of allocations by relying on a well known
|
||||||
|
technique called _small buffer optimization_ and a fake vtable.
|
||||||
|
|
||||||
|
Creating an object of the `any` type, whether empty or not, is trivial:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// an empty container
|
||||||
|
entt::any empty{};
|
||||||
|
|
||||||
|
// a container for an int
|
||||||
|
entt::any any{0};
|
||||||
|
|
||||||
|
// in place construction
|
||||||
|
entt::any in_place{std::in_place_type<int>, 42};
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, the `make_any` function serves the same purpose but requires to
|
||||||
|
always be explicit about the type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::any any = entt::make_any<int>(42);
|
||||||
|
```
|
||||||
|
|
||||||
|
In both cases, the `any` class takes the burden of destroying the contained
|
||||||
|
element when required, regardless of the storage strategy used for the specific
|
||||||
|
object.<br/>
|
||||||
|
Furthermore, an instance of `any` isn't tied to an actual type. Therefore, the
|
||||||
|
wrapper is reconfigured when it's assigned a new object of a type other than
|
||||||
|
the one it contains.
|
||||||
|
|
||||||
|
There is also a way to directly assign a value to the variable contained by an
|
||||||
|
`entt::any`, without necessarily replacing it. This is especially useful when
|
||||||
|
the object is used in _aliasing mode_, as described below:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::any any{42};
|
||||||
|
entt::any value{3};
|
||||||
|
|
||||||
|
// assigns by copy
|
||||||
|
any.assign(value);
|
||||||
|
|
||||||
|
// assigns by move
|
||||||
|
any.assign(std::move(value));
|
||||||
|
```
|
||||||
|
|
||||||
|
The `any` class performs a check on the type information and whether or not the
|
||||||
|
original type was copy or move assignable, as appropriate.<br/>
|
||||||
|
In all cases, the `assign` function returns a boolean value that is true in case
|
||||||
|
of success and false otherwise.
|
||||||
|
|
||||||
|
When in doubt about the type of object contained, the `type` member function
|
||||||
|
returns a const reference to the `type_info` associated with its element, or
|
||||||
|
`type_id<void>()` if the container is empty.<br/>
|
||||||
|
The type is also used internally when comparing two `any` objects:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if(any == empty) { /* ... */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, before proceeding with a comparison, it's verified that the _type_
|
||||||
|
of the two objects is actually the same.<br/>
|
||||||
|
Refer to the `EnTT` type system documentation for more details about how
|
||||||
|
`type_info` works and the possible risks of a comparison.
|
||||||
|
|
||||||
|
A particularly interesting feature of this class is that it can also be used as
|
||||||
|
an opaque container for const and non-const references:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int value = 42;
|
||||||
|
|
||||||
|
entt::any any{std::in_place_type<int &>(value)};
|
||||||
|
entt::any cany = entt::make_any<const int &>(value);
|
||||||
|
entt::any fwd = entt::forward_as_any(value);
|
||||||
|
|
||||||
|
any.emplace<const int &>(value);
|
||||||
|
```
|
||||||
|
|
||||||
|
In other words, whenever `any` is explicitly told to construct an _alias_, it
|
||||||
|
acts as a pointer to the original instance rather than making a copy of it or
|
||||||
|
moving it internally. The contained object is never destroyed and users must
|
||||||
|
ensure that its lifetime exceeds that of the container.<br/>
|
||||||
|
Similarly, it's possible to create non-owning copies of `any` from an existing
|
||||||
|
object:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// aliasing constructor
|
||||||
|
entt::any ref = other.as_ref();
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, it doesn't matter if the original container actually holds an
|
||||||
|
object or is as a reference for unmanaged elements already. The new instance
|
||||||
|
thus created doesn't create copies and only serves as a reference for the
|
||||||
|
original item.
|
||||||
|
|
||||||
|
It's worth mentioning that, while everything works transparently when it comes
|
||||||
|
to non-const references, there are some exceptions when it comes to const
|
||||||
|
references.<br/>
|
||||||
|
In particular, the `data` member function invoked on a non-const instance of
|
||||||
|
`any` that wraps a const reference returns a null pointer in all cases.
|
||||||
|
|
||||||
|
To cast an instance of `any` to a type, the library offers a set of `any_cast`
|
||||||
|
functions in all respects similar to their most famous counterparts.<br/>
|
||||||
|
The only difference is that, in the case of `EnTT`, they won't raise exceptions
|
||||||
|
but will only trigger an assert in debug mode, otherwise resulting in undefined
|
||||||
|
behavior in case of misuse in release mode.
|
||||||
|
|
||||||
|
## Small buffer optimization
|
||||||
|
|
||||||
|
The `any` class uses a technique called _small buffer optimization_ to reduce
|
||||||
|
the number of allocations where possible.<br/>
|
||||||
|
The default reserved size for an instance of `any` is `sizeof(double[2])`.
|
||||||
|
However, this is also configurable if needed. In fact, `any` is defined as an
|
||||||
|
alias for `basic_any<Len>`, where `Len` is the size above.<br/>
|
||||||
|
Users can easily set a custom size or define their own aliases:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using my_any = entt::basic_any<sizeof(double[4])>;
|
||||||
|
```
|
||||||
|
|
||||||
|
This feature, in addition to allowing the choice of a size that best suits the
|
||||||
|
needs of an application, also offers the possibility of forcing dynamic creation
|
||||||
|
of objects during construction.<br/>
|
||||||
|
In other terms, if the size is 0, `any` suppresses the small buffer optimization
|
||||||
|
and always dynamically allocates objects (except for aliasing cases).
|
||||||
|
|
||||||
|
## Alignment requirement
|
||||||
|
|
||||||
|
The alignment requirement is optional and by default the most stringent (the
|
||||||
|
largest) for any object whose size is at most equal to the one provided.<br/>
|
||||||
|
It's provided as an optional second parameter following the desired size for the
|
||||||
|
internal storage:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using my_any = entt::basic_any<sizeof(double[4]), alignof(double[4])>;
|
||||||
|
```
|
||||||
|
|
||||||
|
The `basic_any` class template inspects the alignment requirements in each case,
|
||||||
|
even when not provided and may decide not to use the small buffer optimization
|
||||||
|
in order to meet them.
|
||||||
|
|
||||||
|
# Compressed pair
|
||||||
|
|
||||||
|
Primarily designed for internal use and far from being feature complete, the
|
||||||
|
`compressed_pair` class does exactly what it promises: it tries to reduce the
|
||||||
|
size of a pair by exploiting _Empty Base Class Optimization_ (or _EBCO_).<br/>
|
||||||
|
This class **is not** a drop-in replacement for `std::pair`. However, it offers
|
||||||
|
enough functionalities to be a good alternative for when reducing memory usage
|
||||||
|
is more important than having some cool and probably useless feature.
|
||||||
|
|
||||||
|
Although the API is very close to that of `std::pair` (apart from the fact that
|
||||||
|
the template parameters are inferred from the constructor and therefore there is
|
||||||
|
no `entt::make_compressed_pair`), the major difference is that `first` and
|
||||||
|
`second` are functions for implementation requirements:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::compressed_pair pair{0, 3.};
|
||||||
|
pair.first() = 42;
|
||||||
|
```
|
||||||
|
|
||||||
|
There isn't much to describe then. It's recommended to rely on documentation and
|
||||||
|
intuition. At the end of the day, it's just a pair and nothing more.
|
||||||
|
|
||||||
|
# Enum as bitmask
|
||||||
|
|
||||||
|
Sometimes it's useful to be able to use enums as bitmasks. However, enum classes
|
||||||
|
aren't really suitable for the purpose. Main problem is that they don't convert
|
||||||
|
implicitly to their underlying type.<br/>
|
||||||
|
The choice is then between using old-fashioned enums (with all their problems
|
||||||
|
that I don't want to discuss here) or writing _ugly_ code.
|
||||||
|
|
||||||
|
Fortunately, there is also a third way: adding enough operators in the global
|
||||||
|
scope to treat enum classes as bitmasks transparently.<br/>
|
||||||
|
The ultimate goal is to write code like the following (or maybe something more
|
||||||
|
meaningful, but this should give a grasp and remain simple at the same time):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum class my_flag {
|
||||||
|
unknown = 0x01,
|
||||||
|
enabled = 0x02,
|
||||||
|
disabled = 0x04
|
||||||
|
};
|
||||||
|
|
||||||
|
const my_flag flags = my_flag::enabled;
|
||||||
|
const bool is_enabled = !!(flags & my_flag::enabled);
|
||||||
|
```
|
||||||
|
|
||||||
|
The problem with adding all operators to the global scope is that these come
|
||||||
|
into play even when not required, with the risk of introducing errors that are
|
||||||
|
difficult to deal with.<br/>
|
||||||
|
However, C++ offers enough tools to get around this problem. In particular, the
|
||||||
|
library requires users to register the enum classes for which bitmask support
|
||||||
|
should be enabled:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<>
|
||||||
|
struct entt::enum_as_bitmask<my_flag>
|
||||||
|
: std::true_type
|
||||||
|
{};
|
||||||
|
```
|
||||||
|
|
||||||
|
This is handy when dealing with enum classes defined by third party libraries
|
||||||
|
and over which the user has no control. However, it's also verbose and can be
|
||||||
|
avoided by adding a specific value to the enum class itself:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum class my_flag {
|
||||||
|
unknown = 0x01,
|
||||||
|
enabled = 0x02,
|
||||||
|
disabled = 0x04,
|
||||||
|
_entt_enum_as_bitmask
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, there is no need to specialize the `enum_as_bitmask` traits, since
|
||||||
|
`EnTT` automatically detects the flag and enables the bitmask support.<br/>
|
||||||
|
Once the enum class is registered (in one way or the other), the most common
|
||||||
|
operators such as `&`, `|` but also `&=` and `|=` are available for use.
|
||||||
|
|
||||||
|
Refer to the official documentation for the full list of operators.
|
||||||
|
|
||||||
|
# Hashed strings
|
||||||
|
|
||||||
|
Hashed strings are human-readable identifiers in the codebase that turn into
|
||||||
|
numeric values at runtime, thus without affecting performance.<br/>
|
||||||
|
The class has an implicit `constexpr` constructor that chews a bunch of
|
||||||
|
characters. Once created, one can get the original string by means of the `data`
|
||||||
|
member function or convert the instance into a number.<br/>
|
||||||
|
A hashed string is well suited wherever a constant expression is required. No
|
||||||
|
_string-to-number_ conversion will take place at runtime if used carefully.
|
||||||
|
|
||||||
|
Example of use:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto load(entt::hashed_string::hash_type resource) {
|
||||||
|
// uses the numeric representation of the resource to load and return it
|
||||||
|
}
|
||||||
|
|
||||||
|
auto resource = load(entt::hashed_string{"gui/background"});
|
||||||
|
```
|
||||||
|
|
||||||
|
There is also a _user defined literal_ dedicated to hashed strings to make them
|
||||||
|
more _user-friendly_:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace entt::literals;
|
||||||
|
constexpr auto str = "text"_hs;
|
||||||
|
```
|
||||||
|
|
||||||
|
User defined literals in `EnTT` are enclosed in the `entt::literals` namespace.
|
||||||
|
Therefore, the entire namespace or selectively the literal of interest must be
|
||||||
|
explicitly included before each use, a bit like `std::literals`.<br/>
|
||||||
|
The class also offers the necessary functionalities to create hashed strings at
|
||||||
|
runtime:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::string orig{"text"};
|
||||||
|
|
||||||
|
// create a full-featured hashed string...
|
||||||
|
entt::hashed_string str{orig.c_str()};
|
||||||
|
|
||||||
|
// ... or compute only the unique identifier
|
||||||
|
const auto hash = entt::hashed_string::value(orig.c_str());
|
||||||
|
```
|
||||||
|
|
||||||
|
This possibility shouldn't be exploited in tight loops, since the computation
|
||||||
|
takes place at runtime and no longer at compile-time. It could therefore affect
|
||||||
|
performance to some degrees.
|
||||||
|
|
||||||
|
## Wide characters
|
||||||
|
|
||||||
|
The `hashed_string` class is an alias for `basic_hashed_string<char>`. To use
|
||||||
|
the C++ type for wide character representations, there exists also the alias
|
||||||
|
`hashed_wstring` for `basic_hashed_string<wchar_t>`.<br/>
|
||||||
|
In this case, the user defined literal to use to create hashed strings on the
|
||||||
|
fly is `_hws`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr auto str = L"text"_hws;
|
||||||
|
```
|
||||||
|
|
||||||
|
The hash type of `hashed_wstring` is the same as its counterpart.
|
||||||
|
|
||||||
|
## Conflicts
|
||||||
|
|
||||||
|
The hashed string class uses FNV-1a internally to hash strings. Because of the
|
||||||
|
_pigeonhole principle_, conflicts are possible. This is a fact.<br/>
|
||||||
|
There is no silver bullet to solve the problem of conflicts when dealing with
|
||||||
|
hashing functions. In this case, the best solution is likely to give up. That's
|
||||||
|
all.<br/>
|
||||||
|
After all, human-readable unique identifiers aren't something strictly defined
|
||||||
|
and over which users have not the control. Choosing a slightly different
|
||||||
|
identifier is probably the best solution to make the conflict disappear in this
|
||||||
|
case.
|
||||||
|
|
||||||
|
# Iterators
|
||||||
|
|
||||||
|
Writing and working with iterators isn't always easy. More often than not it
|
||||||
|
also leads to duplicated code.<br/>
|
||||||
|
`EnTT` tries to overcome this problem by offering some utilities designed to
|
||||||
|
make this hard work easier.
|
||||||
|
|
||||||
|
## Input iterator pointer
|
||||||
|
|
||||||
|
When writing an input iterator that returns in-place constructed values if
|
||||||
|
dereferenced, it's not always straightforward to figure out what `value_type` is
|
||||||
|
and how to make it behave like a full-fledged pointer.<br/>
|
||||||
|
Conversely, it would be very useful to have an `operator->` available on the
|
||||||
|
iterator itself that always works without too much complexity.
|
||||||
|
|
||||||
|
The input iterator pointer is meant for this. It's a small class that wraps the
|
||||||
|
in-place constructed value and adds some functions on top of it to make it
|
||||||
|
suitable for use with input iterators:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct iterator_type {
|
||||||
|
using value_type = std::pair<first_type, second_type>;
|
||||||
|
using pointer = input_iterator_pointer<value_type>;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The library makes extensive use of this class internally. In many cases, the
|
||||||
|
`value_type` of the returned iterators is just an input iterator pointer.
|
||||||
|
|
||||||
|
## Iota iterator
|
||||||
|
|
||||||
|
Waiting for C++20, this iterator accepts an integral value and returns all
|
||||||
|
elements in a certain range:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::iota_iterator first{0};
|
||||||
|
entt::iota_iterator last{100};
|
||||||
|
|
||||||
|
for(; first != last; ++first) {
|
||||||
|
int value = *first;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the future, views will replace this class. Meanwhile, the library makes some
|
||||||
|
interesting uses of it when a range of integral values is to be returned to the
|
||||||
|
user.
|
||||||
|
|
||||||
|
## Iterable adaptor
|
||||||
|
|
||||||
|
Typically, a container class provides `begin` and `end` member functions (with
|
||||||
|
their const counterparts) for iteration.<br/>
|
||||||
|
However, it can happen that a class offers multiple iteration methods or allows
|
||||||
|
users to iterate different sets of _elements_.
|
||||||
|
|
||||||
|
The iterable adaptor is a utility class that makes it easier to use and access
|
||||||
|
data in this case.<br/>
|
||||||
|
It accepts a couple of iterators (or an iterator and a sentinel) and offers an
|
||||||
|
_iterable_ object with all the expected methods like `begin`, `end` and whatnot.
|
||||||
|
|
||||||
|
The library uses this class extensively.<br/>
|
||||||
|
Think for example of views, which can be iterated to access entities but also
|
||||||
|
offer a method of obtaining an iterable object that returns tuples of entities
|
||||||
|
and components at once.<br/>
|
||||||
|
Another example is the registry class which allows users to iterate its storage
|
||||||
|
by returning an iterable object for the purpose.
|
||||||
|
|
||||||
|
# Memory
|
||||||
|
|
||||||
|
There are a handful of tools within `EnTT` to interact with memory in one way or
|
||||||
|
another.<br/>
|
||||||
|
Some are geared towards simplifying the implementation of (internal or external)
|
||||||
|
allocator aware containers. Others are designed to help the developer with
|
||||||
|
everyday problems.
|
||||||
|
|
||||||
|
The former are very specific and for niche problems. These are tools designed to
|
||||||
|
unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of
|
||||||
|
acronyms like _POCCA_, _POCMA_ or _POCS_.<br/>
|
||||||
|
I won't describe them here in detail. Instead, I recommend reading the inline
|
||||||
|
documentation to those interested in the subject.
|
||||||
|
|
||||||
|
## Power of two and fast modulus
|
||||||
|
|
||||||
|
Finding out if a number is a power of two (`is_power_of_two`) or what the next
|
||||||
|
power of two is given a random value (`next_power_of_two`) is very useful at
|
||||||
|
times.<br/>
|
||||||
|
For example, it helps to allocate memory in pages having a size suitable for the
|
||||||
|
fast modulus:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const std::size_t result = entt::fast_mod(value, modulus);
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `modulus` is necessarily a power of two. Perhaps not everyone knows that
|
||||||
|
this type of operation is far superior in terms of performance to the basic
|
||||||
|
modulus and for this reason preferred in many areas.
|
||||||
|
|
||||||
|
## Allocator aware unique pointers
|
||||||
|
|
||||||
|
A nasty thing in C++ (at least up to C++20) is the fact that shared pointers
|
||||||
|
support allocators while unique pointers don't.<br/>
|
||||||
|
There is a proposal at the moment that also shows (among the other things) how
|
||||||
|
this can be implemented without any compiler support.
|
||||||
|
|
||||||
|
The `allocate_unique` function follows this proposal, making a virtue out of
|
||||||
|
necessity:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::unique_ptr<my_type, entt::allocation_deleter<my_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments);
|
||||||
|
```
|
||||||
|
|
||||||
|
Although the internal implementation is slightly different from what is proposed
|
||||||
|
for the standard, this function offers an API that is a drop-in replacement for
|
||||||
|
the same feature.
|
||||||
|
|
||||||
|
# Monostate
|
||||||
|
|
||||||
|
The monostate pattern is often presented as an alternative to a singleton based
|
||||||
|
configuration system.<br/>
|
||||||
|
This is exactly its purpose in `EnTT`. Moreover, this implementation is thread
|
||||||
|
safe by design (hopefully).
|
||||||
|
|
||||||
|
Keys are integral values (easily obtained by hashed strings), values are basic
|
||||||
|
types like `int`s or `bool`s. Values of different types can be associated with
|
||||||
|
each key, even more than one at a time.<br/>
|
||||||
|
Because of this, one should pay attention to use the same type both during an
|
||||||
|
assignment and when trying to read back the data. Otherwise, there is the risk
|
||||||
|
to incur in unexpected results.
|
||||||
|
|
||||||
|
Example of use:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::monostate<entt::hashed_string{"mykey"}>{} = true;
|
||||||
|
entt::monostate<"mykey"_hs>{} = 42;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
const bool b = entt::monostate<"mykey"_hs>{};
|
||||||
|
const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
|
||||||
|
```
|
||||||
|
|
||||||
|
# Type support
|
||||||
|
|
||||||
|
`EnTT` provides some basic information about types of all kinds.<br/>
|
||||||
|
It also offers additional features that are not yet available in the standard
|
||||||
|
library or that will never be.
|
||||||
|
|
||||||
|
## Built-in RTTI support
|
||||||
|
|
||||||
|
Runtime type identification support (or RTTI) is one of the most frequently
|
||||||
|
disabled features in the C++ world, especially in the gaming sector. Regardless
|
||||||
|
of the reasons for this, it's often a shame not to be able to rely on opaque
|
||||||
|
type information at runtime.<br/>
|
||||||
|
The library tries to fill this gap by offering a built-in system that doesn't
|
||||||
|
serve as a replacement but comes very close to being one and offers similar
|
||||||
|
information to that provided by its counterpart.
|
||||||
|
|
||||||
|
Basically, the whole system relies on a handful of classes. In particular:
|
||||||
|
|
||||||
|
* The unique sequential identifier associated with a given type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto index = entt::type_index<a_type>::value();
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned value isn't guaranteed to be stable across different runs.<br/>
|
||||||
|
However, it can be very useful as index in associative and unordered
|
||||||
|
associative containers or for positional accesses in a vector or an array.
|
||||||
|
|
||||||
|
An external generator can also be used if needed. In fact, `type_index` can be
|
||||||
|
specialized by type and is also _sfinae-friendly_ in order to allow more
|
||||||
|
refined specializations such as:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename Type>
|
||||||
|
struct entt::type_index<Type, std::void_d<decltype(Type::index())>> {
|
||||||
|
static entt::id_type value() noexcept {
|
||||||
|
return Type::index();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Indexes **must** be sequentially generated in this case.<br/>
|
||||||
|
The tool is widely used within `EnTT`. Generating indices not sequentially
|
||||||
|
would break an assumption and would likely lead to undesired behaviors.
|
||||||
|
|
||||||
|
* The hash value associated with a given type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto hash = entt::type_hash<a_type>::value();
|
||||||
|
```
|
||||||
|
|
||||||
|
In general, the `value` function exposed by `type_hash` is also `constexpr`
|
||||||
|
but this isn't guaranteed for all compilers and platforms (although it's valid
|
||||||
|
with the most well-known and popular ones).
|
||||||
|
|
||||||
|
This function **can** use non-standard features of the language for its own
|
||||||
|
purposes. This makes it possible to provide compile-time identifiers that
|
||||||
|
remain stable across different runs.<br/>
|
||||||
|
Users can prevent the library from using these features by means of the
|
||||||
|
`ENTT_STANDARD_CPP` definition. In this case, there is no guarantee that
|
||||||
|
identifiers remain stable across executions. Moreover, they are generated
|
||||||
|
at runtime and are no longer a compile-time thing.
|
||||||
|
|
||||||
|
As it happens with `type_index`, also `type_hash` is a _sfinae-friendly_ class
|
||||||
|
that can be specialized in order to customize its behavior globally or on a
|
||||||
|
per-type or per-traits basis.
|
||||||
|
|
||||||
|
* The name associated with a given type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto name = entt::type_name<a_type>::value();
|
||||||
|
```
|
||||||
|
|
||||||
|
This value is extracted from some information generally made available by the
|
||||||
|
compiler in use. Therefore, it may differ depending on the compiler and may be
|
||||||
|
empty in the event that this information isn't available.<br/>
|
||||||
|
For example, given the following class:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_type { /* ... */ };
|
||||||
|
```
|
||||||
|
|
||||||
|
The name is `my_type` when compiled with GCC or CLang and `struct my_type`
|
||||||
|
when MSVC is in use.<br/>
|
||||||
|
Most of the time the name is also retrieved at compile-time and is therefore
|
||||||
|
always returned through an `std::string_view`. Users can easily access it and
|
||||||
|
modify it as needed, for example by removing the word `struct` to normalize
|
||||||
|
the result. `EnTT` doesn't do this for obvious reasons, since it would be
|
||||||
|
creating a new string at runtime otherwise.
|
||||||
|
|
||||||
|
This function **can** use non-standard features of the language for its own
|
||||||
|
purposes. Users can prevent the library from using these features by means of
|
||||||
|
the `ENTT_STANDARD_CPP` definition. In this case, the name is just empty.
|
||||||
|
|
||||||
|
As it happens with `type_index`, also `type_name` is a _sfinae-friendly_ class
|
||||||
|
that can be specialized in order to customize its behavior globally or on a
|
||||||
|
per-type or per-traits basis.
|
||||||
|
|
||||||
|
These are then combined into utilities that aim to offer an API that is somewhat
|
||||||
|
similar to that made available by the standard library.
|
||||||
|
|
||||||
|
### Type info
|
||||||
|
|
||||||
|
The `type_info` class isn't a drop-in replacement for `std::type_info` but can
|
||||||
|
provide similar information which are not implementation defined and don't
|
||||||
|
require to enable RTTI.<br/>
|
||||||
|
Therefore, they can sometimes be even more reliable than those obtained
|
||||||
|
otherwise.
|
||||||
|
|
||||||
|
Its type defines an opaque class that is also copyable and movable.<br/>
|
||||||
|
Objects of this type are generally returned by the `type_id` functions:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// by type
|
||||||
|
auto info = entt::type_id<a_type>();
|
||||||
|
|
||||||
|
// by value
|
||||||
|
auto other = entt::type_id(42);
|
||||||
|
```
|
||||||
|
|
||||||
|
All elements thus received are nothing more than const references to instances
|
||||||
|
of `type_info` with static storage duration.<br/>
|
||||||
|
This is convenient for saving the entire object aside for the cost of a pointer.
|
||||||
|
However, nothing prevents from constructing `type_info` objects directly:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::type_info info{std::in_place_type<int>};
|
||||||
|
```
|
||||||
|
|
||||||
|
These are the information made available by `type_info`:
|
||||||
|
|
||||||
|
* The index associated with a given type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto idx = entt::type_id<a_type>().index();
|
||||||
|
```
|
||||||
|
|
||||||
|
This is also an alias for the following:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto idx = entt::type_index<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||||
|
```
|
||||||
|
|
||||||
|
* The hash value associated with a given type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto hash = entt::type_id<a_type>().hash();
|
||||||
|
```
|
||||||
|
|
||||||
|
This is also an alias for the following:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto hash = entt::type_hash<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||||
|
```
|
||||||
|
|
||||||
|
* The name associated with a given type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto name = entt::type_id<my_type>().name();
|
||||||
|
```
|
||||||
|
|
||||||
|
This is also an alias for the following:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto name = entt::type_name<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||||
|
```
|
||||||
|
|
||||||
|
Where all accessed features are available at compile-time, the `type_info` class
|
||||||
|
is also fully `constexpr`. However, this cannot be guaranteed in advance and
|
||||||
|
depends mainly on the compiler in use and any specializations of the classes
|
||||||
|
described above.
|
||||||
|
|
||||||
|
### Almost unique identifiers
|
||||||
|
|
||||||
|
Since the default non-standard, compile-time implementation of `type_hash` makes
|
||||||
|
use of hashed strings, it may happen that two types are assigned the same hash
|
||||||
|
value.<br/>
|
||||||
|
In fact, although this is quite rare, it's not entirely excluded.
|
||||||
|
|
||||||
|
Another case where two types are assigned the same identifier is when classes
|
||||||
|
from different contexts (for example two or more libraries loaded at runtime)
|
||||||
|
have the same fully qualified name. In this case, `type_name` returns the same
|
||||||
|
value for the two types.<br/>
|
||||||
|
Fortunately, there are several easy ways to deal with this:
|
||||||
|
|
||||||
|
* The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime
|
||||||
|
identifiers don't suffer from the same problem in fact. However, this solution
|
||||||
|
doesn't work well with a plugin system, where the libraries aren't linked.
|
||||||
|
|
||||||
|
* Another possibility is to specialize the `type_name` class for one of the
|
||||||
|
conflicting types, in order to assign it a custom identifier. This is probably
|
||||||
|
the easiest solution that also preserves the feature of the tool.
|
||||||
|
|
||||||
|
* A fully customized identifier generation policy (based for example on enum
|
||||||
|
classes or preprocessing steps) may represent yet another option.
|
||||||
|
|
||||||
|
These are just some examples of possible approaches to the problem but there are
|
||||||
|
many others. As already mentioned above, since users have full control over
|
||||||
|
their types, this problem is in any case easy to solve and should not worry too
|
||||||
|
much.<br/>
|
||||||
|
In all likelihood, it will never happen to run into a conflict anyway.
|
||||||
|
|
||||||
|
## Type traits
|
||||||
|
|
||||||
|
A handful of utilities and traits not present in the standard template library
|
||||||
|
but which can be useful in everyday life.<br/>
|
||||||
|
This list **is not** exhaustive and contains only some of the most useful
|
||||||
|
classes. Refer to the inline documentation for more information on the features
|
||||||
|
offered by this module.
|
||||||
|
|
||||||
|
### Size of
|
||||||
|
|
||||||
|
The standard operator `sizeof` complains if users provide it with functions or
|
||||||
|
incomplete types. On the other hand, it's guaranteed that its result is always
|
||||||
|
non-zero, even if applied to an empty class type.<br/>
|
||||||
|
This small class combines the two and offers an alternative to `sizeof` that
|
||||||
|
works under all circumstances, returning zero if the type isn't supported:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const auto size = entt::size_of_v<void>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Is applicable
|
||||||
|
|
||||||
|
The standard library offers the great `std::is_invocable` trait in several
|
||||||
|
forms. This takes a function type and a series of arguments and returns true if
|
||||||
|
the condition is satisfied.<br/>
|
||||||
|
Moreover, users are also provided with `std::apply`, a tool for combining
|
||||||
|
invocable elements and tuples of arguments.
|
||||||
|
|
||||||
|
It would therefore be a good idea to have a variant of `std::is_invocable` that
|
||||||
|
also accepts its arguments in the form of a tuple-like type, so as to complete
|
||||||
|
the offer:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr bool result = entt::is_applicable<Func, std::tuple<a_type, another_type>>;
|
||||||
|
```
|
||||||
|
|
||||||
|
This trait is built on top of `std::is_invocable` and does nothing but unpack a
|
||||||
|
tuple-like type and simplify the code at the call site.
|
||||||
|
|
||||||
|
### Constness as
|
||||||
|
|
||||||
|
A utility to easily transfer the constness of a type to another type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// type is const dst_type because of the constness of src_type
|
||||||
|
using type = entt::constness_as_t<dst_type, const src_type>;
|
||||||
|
```
|
||||||
|
|
||||||
|
The trait is subject to the rules of the language. For example, _transferring_
|
||||||
|
constness between references won't give the desired effect.
|
||||||
|
|
||||||
|
### Member class type
|
||||||
|
|
||||||
|
The `auto` template parameter introduced with C++17 made it possible to simplify
|
||||||
|
many class templates and template functions but also made the class type opaque
|
||||||
|
when members are passed as template arguments.<br/>
|
||||||
|
The purpose of this utility is to extract the class type in a few lines of code:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename Member>
|
||||||
|
using clazz = entt::member_class_t<Member>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### N-th argument
|
||||||
|
|
||||||
|
A utility to quickly find the n-th argument of a function, member function or
|
||||||
|
data member (for blind operations on opaque types):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using type = entt::nth_argument_t<1u, &clazz::member>;
|
||||||
|
```
|
||||||
|
|
||||||
|
Disambiguation of overloaded functions is the responsibility of the user, should
|
||||||
|
it be needed.
|
||||||
|
|
||||||
|
### Integral constant
|
||||||
|
|
||||||
|
Since `std::integral_constant` may be annoying because of its form that requires
|
||||||
|
to specify both a type and a value of that type, there is a more user-friendly
|
||||||
|
shortcut for the creation of integral constants.<br/>
|
||||||
|
This shortcut is the alias template `entt::integral_constant`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr auto constant = entt::integral_constant<42>;
|
||||||
|
```
|
||||||
|
|
||||||
|
Among the other uses, when combined with a hashed string it helps to define tags
|
||||||
|
as human-readable _names_ where actual types would be required otherwise:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr auto enemy_tag = entt::integral_constant<"enemy"_hs>;
|
||||||
|
registry.emplace<enemy_tag>(entity);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tag
|
||||||
|
|
||||||
|
Type `id_type` is very important and widely used in `EnTT`. Therefore, there is
|
||||||
|
a more user-friendly shortcut for the creation of constants based on it.<br/>
|
||||||
|
This shortcut is the alias template `entt::tag`.
|
||||||
|
|
||||||
|
If used in combination with hashed strings, it helps to use human-readable names
|
||||||
|
where types would be required otherwise. As an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
registry.emplace<entt::tag<"enemy"_hs>>(entity);
|
||||||
|
```
|
||||||
|
|
||||||
|
However, this isn't the only permitted use. Literally any value convertible to
|
||||||
|
`id_type` is a good candidate, such as the named constants of an unscoped enum.
|
||||||
|
|
||||||
|
### Type list and value list
|
||||||
|
|
||||||
|
There is no respectable library where the much desired _type list_ can be
|
||||||
|
missing.<br/>
|
||||||
|
`EnTT` is no exception and provides (making extensive use of it internally) the
|
||||||
|
`type_list` type, in addition to its `value_list` counterpart dedicated to
|
||||||
|
non-type template parameters.
|
||||||
|
|
||||||
|
Here is a (possibly incomplete) list of the functionalities that come with a
|
||||||
|
type list:
|
||||||
|
|
||||||
|
* `type_list_element[_t]` to get the N-th element of a type list.
|
||||||
|
* `type_list_index[_v]` to get the index of a given element of a type list.
|
||||||
|
* `type_list_cat[_t]` and a handy `operator+` to concatenate type lists.
|
||||||
|
* `type_list_unique[_t]` to remove duplicate types from a type list.
|
||||||
|
* `type_list_contains[_v]` to know if a type list contains a given type.
|
||||||
|
* `type_list_diff[_t]` to remove types from type lists.
|
||||||
|
* `type_list_transform[_t]` to _transform_ a range and create another type list.
|
||||||
|
|
||||||
|
I'm also pretty sure that more and more utilities will be added over time as
|
||||||
|
needs become apparent.<br/>
|
||||||
|
Many of these functionalities also exist in their version dedicated to value
|
||||||
|
lists. We therefore have `value_list_element[_v]` as well as
|
||||||
|
`value_list_cat[_t]`and so on.
|
||||||
|
|
||||||
|
# Unique sequential identifiers
|
||||||
|
|
||||||
|
Sometimes it's useful to be able to give unique, sequential numeric identifiers
|
||||||
|
to types either at compile-time or runtime.<br/>
|
||||||
|
There are plenty of different solutions for this out there and I could have used
|
||||||
|
one of them. However, I decided to spend my time to define a couple of tools
|
||||||
|
that fully embraces what the modern C++ has to offer.
|
||||||
|
|
||||||
|
## Compile-time generator
|
||||||
|
|
||||||
|
To generate sequential numeric identifiers at compile-time, `EnTT` offers the
|
||||||
|
`ident` class template:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// defines the identifiers for the given types
|
||||||
|
using id = entt::ident<a_type, another_type>;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
switch(a_type_identifier) {
|
||||||
|
case id::value<a_type>:
|
||||||
|
// ...
|
||||||
|
break;
|
||||||
|
case id::value<another_type>:
|
||||||
|
// ...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is what this class template has to offer: a `value` inline variable that
|
||||||
|
contains a numeric identifier for the given type. It can be used in any context
|
||||||
|
where constant expressions are required.
|
||||||
|
|
||||||
|
As long as the list remains unchanged, identifiers are also guaranteed to be
|
||||||
|
stable across different runs. In case they have been used in a production
|
||||||
|
environment and a type has to be removed, one can just use a placeholder to
|
||||||
|
leave the other identifiers unchanged:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename> struct ignore_type {};
|
||||||
|
|
||||||
|
using id = entt::ident<
|
||||||
|
a_type_still_valid,
|
||||||
|
ignore_type<no_longer_valid_type>,
|
||||||
|
another_type_still_valid
|
||||||
|
>;
|
||||||
|
```
|
||||||
|
|
||||||
|
Perhaps a bit ugly to see in a codebase but it gets the job done at least.
|
||||||
|
|
||||||
|
## Runtime generator
|
||||||
|
|
||||||
|
The `family` class template helps to generate sequential numeric identifiers for
|
||||||
|
types at runtime:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// defines a custom generator
|
||||||
|
using id = entt::family<struct my_tag>;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
const auto a_type_id = id::value<a_type>;
|
||||||
|
const auto another_type_id = id::value<another_type>;
|
||||||
|
```
|
||||||
|
|
||||||
|
This is what a _family_ has to offer: a `value` inline variable that contains a
|
||||||
|
numeric identifier for the given type.<br/>
|
||||||
|
The generator is customizable, so as to get different _sequences_ for different
|
||||||
|
purposes if needed.
|
||||||
|
|
||||||
|
Identifiers aren't guaranteed to be stable across different runs. Indeed it
|
||||||
|
mostly depends on the flow of execution.
|
||||||
|
|
||||||
|
# Utilities
|
||||||
|
|
||||||
|
It's not possible to escape the temptation to add utilities of some kind to a
|
||||||
|
library. In fact, `EnTT` also provides a handful of tools to simplify the
|
||||||
|
life of developers:
|
||||||
|
|
||||||
|
* `entt::identity`: the identity function object that will be available with
|
||||||
|
C++20. It returns its argument unchanged and nothing more. It's useful as a
|
||||||
|
sort of _do nothing_ function in template programming.
|
||||||
|
|
||||||
|
* `entt::overload`: a tool to disambiguate different overloads from their
|
||||||
|
function type. It works with both free and member functions.<br/>
|
||||||
|
Consider the following definition:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct clazz {
|
||||||
|
void bar(int) {}
|
||||||
|
void bar() {}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
This utility can be used to get the _right_ overload as:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto *member = entt::overload<void(int)>(&clazz::bar);
|
||||||
|
```
|
||||||
|
|
||||||
|
The line above is literally equivalent to:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto *member = static_cast<void(clazz:: *)(int)>(&clazz::bar);
|
||||||
|
```
|
||||||
|
|
||||||
|
Just easier to read and shorter to type.
|
||||||
|
|
||||||
|
* `entt::overloaded`: a small class template used to create a new type with an
|
||||||
|
overloaded `operator()` from a bunch of lambdas or functors.<br/>
|
||||||
|
As an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::overloaded func{
|
||||||
|
[](int value) { /* ... */ },
|
||||||
|
[](char value) { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
func(42);
|
||||||
|
func('c');
|
||||||
|
```
|
||||||
|
|
||||||
|
Rather useful when doing metaprogramming and having to pass to a function a
|
||||||
|
callable object that supports multiple types at once.
|
||||||
|
|
||||||
|
* `entt::y_combinator`: this is a C++ implementation of **the** _y-combinator_.
|
||||||
|
If it's not clear what it is, there is probably no need for this utility.<br/>
|
||||||
|
Below is a small example to show its use:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::y_combinator gauss([](const auto &self, auto value) -> unsigned int {
|
||||||
|
return value ? (value + self(value-1u)) : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto result = gauss(3u);
|
||||||
|
```
|
||||||
|
|
||||||
|
Maybe convoluted at a first glance but certainly effective. Unfortunately,
|
||||||
|
the language doesn't make it possible to do much better.
|
||||||
|
|
||||||
|
This is a rundown of the (actually few) utilities made available by `EnTT`. The
|
||||||
|
list will probably grow over time but the size of each will remain rather small,
|
||||||
|
as has been the case so far.
|
2344
external/entt/entt/docs/md/entity.md
vendored
Normal file
215
external/entt/entt/docs/md/faq.md
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
# Frequently Asked Questions
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [FAQ](#faq)
|
||||||
|
* [Why is my debug build on Windows so slow?](#why-is-my-debug-build-on-windows-so-slow)
|
||||||
|
* [How can I represent hierarchies with my components?](#how-can-i-represent-hierarchies-with-my-components)
|
||||||
|
* [Custom entity identifiers: yay or nay?](#custom-entity-identifiers-yay-or-nay)
|
||||||
|
* [Warning C4307: integral constant overflow](#warning-C4307-integral-constant-overflow)
|
||||||
|
* [Warning C4003: the min, the max and the macro](#warning-C4003-the-min-the-max-and-the-macro)
|
||||||
|
* [The standard and the non-copyable types](#the-standard-and-the-non-copyable-types)
|
||||||
|
* [Which functions trigger which signals](#which-functions-trigger-which-signals)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
This is a constantly updated section where I'm trying to put the answers to the
|
||||||
|
most frequently asked questions.<br/>
|
||||||
|
If you don't find your answer here, there are two cases: nobody has done it yet
|
||||||
|
or this section needs updating. In both cases, you can
|
||||||
|
[open a new issue](https://github.com/skypjack/entt/issues/new) or enter either
|
||||||
|
the [gitter channel](https://gitter.im/skypjack/entt) or the
|
||||||
|
[discord server](https://discord.gg/5BjPWBd) to ask for help.<br/>
|
||||||
|
Probably someone already has an answer for you and we can then integrate this
|
||||||
|
part of the documentation.
|
||||||
|
|
||||||
|
# FAQ
|
||||||
|
|
||||||
|
## Why is my debug build on Windows so slow?
|
||||||
|
|
||||||
|
`EnTT` is an experimental project that I also use to keep me up-to-date with the
|
||||||
|
latest revision of the language and the standard library. For this reason, it's
|
||||||
|
likely that some classes you're working with are using standard containers under
|
||||||
|
the hood.<br/>
|
||||||
|
Unfortunately, it's known that the standard containers aren't particularly
|
||||||
|
performing in debugging (the reasons for this go beyond this document) and are
|
||||||
|
even less so on Windows apparently. Fortunately this can also be mitigated a
|
||||||
|
lot, achieving good results in many cases.
|
||||||
|
|
||||||
|
First of all, there are two things to do in a Windows project:
|
||||||
|
|
||||||
|
* Disable the [`/JMC`](https://docs.microsoft.com/cpp/build/reference/jmc)
|
||||||
|
option (_Just My Code_ debugging), available starting with Visual Studio 2017
|
||||||
|
version 15.8.
|
||||||
|
|
||||||
|
* Set the [`_ITERATOR_DEBUG_LEVEL`](https://docs.microsoft.com/cpp/standard-library/iterator-debug-level)
|
||||||
|
macro to 0. This will disable checked iterators and iterator debugging.
|
||||||
|
|
||||||
|
Moreover, set the `ENTT_DISABLE_ASSERT` variable or redefine the `ENTT_ASSERT`
|
||||||
|
macro to disable internal debug checks in `EnTT`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define ENTT_ASSERT(...) ((void)0)
|
||||||
|
```
|
||||||
|
|
||||||
|
These asserts are introduced to help the users but they require to access to the
|
||||||
|
underlying containers and therefore risk ruining the performance in some cases.
|
||||||
|
|
||||||
|
With these changes, debug performance should increase enough in most cases. If
|
||||||
|
you want something more, you can also switch to an optimization level `O0` or
|
||||||
|
preferably `O1`.
|
||||||
|
|
||||||
|
## How can I represent hierarchies with my components?
|
||||||
|
|
||||||
|
This is one of the first questions that anyone makes when starting to work with
|
||||||
|
the entity-component-system architectural pattern.<br/>
|
||||||
|
There are several approaches to the problem and the best one depends mainly on
|
||||||
|
the real problem one is facing. In all cases, how to do it doesn't strictly
|
||||||
|
depend on the library in use, but the latter certainly allows or not different
|
||||||
|
techniques depending on how the data are laid out.
|
||||||
|
|
||||||
|
I tried to describe some of the approaches that fit well with the model of
|
||||||
|
`EnTT`. [This](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the
|
||||||
|
first post of a series that tries to _explore_ the problem. More will probably
|
||||||
|
come in future.<br/>
|
||||||
|
In addition, `EnTT` also offers the possibility to create stable storage types
|
||||||
|
and therefore have pointer stability for one, all or some components. This is by
|
||||||
|
far the most convenient solution when it comes to creating hierarchies and
|
||||||
|
whatnot. See the documentation for the ECS part of the library and in particular
|
||||||
|
what concerns the `component_traits` class for further details.
|
||||||
|
|
||||||
|
## Custom entity identifiers: yay or nay?
|
||||||
|
|
||||||
|
Custom entity identifiers are definitely a good idea in two cases at least:
|
||||||
|
|
||||||
|
* If `std::uint32_t` isn't large enough for your purposes, since this is the
|
||||||
|
underlying type of `entt::entity`.
|
||||||
|
|
||||||
|
* If you want to avoid conflicts when using multiple registries.
|
||||||
|
|
||||||
|
Identifiers can be defined through enum classes and class types that define an
|
||||||
|
`entity_type` member of type `std::uint32_t` or `std::uint64_t`.<br/>
|
||||||
|
In fact, this is a definition equivalent to that of `entt::entity`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum class entity: std::uint32_t {};
|
||||||
|
```
|
||||||
|
|
||||||
|
There is no limit to the number of identifiers that can be defined.
|
||||||
|
|
||||||
|
## Warning C4307: integral constant overflow
|
||||||
|
|
||||||
|
According to [this](https://github.com/skypjack/entt/issues/121) issue, using a
|
||||||
|
hashed string under VS (toolset v141) could generate a warning.<br/>
|
||||||
|
First of all, I want to reassure you: it's expected and harmless. However, it
|
||||||
|
can be annoying.
|
||||||
|
|
||||||
|
To suppress it and if you don't want to suppress all the other warnings as well,
|
||||||
|
here is a workaround in the form of a macro:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define HS(str) __pragma(warning(suppress:4307)) entt::hashed_string{str}
|
||||||
|
#else
|
||||||
|
#define HS(str) entt::hashed_string{str}
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
With an example of use included:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr auto identifier = HS("my/resource/identifier");
|
||||||
|
```
|
||||||
|
|
||||||
|
Thanks to [huwpascoe](https://github.com/huwpascoe) for the courtesy.
|
||||||
|
|
||||||
|
## Warning C4003: the min, the max and the macro
|
||||||
|
|
||||||
|
On Windows, a header file defines two macros `min` and `max` which may result in
|
||||||
|
conflicts with their counterparts in the standard library and therefore in
|
||||||
|
errors during compilation.
|
||||||
|
|
||||||
|
It's a pretty big problem but fortunately it's not a problem of `EnTT` and there
|
||||||
|
is a fairly simple solution to it.<br/>
|
||||||
|
It consists in defining the `NOMINMAX` macro before including any other header
|
||||||
|
so as to get rid of the extra definitions:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define NOMINMAX
|
||||||
|
```
|
||||||
|
|
||||||
|
Please refer to [this](https://github.com/skypjack/entt/issues/96) issue for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
## The standard and the non-copyable types
|
||||||
|
|
||||||
|
`EnTT` uses internally the trait `std::is_copy_constructible_v` to check if a
|
||||||
|
component is actually copyable. However, this trait doesn't really check whether
|
||||||
|
a type is actually copyable. Instead, it just checks that a suitable copy
|
||||||
|
constructor and copy operator exist.<br/>
|
||||||
|
This can lead to surprising results due to some idiosyncrasies of the standard.
|
||||||
|
|
||||||
|
For example, `std::vector` defines a copy constructor that is conditionally
|
||||||
|
enabled depending on whether the value type is copyable or not. As a result,
|
||||||
|
`std::is_copy_constructible_v` returns true for the following specialization:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct type {
|
||||||
|
std::vector<std::unique_ptr<action>> vec;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
However, the copy constructor is effectively disabled upon specialization.
|
||||||
|
Therefore, trying to assign an instance of this type to an entity may trigger a
|
||||||
|
compilation error.<br/>
|
||||||
|
As a workaround, users can mark the type explicitly as non-copyable. This also
|
||||||
|
suppresses the implicit generation of the move constructor and operator, which
|
||||||
|
will therefore have to be defaulted accordingly:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct type {
|
||||||
|
type(const type &) = delete;
|
||||||
|
type(type &&) = default;
|
||||||
|
|
||||||
|
type & operator=(const type &) = delete;
|
||||||
|
type & operator=(type &&) = default;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<action>> vec;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that aggregate initialization is also disabled as a consequence.<br/>
|
||||||
|
Fortunately, this type of trick is quite rare. The bad news is that there is no
|
||||||
|
way to deal with it at the library level, this being due to the design of the
|
||||||
|
language. On the other hand, the fact that the language itself also offers a way
|
||||||
|
to mitigate the problem makes it manageable.
|
||||||
|
|
||||||
|
## Which functions trigger which signals
|
||||||
|
|
||||||
|
Storage classes offer three _signals_ that are emitted following specific
|
||||||
|
operations. Maybe not everyone knows what these operations are, though.<br/>
|
||||||
|
If this isn't clear, below you can find a _vademecum_ for this purpose:
|
||||||
|
|
||||||
|
* `on_created` is invoked when a component is first added (neither modified nor
|
||||||
|
replaced) to an entity.
|
||||||
|
|
||||||
|
* `on_update` is called whenever an existing component is modified or replaced.
|
||||||
|
|
||||||
|
* `on_destroyed` is called when a component is explicitly or implicitly removed
|
||||||
|
from an entity.
|
||||||
|
|
||||||
|
Among the most controversial functions can be found `emplace_or_replace` and
|
||||||
|
`destroy`. However, following the above rules, it's quite simple to know what
|
||||||
|
will happen.<br/>
|
||||||
|
In the first case, `on_created` is invoked if the entity has not the component,
|
||||||
|
otherwise the latter is replaced and therefore `on_update` is triggered. As for
|
||||||
|
the second case, components are removed from their entities and thus freed when
|
||||||
|
they are recycled. It means that `on_destroyed` is triggered for every component
|
||||||
|
owned by the entity that is destroyed.
|
372
external/entt/entt/docs/md/graph.md
vendored
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
# Crash Course: graph
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Data structures](#data-structures)
|
||||||
|
* [Adjacency matrix](#adjacency-matrix)
|
||||||
|
* [Graphviz dot language](#graphviz-dot-language)
|
||||||
|
* [Flow builder](#flow-builder)
|
||||||
|
* [Tasks and resources](#tasks-and-resources)
|
||||||
|
* [Fake resources and order of execution](#fake-resources-and-order-of-execution)
|
||||||
|
* [Sync points](#sync-points)
|
||||||
|
* [Execution graph](#execution-graph)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
`EnTT` doesn't aim to offer everything one needs to work with graphs. Therefore,
|
||||||
|
anyone looking for this in the _graph_ submodule will be disappointed.<br/>
|
||||||
|
Quite the opposite is true though. This submodule is minimal and contains only
|
||||||
|
the data structures and algorithms strictly necessary for the development of
|
||||||
|
some tools such as the _flow builder_.
|
||||||
|
|
||||||
|
# Data structures
|
||||||
|
|
||||||
|
As anticipated in the introduction, the aim isn't to offer all possible data
|
||||||
|
structures suitable for representing and working with graphs. Many will likely
|
||||||
|
be added or refined over time. However I want to discourage anyone expecting
|
||||||
|
tight scheduling on the subject.<br/>
|
||||||
|
The data structures presented in this section are mainly useful for the
|
||||||
|
development and support of some tools which are also part of the same submodule.
|
||||||
|
|
||||||
|
## Adjacency matrix
|
||||||
|
|
||||||
|
The adjacency matrix is designed to represent either a directed or an undirected
|
||||||
|
graph:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `directed_tag` type _creates_ the graph as directed. There is also an
|
||||||
|
`undirected_tag` counterpart which creates it as undirected.<br/>
|
||||||
|
The interface deviates slightly from the typical double indexing of C and offers
|
||||||
|
an API that is perhaps more familiar to a C++ programmer. Therefore, the access
|
||||||
|
and modification of an element takes place via the `contains`, `insert` and
|
||||||
|
`erase` functions rather than a double call to an `operator[]`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if(adjacency_matrix.contains(0u, 1u)) {
|
||||||
|
adjacency_matrix.erase(0u, 1u);
|
||||||
|
} else {
|
||||||
|
adjacency_matrix.insert(0u, 1u);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Both `insert` and` erase` are _idempotent_ functions which have no effect if the
|
||||||
|
element already exists or has already been deleted.<br/>
|
||||||
|
The first one returns an `std::pair` containing the iterator to the element and
|
||||||
|
a boolean value indicating whether the element was newly inserted or not. The
|
||||||
|
second one returns the number of deleted elements (0 or 1).
|
||||||
|
|
||||||
|
An adjacency matrix is initialized with the number of elements (vertices) when
|
||||||
|
constructing it but can also be resized later using the `resize` function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||||
|
```
|
||||||
|
|
||||||
|
To visit all vertices, the class offers a function named `vertices` that returns
|
||||||
|
an iterable object suitable for the purpose:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto &&vertex: adjacency_matrix.vertices()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The same result is obtained with the following snippet, since the vertices are
|
||||||
|
plain unsigned integral values:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto last = adjacency_matrix.size(), pos = {}; pos < last; ++pos) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
As for visiting the edges, a few functions are available.<br/>
|
||||||
|
When the purpose is to visit all the edges of a given adjacency matrix, the
|
||||||
|
`edges` function returns an iterable object that is used to get them as pairs of
|
||||||
|
vertices:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto [lhs, rhs]: adjacency_matrix.edges()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the goal is to visit all the in- or out-edges of a given vertex instead, the
|
||||||
|
`in_edges` and `out_edges` functions are meant for that:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto [lhs, rhs]: adjacency_matrix.out_edges(3u)) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Both the functions expect the vertex to visit (that is, to return the in- or
|
||||||
|
out-edges for) as an argument.<br/>
|
||||||
|
Finally, the adjacency matrix is an allocator-aware container and offers most of
|
||||||
|
the functionalities one would expect from this type of containers, such as
|
||||||
|
`clear` or 'get_allocator` and so on.
|
||||||
|
|
||||||
|
## Graphviz dot language
|
||||||
|
|
||||||
|
As it's one of the most popular formats, the library offers minimal support for
|
||||||
|
converting a graph to a Graphviz dot snippet.<br/>
|
||||||
|
The simplest way is to pass both an output stream and a graph to the `dot`
|
||||||
|
function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::ostringstream output{};
|
||||||
|
entt::dot(output, adjacency_matrix);
|
||||||
|
```
|
||||||
|
|
||||||
|
It's also possible to provide a callback to which the vertices are passed and
|
||||||
|
which can be used to add (`dot`) properties to the output as needed:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::ostringstream output{};
|
||||||
|
|
||||||
|
entt::dot(output, adjacency_matrix, [](auto &output, auto vertex) {
|
||||||
|
out << "label=\"v\"" << vertex << ",shape=\"box\"";
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This second mode is particularly convenient when the user wants to associate
|
||||||
|
externally managed data to the graph being converted.
|
||||||
|
|
||||||
|
# Flow builder
|
||||||
|
|
||||||
|
A flow builder is used to create execution graphs from tasks and resources.<br/>
|
||||||
|
The implementation is as generic as possible and doesn't bind to any other part
|
||||||
|
of the library.
|
||||||
|
|
||||||
|
This class is designed as a sort of _state machine_ to which a specific task is
|
||||||
|
attached for which the resources accessed in read-only or read-write mode are
|
||||||
|
specified.<br/>
|
||||||
|
Most of the functions in the API also return the flow builder itself, according
|
||||||
|
to what is the common sense API when it comes to builder classes.
|
||||||
|
|
||||||
|
Once all tasks are registered and resources assigned to them, an execution graph
|
||||||
|
in the form of an adjacency matrix is returned to the user.<br/>
|
||||||
|
This graph contains all the tasks assigned to the flow builder in the form of
|
||||||
|
_vertices_. The _vertex_ itself is used as an index to get the identifier passed
|
||||||
|
during registration.
|
||||||
|
|
||||||
|
## Tasks and resources
|
||||||
|
|
||||||
|
Although these terms are used extensively in the documentation, the flow builder
|
||||||
|
has no real concept of tasks and resources.<br/>
|
||||||
|
This class works mainly with _identifiers_, that is, values of type `id_type`.
|
||||||
|
In other terms, both tasks and resources are identified by integral values.<br/>
|
||||||
|
This allows not to couple the class itself to the rest of the library or to any
|
||||||
|
particular data structure. On the other hand, it requires the user to keep track
|
||||||
|
of the association between identifiers and operations or actual data.
|
||||||
|
|
||||||
|
Once a flow builder is created (which requires no constructor arguments), the
|
||||||
|
first thing to do is to bind a task. This tells to the builder _who_ intends to
|
||||||
|
consume the resources that are specified immediately after:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::flow builder{};
|
||||||
|
builder.bind("task_1"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
The example uses the `EnTT` hashed string to generate an identifier for the
|
||||||
|
task.<br/>
|
||||||
|
Indeed, the use of `id_type` as an identifier type isn't by accident. In fact,
|
||||||
|
it matches well with the internal hashed string class. Moreover, it's also the
|
||||||
|
same type returned by the hash function of the internal RTTI system, in case the
|
||||||
|
user wants to rely on that.<br/>
|
||||||
|
However, being an integral value, it leaves the user full freedom to rely on his
|
||||||
|
own tools if necessary.
|
||||||
|
|
||||||
|
Once a task is associated with the flow builder, it's also assigned read-only or
|
||||||
|
read-write resources as appropriate:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
builder
|
||||||
|
.bind("task_1"_hs)
|
||||||
|
.ro("resource_1"_hs)
|
||||||
|
.ro("resource_2"_hs)
|
||||||
|
.bind("task_2"_hs)
|
||||||
|
.rw("resource_2"_hs)
|
||||||
|
```
|
||||||
|
|
||||||
|
As mentioned, many functions return the builder itself and it's therefore easy
|
||||||
|
to concatenate the different calls.<br/>
|
||||||
|
Also in the case of resources, they are identified by numeric values of type
|
||||||
|
`id_type`. As above, the choice is not entirely random. This goes well with the
|
||||||
|
tools offered by the library while leaving room for maximum flexibility.
|
||||||
|
|
||||||
|
Finally, both the `ro` and` rw` functions also offer an overload that accepts a
|
||||||
|
pair of iterators, so that one can pass a range of resources in one go.
|
||||||
|
|
||||||
|
### Rebinding
|
||||||
|
|
||||||
|
The `flow` class is resource based rather than task based. This means that graph
|
||||||
|
generation is driven by resources and not by the order of _appearance_ of tasks
|
||||||
|
during flow definition.<br/>
|
||||||
|
Although this concept is particularly important, it's almost irrelevant for the
|
||||||
|
vast majority of cases. However, it becomes relevant when _rebinding_ resources
|
||||||
|
or tasks.
|
||||||
|
|
||||||
|
In fact, nothing prevents rebinding elements to a flow.<br/>
|
||||||
|
However, the behavior changes slightly from case to case and has some nuances
|
||||||
|
that it's worth knowing about.
|
||||||
|
|
||||||
|
Directly rebinding a resource without the task being replaced trivially results
|
||||||
|
in the task's access mode for that resource being updated:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
builder.bind("task"_hs).rw("resource"_hs).ro("resource"_hs)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, the resource is accessed in read-only mode, regardless of the
|
||||||
|
first call to `rw`.<br/>
|
||||||
|
Behind the scenes, the call doesn't actually _replace_ the previous one but is
|
||||||
|
queued after it instead, overwriting it when generating the graph. Thus, a large
|
||||||
|
number of resource rebindings may even impact processing times (very difficult
|
||||||
|
to observe but theoretically possible).
|
||||||
|
|
||||||
|
Rebinding resources and also combining it with changes to tasks has far more
|
||||||
|
implications instead.<br/>
|
||||||
|
As mentioned, graph generation takes place starting from resources and not from
|
||||||
|
tasks. Therefore, the result may not be as expected:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
builder
|
||||||
|
.bind("task_1"_hs)
|
||||||
|
.ro("resource"_hs)
|
||||||
|
.bind("task_2"_hs)
|
||||||
|
.ro("resource"_hs)
|
||||||
|
.bind("task_1"_hs)
|
||||||
|
.rw("resource"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
What happens here is that the resource first _sees_ a read-only access request
|
||||||
|
from the first task, then a read-write request from the second task and finally
|
||||||
|
a new read-only request from the first task.<br/>
|
||||||
|
Although this definition would probably be counted as an error, the resulting
|
||||||
|
graph may be unexpected. This in fact consists of a single edge outgoing from
|
||||||
|
the second task and directed to the first task.<br/>
|
||||||
|
To intuitively understand what happens, it's enough to think of the fact that a
|
||||||
|
task never has an edge pointing to itself.
|
||||||
|
|
||||||
|
While not obvious, this approach has its pros and cons like any other solution.
|
||||||
|
For example, creating loops is actually simple in the context of resource-based
|
||||||
|
graph generations:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
builder
|
||||||
|
.bind("task_1"_hs)
|
||||||
|
.rw("resource"_hs)
|
||||||
|
.bind("task_2"_hs)
|
||||||
|
.rw("resource"_hs)
|
||||||
|
.bind("task_1"_hs)
|
||||||
|
.rw("resource"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
As expected, this definition leads to the creation of two edges that define a
|
||||||
|
loop between the two tasks.
|
||||||
|
|
||||||
|
As a general rule, rebinding resources and tasks is highly discouraged because
|
||||||
|
it could lead to subtle bugs if users don't know what they're doing.<br/>
|
||||||
|
However, once the mechanisms of resource-based graph generation are understood,
|
||||||
|
it can offer to the expert user a flexibility and a range of possibilities
|
||||||
|
otherwise inaccessible.
|
||||||
|
|
||||||
|
## Fake resources and order of execution
|
||||||
|
|
||||||
|
The flow builder doesn't offer the ability to specify when a task should execute
|
||||||
|
before or after another task.<br/>
|
||||||
|
In fact, the order of _registration_ on the resources also determines the order
|
||||||
|
in which the tasks are processed during the generation of the execution graph.
|
||||||
|
|
||||||
|
However, there is a way to _force_ the execution order of two processes.<br/>
|
||||||
|
Briefly, since accessing a resource in opposite modes requires sequential rather
|
||||||
|
than parallel scheduling, it's possible to make use of fake resources to rule on
|
||||||
|
the execution order:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
builder
|
||||||
|
.bind("task_1"_hs)
|
||||||
|
.ro("resource_1"_hs)
|
||||||
|
.rw("fake"_hs)
|
||||||
|
.bind("task_2"_hs)
|
||||||
|
.ro("resource_2"_hs)
|
||||||
|
.ro("fake"_hs)
|
||||||
|
.bind("task_3"_hs)
|
||||||
|
.ro("resource_2"_hs)
|
||||||
|
.ro("fake"_hs)
|
||||||
|
```
|
||||||
|
|
||||||
|
This snippet forces the execution of `task_1` **before** `task_2` and `task_3`.
|
||||||
|
This is due to the fact that the former sets a read-write requirement on a fake
|
||||||
|
resource that the other tasks also want to access in read-only mode.<br/>
|
||||||
|
Similarly, it's possible to force a task to run **after** a certain group:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
builder
|
||||||
|
.bind("task_1"_hs)
|
||||||
|
.ro("resource_1"_hs)
|
||||||
|
.ro("fake"_hs)
|
||||||
|
.bind("task_2"_hs)
|
||||||
|
.ro("resource_1"_hs)
|
||||||
|
.ro("fake"_hs)
|
||||||
|
.bind("task_3"_hs)
|
||||||
|
.ro("resource_2"_hs)
|
||||||
|
.rw("fake"_hs)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, since there are a number of processes that want to read a specific
|
||||||
|
resource, they will do so in parallel by forcing `task_3` to run after all the
|
||||||
|
others tasks.
|
||||||
|
|
||||||
|
## Sync points
|
||||||
|
|
||||||
|
Sometimes it's useful to assign the role of _sync point_ to a node.<br/>
|
||||||
|
Whether it accesses new resources or is simply a watershed, the procedure for
|
||||||
|
assigning this role to a vertex is always the same. First it's tied to the flow
|
||||||
|
builder, then the `sync` function is invoked:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
builder.bind("sync_point"_hs).sync();
|
||||||
|
```
|
||||||
|
|
||||||
|
The choice to assign an _identity_ to this type of nodes lies in the fact that,
|
||||||
|
more often than not, they also perform operations on resources.<br/>
|
||||||
|
If this isn't the case, it will still be possible to create no-op vertices to
|
||||||
|
which empty tasks are assigned.
|
||||||
|
|
||||||
|
## Execution graph
|
||||||
|
|
||||||
|
Once both the resources and their consumers have been properly registered, the
|
||||||
|
purpose of this tool is to generate an execution graph that takes into account
|
||||||
|
all specified constraints to return the best scheduling for the vertices:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::adjacency_matrix<entt::directed_tag> graph = builder.graph();
|
||||||
|
```
|
||||||
|
|
||||||
|
Searching for the main vertices (that is, those without in-edges) is usually the
|
||||||
|
first thing required:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto &&vertex: graph) {
|
||||||
|
if(auto in_edges = graph.in_edges(vertex); in_edges.begin() == in_edges.end()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then it's possible to instantiate an execution graph by means of other functions
|
||||||
|
such as `out_edges` to retrieve the children of a given task or `edges` to get
|
||||||
|
the identifiers.
|
97
external/entt/entt/docs/md/lib.md
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# Push EnTT across boundaries
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Working across boundaries](#working-across-boundaries)
|
||||||
|
* [Smooth until proven otherwise](#smooth-until-proven-otherwise)
|
||||||
|
* [Meta context](#meta-context)
|
||||||
|
* [Memory management](#memory-management)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Working across boundaries
|
||||||
|
|
||||||
|
`EnTT` has historically had a limit when used across boundaries on Windows in
|
||||||
|
general and on GNU/Linux when default visibility was set to hidden. The
|
||||||
|
limitation was mainly due to a custom utility used to assign unique, sequential
|
||||||
|
identifiers with different types.<br/>
|
||||||
|
Fortunately, nowadays `EnTT` works smoothly across boundaries.
|
||||||
|
|
||||||
|
## Smooth until proven otherwise
|
||||||
|
|
||||||
|
Many classes in `EnTT` make extensive use of type erasure for their purposes.
|
||||||
|
This raises the need to identify objects whose type has been erased.<br/>
|
||||||
|
The `type_hash` class template is how identifiers are generated and thus made
|
||||||
|
available to the rest of the library. In general, this class doesn't arouse much
|
||||||
|
interest. The only exception is when a conflict between identifiers occurs
|
||||||
|
(definitely uncommon though) or when the default solution proposed by `EnTT`
|
||||||
|
isn't suitable for the user's purposes.<br/>
|
||||||
|
The section dedicated to `type_info` contains all the details to get around the
|
||||||
|
issue in a concise and elegant way. Please refer to the specific documentation.
|
||||||
|
|
||||||
|
When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
|
||||||
|
`ENTT_API_IMPORT` are to import or export symbols, so as to make everything work
|
||||||
|
nicely across boundaries.<br/>
|
||||||
|
On the other hand, everything should run smoothly when working with plugins or
|
||||||
|
shared libraries that don't export any symbols.
|
||||||
|
|
||||||
|
For those who need more details, the test suite contains many examples covering
|
||||||
|
the most common cases (see the `lib` directory for all details).<br/>
|
||||||
|
It goes without saying that it's impossible to cover **all** possible cases.
|
||||||
|
However, what is offered should hopefully serve as a basis for all of them.
|
||||||
|
|
||||||
|
## Meta context
|
||||||
|
|
||||||
|
The runtime reflection system deserves a special mention when it comes to using
|
||||||
|
it across boundaries.<br/>
|
||||||
|
Since it's linked already to a static context to which the elements are attached
|
||||||
|
and different contexts don't relate to each other, they must be _shared_ to
|
||||||
|
allow the use of meta types across boundaries.
|
||||||
|
|
||||||
|
Fortunately, sharing a context is also trivial to do. First of all, the local
|
||||||
|
one is acquired in the main space:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto handle = entt::locator<entt::meta_ctx>::handle();
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, it's passed to the receiving space that sets it as its default context,
|
||||||
|
thus discarding or storing aside the local one:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::locator<entt::meta_ctx>::reset(handle);
|
||||||
|
```
|
||||||
|
|
||||||
|
From now on, both spaces refer to the same context and on it are attached all
|
||||||
|
new meta types, no matter where they are created.<br/>
|
||||||
|
Note that _replacing_ the main context doesn't also propagate changes across
|
||||||
|
boundaries. In other words, replacing a context results in the decoupling of the
|
||||||
|
two sides and therefore a divergence in the contents.
|
||||||
|
|
||||||
|
## Memory Management
|
||||||
|
|
||||||
|
There is another subtle problem due to memory management that can lead to
|
||||||
|
headaches.<br/>
|
||||||
|
It can occur where there are pools of objects (such as components or events)
|
||||||
|
dynamically created on demand. This is usually not a problem when working with
|
||||||
|
linked libraries that rely on the same dynamic runtime. However, it can occur in
|
||||||
|
the case of plugins or statically linked runtimes.
|
||||||
|
|
||||||
|
As an example, imagine creating an instance of `registry` in the main executable
|
||||||
|
and sharing it with a plugin. If the latter starts working with a component that
|
||||||
|
is unknown to the former, a dedicated pool is created within the registry on
|
||||||
|
first use.<br/>
|
||||||
|
As one can guess, this pool is instantiated on a different side of the boundary
|
||||||
|
from the `registry`. Therefore, the instance is now managing memory from
|
||||||
|
different spaces and this can quickly lead to crashes if not properly addressed.
|
||||||
|
|
||||||
|
To overcome the risk, it's recommended to use well-defined interfaces that make
|
||||||
|
fundamental types pass through the boundaries, isolating the instances of the
|
||||||
|
`EnTT` classes from time to time and as appropriate.<br/>
|
||||||
|
Refer to the test suite for some examples, read the documentation available
|
||||||
|
online about this type of issues or consult someone who has already had such
|
||||||
|
experiences to avoid problems.
|
304
external/entt/entt/docs/md/links.md
vendored
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
# EnTT in Action
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [EnTT in Action](#entt-in-action)
|
||||||
|
* [Games](#games)
|
||||||
|
* [Engines and the like](#engines-and-the-like)
|
||||||
|
* [Articles, videos and blog posts](#articles-videos-and-blog-posts)
|
||||||
|
* [Any Other Business](#any-other-business)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
`EnTT` is widely used in private and commercial applications. I cannot even
|
||||||
|
mention most of them because of some signatures I put on some documents time
|
||||||
|
ago. Fortunately, there are also people who took the time to implement open
|
||||||
|
source projects based on `EnTT` and didn't hold back when it came to documenting
|
||||||
|
them.
|
||||||
|
|
||||||
|
Below an incomplete list of games, applications and articles that can be used as
|
||||||
|
a reference.<br/>
|
||||||
|
Where I put the word _apparently_ means that the use of `EnTT` is documented but
|
||||||
|
the authors didn't make explicit announcements or contacted me directly.
|
||||||
|
|
||||||
|
If you know of other resources out there that are about `EnTT`, feel free to
|
||||||
|
open an issue or a PR and I'll be glad to add them to this page.<br/>
|
||||||
|
I hope the following lists can grow much more in the future.
|
||||||
|
|
||||||
|
# EnTT in Action
|
||||||
|
|
||||||
|
## Games
|
||||||
|
|
||||||
|
* [Minecraft](https://minecraft.net/en-us/attribution/) by
|
||||||
|
[Mojang](https://mojang.com/): of course, **that** Minecraft, see the
|
||||||
|
open source attributions page for more details.
|
||||||
|
* [Minecraft Earth](https://www.minecraft.net/en-us/about-earth) by
|
||||||
|
[Mojang](https://mojang.com/): an augmented reality game for mobile, that
|
||||||
|
lets users bring Minecraft into the real world.
|
||||||
|
* [Ember Sword](https://embersword.com/): a modern Free-to-Play MMORPG with a
|
||||||
|
player-driven economy, a classless combat system, and scarce, tradable
|
||||||
|
cosmetic collectibles.
|
||||||
|
* Apparently [Diablo II: Resurrected](https://diablo2.blizzard.com/) by
|
||||||
|
[Blizzard](https://www.blizzard.com/): monsters, heroes, items, spells, all
|
||||||
|
resurrected. Thanks unknown insider.
|
||||||
|
* [Apparently](https://www.youtube.com/watch?v=P8xvOA3ikrQ&t=1105s)
|
||||||
|
[Call of Duty: Vanguard](https://www.callofduty.com/vanguard) by
|
||||||
|
[Sledgehammer Games](https://www.sledgehammergames.com/): I can neither
|
||||||
|
confirm nor deny but there is a license I know in the credits.
|
||||||
|
* Apparently [D&D Dark Alliance](https://darkalliance.wizards.com) by
|
||||||
|
[Wizards of the Coast](https://company.wizards.com): your party, their
|
||||||
|
funeral.
|
||||||
|
* [TiltedOnline](https://github.com/tiltedphoques/TiltedOnline) by
|
||||||
|
[Tilted Phoques](https://github.com/tiltedphoques): Skyrim and Fallout 4 mod
|
||||||
|
to play online.
|
||||||
|
* [Antkeeper](https://github.com/antkeeper/antkeeper-source): an ant colony
|
||||||
|
simulation [game](https://antkeeper.com/).
|
||||||
|
* [Openblack](https://github.com/openblack/openblack): open source
|
||||||
|
reimplementation of the game _Black & White_ (2001).
|
||||||
|
* [Land of the Rair](https://github.com/LandOfTheRair/core2): the new backend
|
||||||
|
of [a retro-style MUD](https://rair.land/) for the new age.
|
||||||
|
* [Face Smash](https://play.google.com/store/apps/details?id=com.gamee.facesmash):
|
||||||
|
a game to play with your face.
|
||||||
|
* [EnTT Pacman](https://github.com/Kerndog73/EnTT-Pacman): an example of how
|
||||||
|
to make Pacman with `EnTT`.
|
||||||
|
* [Wacman](https://github.com/carlfindahl/wacman): a pacman clone with OpenGL.
|
||||||
|
* [Classic Tower Defence](https://github.com/kerndog73/Classic-Tower-Defence):
|
||||||
|
a tiny little tower defence game featuring a homemade font.
|
||||||
|
[Check it out](https://indi-kernick.itch.io/classic-tower-defence).
|
||||||
|
* [The Machine](https://github.com/Kerndog73/The-Machine): a box pushing
|
||||||
|
puzzler with logic gates and other cool stuff.
|
||||||
|
[Check it out](https://indi-kernick.itch.io/the-machine-web-version).
|
||||||
|
* [EnTTPong](https://github.com/DomRe/EnttPong): a basic game made to showcase
|
||||||
|
different parts of `EnTT` and C++17.
|
||||||
|
* [Randballs](https://github.com/gale93/randballs): simple `SFML` and `EnTT`
|
||||||
|
playground.
|
||||||
|
* [EnTT Tower Defense](https://github.com/Daivuk/tddod): a data oriented tower
|
||||||
|
defense example.
|
||||||
|
* [EnTT Breakout](https://github.com/vblanco20-1/entt-breakout): simple
|
||||||
|
example of a breakout game, using `SDL` and `EnTT`.
|
||||||
|
* [Arcade puzzle game with EnTT](https://github.com/MasonRG/ArcadePuzzleGame):
|
||||||
|
arcade puzzle game made in C++ using the `SDL2` and `EnTT` libraries.
|
||||||
|
* [Snake with EnTT](https://github.com/MasonRG/SnakeGame): simple snake game
|
||||||
|
made in C++ with the `SDL2` and `EnTT` libraries.
|
||||||
|
* [Mirrors lasers and robots](https://github.com/guillaume-haerinck/imac-tower-defense):
|
||||||
|
a small tower defense game based on mirror orientation.
|
||||||
|
* [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead/): 2D, Zombie,
|
||||||
|
RPG game made from scratch in C++.
|
||||||
|
* [Robotligan](https://github.com/Trisslotten/robotligan): multiplayer
|
||||||
|
football game.
|
||||||
|
* [DungeonSlayer](https://github.com/alohaeee/DungeonSlayer): 2D game made
|
||||||
|
from scratch in C++.
|
||||||
|
* [3DGame](https://github.com/kwarkGorny/3DGame): 2.5D top-down space shooter.
|
||||||
|
* [Pulcher](https://github.com/AODQ/pulcher): 2D cross-platform game inspired
|
||||||
|
by Quake.
|
||||||
|
* [Destroid](https://github.com/tyrannicaltoucan/destroid): _one-bazillionth_
|
||||||
|
arcade game about shooting dirty rocks in space, inspired by Asteroids.
|
||||||
|
* [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration
|
||||||
|
based indie game.
|
||||||
|
* [Spelunky<EFBFBD> Classic remake](https://github.com/dbeef/spelunky-psp): a truly
|
||||||
|
multiplatform experience with a rewrite from scratch.
|
||||||
|
* [CubbyTower](https://github.com/utilForever/CubbyTower): a simple tower
|
||||||
|
defense game using C++ with Entity Component System (ECS).
|
||||||
|
* [Runeterra](https://github.com/utilForever/Runeterra): Legends of Runeterra
|
||||||
|
simulator using C++ with some reinforcement learning.
|
||||||
|
* [Black Sun](https://store.steampowered.com/app/1670930/Black_Sun/): fly your
|
||||||
|
space ship through a large 2D open world.
|
||||||
|
* [PokeMaster](https://github.com/utilForever/PokeMaster): Pokemon Battle
|
||||||
|
simulator using C++ with some reinforcement learning.
|
||||||
|
* [HomeHearth](https://youtu.be/GrEWl8npL9Y): choose your hero, protect the
|
||||||
|
town, before it's too late.
|
||||||
|
* [City Builder Game](https://github.com/PhiGei2000/CityBuilderGame): a simple
|
||||||
|
city-building game using C++ and OpenGL.
|
||||||
|
* [BattleSub](https://github.com/bfeldpw/battlesub): two player 2D submarine
|
||||||
|
game with some fluid dynamics.
|
||||||
|
* [Crimson Rush](https://github.com/WilKam01/LuaCGame): a dungeon-crawler and
|
||||||
|
rougelike inspired game about exploring and surviving as long as possible.
|
||||||
|
* [Space Fight](https://github.com/cholushkin/SpaceFight): one screen
|
||||||
|
multi-player arcade shooter game prototype.
|
||||||
|
* [Confetti Party](https://github.com/hexerei/entt-confetti): C++ sample
|
||||||
|
application as a starting point using `EnTT` and `SDL2`.
|
||||||
|
|
||||||
|
## Engines and the like:
|
||||||
|
|
||||||
|
* [Aether Engine](https://hadean.com/spatial-simulation/)
|
||||||
|
[v1.1+](https://docs.hadean.com/v1.1/Licenses/) by
|
||||||
|
[Hadean](https://hadean.com/): a library designed for spatially partitioning
|
||||||
|
agent-based simulations.
|
||||||
|
* [Fling Engine](https://github.com/flingengine/FlingEngine): a Vulkan game
|
||||||
|
engine with a focus on data oriented design.
|
||||||
|
* [NovusCore](https://github.com/novuscore/NovusCore): a modern take on World
|
||||||
|
of Warcraft emulation.
|
||||||
|
* [Chrysalis](https://github.com/ivanhawkes/Chrysalis): action RPG SDK for
|
||||||
|
CRYENGINE games.
|
||||||
|
* [LM-Engine](https://github.com/Lawrencemm/LM-Engine): the Vim of game
|
||||||
|
engines.
|
||||||
|
* [Edyn](https://github.com/xissburg/edyn): a real-time physics engine
|
||||||
|
organized as an ECS.
|
||||||
|
* [MushMachine](https://github.com/MadeOfJelly/MushMachine): engine...
|
||||||
|
vrooooommm.
|
||||||
|
* [Antara Gaming SDK](https://github.com/KomodoPlatform/antara-gaming-sdk):
|
||||||
|
the Komodo Gaming Software Development Kit.
|
||||||
|
* [XVP](https://ravingbots.com/xvp-expansive-vehicle-physics-for-unreal-engine/):
|
||||||
|
[_eXpansive Vehicle Physics_](https://github.com/raving-bots/xvp/wiki/Plugin-integration-guide)
|
||||||
|
plugin for Unreal Engine.
|
||||||
|
* [Apparently](https://teamwisp.github.io/credits/)
|
||||||
|
[Wisp](https://teamwisp.github.io/product/) by
|
||||||
|
[Team Wisp](https://teamwisp.github.io/): an advanced real-time ray tracing
|
||||||
|
renderer built for the demands of video game artists.
|
||||||
|
* [shiva](https://github.com/Milerius/shiva): modern C++ engine with
|
||||||
|
modularity.
|
||||||
|
* [ImGui/EnTT editor](https://github.com/Green-Sky/imgui_entt_entity_editor):
|
||||||
|
a drop-in, single-file entity editor for `EnTT` that uses `ImGui` as
|
||||||
|
graphical backend (with
|
||||||
|
[demo code](https://github.com/Green-Sky/imgui_entt_entity_editor_demo)).
|
||||||
|
* [SgOgl](https://github.com/stwe/SgOgl): a game engine library for OpenGL
|
||||||
|
developed for educational purposes.
|
||||||
|
* [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++
|
||||||
|
using OpenGL and Vulkan.
|
||||||
|
* [Silvanus](https://github.com/hobbyistmaker/silvanus): Silvanus Fusion 360
|
||||||
|
Box Generator.
|
||||||
|
* [Lina Engine](https://github.com/inanevin/LinaEngine): an open-source,
|
||||||
|
modular, tiny and fast C++ game engine, aimed to develop 3D desktop games.
|
||||||
|
* [Spike](https://github.com/FahimFuad/Spike): a powerful game engine which
|
||||||
|
can run on a toaster.
|
||||||
|
* [Helena Framework](https://github.com/NIKEA-SOFT/HelenaFramework): a modern
|
||||||
|
framework in C++17 for backend development.
|
||||||
|
* [Unity/EnTT](https://github.com/TongTungGiang/unity-entt): tech demo of a
|
||||||
|
native simulation layer using `EnTT` and `Unity` as a rendering engine.
|
||||||
|
* [OverEngine](https://github.com/OverShifted/OverEngine): an over-engineered
|
||||||
|
game engine.
|
||||||
|
* [Electro](https://github.com/Electro-Technologies/Electro): high performance
|
||||||
|
3D game engine with a high emphasis on rendering.
|
||||||
|
* [Kawaii](https://github.com/Mathieu-Lala/Kawaii_Engine): a modern data
|
||||||
|
oriented game engine.
|
||||||
|
* [Becketron](https://github.com/Doctor-Foxling/Becketron): a game engine
|
||||||
|
written mostly in C++.
|
||||||
|
* [Spatial Engine](https://github.com/luizgabriel/Spatial.Engine): a
|
||||||
|
cross-platform engine created on top of google's filament rendering engine.
|
||||||
|
* [Kaguya](https://github.com/KaiH0717/Kaguya): D3D12 Rendering Engine.
|
||||||
|
* [OpenAWE](https://github.com/OpenAWE-Project/OpenAWE): open implementation
|
||||||
|
of the Alan Wake Engine.
|
||||||
|
* [Nazara Engine](https://github.com/DigitalPulseSoftware/NazaraEngine): fast,
|
||||||
|
cross-platform, object-oriented API to help in daily developer life.
|
||||||
|
* [Billy Engine](https://github.com/billy4479/BillyEngine): some kind of a 2D
|
||||||
|
engine based on `SDL2` and `EnTT`.
|
||||||
|
* [Ducktape](https://github.com/DucktapeEngine/Ducktape): an open source C++
|
||||||
|
2D & 3D game engine that focuses on being fast and powerful.
|
||||||
|
* [The Worst Engine](https://github.com/Parasik72/TWE): a game engine based on
|
||||||
|
OpenGL.
|
||||||
|
* [Ecsact](https://ecsact.dev/): a language aimed at describing ECS, with a
|
||||||
|
[runtime implementation](https://github.com/ecsact-dev/ecsact_rt_entt) based
|
||||||
|
on `EnTT`.
|
||||||
|
* [AGE (Arc Game Engine)](https://github.com/MohitSethi99/ArcGameEngine): an
|
||||||
|
open-source engine for building 2D & 3D real-time rendering and interactive
|
||||||
|
contents.
|
||||||
|
* [Kengine](https://github.com/phisko/kengine): the _Koala engine_ is a game
|
||||||
|
engine entirely implemented as an entity-component-ystem.
|
||||||
|
|
||||||
|
## Articles, videos and blog posts:
|
||||||
|
|
||||||
|
* [Some posts](https://skypjack.github.io/tags/#entt) on my personal
|
||||||
|
[blog](https://skypjack.github.io/) are about `EnTT`, for those who want to
|
||||||
|
know **more** on this project.
|
||||||
|
* [Game Engine series](https://www.youtube.com/c/TheChernoProject/videos) by
|
||||||
|
[The Cherno](https://github.com/TheCherno) (not only about `EnTT` but also
|
||||||
|
on the use of an ECS in general):
|
||||||
|
- [Intro to EnTT](https://www.youtube.com/watch?v=D4hz0wEB978).
|
||||||
|
- [Entities and Components](https://www.youtube.com/watch?v=-B1iu4QJTUc).
|
||||||
|
- [The ENTITY Class](https://www.youtube.com/watch?v=GfSzeAcsBb0).
|
||||||
|
- [Camera Systems](https://www.youtube.com/watch?v=ubZn7BlrnTU).
|
||||||
|
- [Scene Camera](https://www.youtube.com/watch?v=UKVFRRufKzo).
|
||||||
|
- [Native Scripting](https://www.youtube.com/watch?v=iIUhg88MK5M).
|
||||||
|
- [Native Scripting (now with virtual functions!)](https://www.youtube.com/watch?v=1cHEcrIn8IQ).
|
||||||
|
- [Scene Hierarchy Panel](https://www.youtube.com/watch?v=wziDnE8guvI).
|
||||||
|
- [Properties Panel](https://www.youtube.com/watch?v=NBpB0qscF3E).
|
||||||
|
- [Camera Component UI](https://www.youtube.com/watch?v=RIMt_6agUiU).
|
||||||
|
- [Drawing Component UI](https://www.youtube.com/watch?v=u3yq8s3KuSE).
|
||||||
|
- [Transform Component UI](https://www.youtube.com/watch?v=8JqcXYbzPJc).
|
||||||
|
- [Adding/Removing Entities and Components UI](https://www.youtube.com/watch?v=PsyGmsIgp9M).
|
||||||
|
- [Saving and Loading Scenes](https://www.youtube.com/watch?v=IEiOP7Y-Mbc).
|
||||||
|
- ... And so on.
|
||||||
|
[Check out](https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw) the
|
||||||
|
_Game Engine Series_ by The Cherno for more videos.
|
||||||
|
* [Warmonger Dynasty devlog series](https://david-delassus.medium.com/list/warmonger-dynasty-devlogs-f64b71f556de)
|
||||||
|
by [linkdd](https://github.com/linkdd): an interesting walkthrough of
|
||||||
|
developing a game (also) with EnTT.
|
||||||
|
* [Use EnTT When You Need An ECS](https://www.codingwiththomas.com/blog/use-entt-when-you-need-an-ecs)
|
||||||
|
by [Thomas](https://www.codingwiththomas.com/): I couldn't have said it
|
||||||
|
better.
|
||||||
|
* [Space Battle: Huge edition](http://victor.madtriangles.com/code%20experiment/2018/06/11/post-ecs-battle-huge.html):
|
||||||
|
huge space battle built entirely from scratch.
|
||||||
|
* [Space Battle](https://github.com/vblanco20-1/ECS_SpaceBattle): huge space
|
||||||
|
battle built on `UE4`.
|
||||||
|
* [Experimenting with ECS in UE4](http://victor.madtriangles.com/code%20experiment/2018/03/25/post-ue4-ecs-battle.html):
|
||||||
|
interesting article about `UE4` and `EnTT`.
|
||||||
|
* [Implementing ECS architecture in UE4](https://forums.unrealengine.com/development-discussion/c-gameplay-programming/1449913-implementing-ecs-architecture-in-ue4-giant-space-battle):
|
||||||
|
giant space battle.
|
||||||
|
* [Conan Adventures (SFML and EnTT in C++)](https://leinnan.github.io/blog/conan-adventuressfml-and-entt-in-c.html):
|
||||||
|
create projects in modern C++ using `SFML`, `EnTT`, `Conan` and `CMake`.
|
||||||
|
* [Adding EnTT ECS to Chrysalis](https://www.tauradius.com/post/adding-an-ecs-to-chrysalis/):
|
||||||
|
a blog entry (and its
|
||||||
|
[follow-up](https://www.tauradius.com/post/chrysalis-update-2020-08-02/))
|
||||||
|
about the integration of `EnTT` into `Chrysalis`, an action RPG SDK for
|
||||||
|
CRYENGINE games.
|
||||||
|
* [Creating Minecraft in One Week with C++ and Vulkan](https://vazgriz.com/189/creating-minecraft-in-one-week-with-c-and-vulkan/):
|
||||||
|
a crack at recreating Minecraft in one week using a custom C++ engine and
|
||||||
|
Vulkan ([code included](https://github.com/vazgriz/VoxelGame)).
|
||||||
|
* [Ability Creator](https://www.erichildebrand.net/blog/ability-creator-project-retrospect):
|
||||||
|
project retrospect by [Eric Hildebrand](https://www.erichildebrand.net/).
|
||||||
|
* [EnTT Entity Component System Gaming Library](https://gamefromscratch.com/entt-entity-component-system-gaming-library/):
|
||||||
|
`EnTT` on GameFromScratch.com.
|
||||||
|
* [Custom C++ server for UE5](https://youtu.be/fbXZVNCOvjM) optimized for
|
||||||
|
MMO(RPG)s and its [follow-up](https://youtu.be/yGlZeopx2hU) episode about
|
||||||
|
player bots and full external ECS: a series definitely worth looking at.
|
||||||
|
|
||||||
|
## Any Other Business:
|
||||||
|
|
||||||
|
* [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by
|
||||||
|
[Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the
|
||||||
|
cross platform C++ rendering engine. The SDKs are utilized by a lot of
|
||||||
|
enterprise custom apps, as well as by Esri for its own public applications
|
||||||
|
such as
|
||||||
|
[Explorer](https://play.google.com/store/apps/details?id=com.esri.explorer),
|
||||||
|
[Collector](https://play.google.com/store/apps/details?id=com.esri.arcgis.collector)
|
||||||
|
and
|
||||||
|
[Navigator](https://play.google.com/store/apps/details?id=com.esri.navigator).
|
||||||
|
* [FASTSUITE Edition 2](https://www.fastsuite.com/en_EN/fastsuite/fastsuite-edition-2.html)
|
||||||
|
by [Cenit](http://www.cenit.com/en_EN/about-us/overview.html): they use
|
||||||
|
`EnTT` to drive their simulation, that is, the communication between robot
|
||||||
|
controller emulator and renderer.
|
||||||
|
* [Ragdoll](https://ragdolldynamics.com/): real-time physics for Autodesk Maya
|
||||||
|
2020.
|
||||||
|
* [Project Lagrange](https://github.com/adobe/lagrange): a robust geometry
|
||||||
|
processing library by [Adobe](https://github.com/adobe).
|
||||||
|
* [AtomicDEX](https://github.com/KomodoPlatform/atomicDEX-Desktop): a secure
|
||||||
|
wallet and non-custodial decentralized exchange rolled into one application.
|
||||||
|
* [Apparently](https://www.linkedin.com/in/skypjack/)
|
||||||
|
[NIO](https://www.nio.io/): there was a collaboration to make some changes
|
||||||
|
to `EnTT`, at the time used for internal projects.
|
||||||
|
* [Apparently](https://www.linkedin.com/jobs/view/architekt-c%2B%2B-at-tieto-1219512333/)
|
||||||
|
[Tieto](https://www.tieto.com/): they published a job post where `EnTT` was
|
||||||
|
listed on their software stack.
|
||||||
|
* [Sequentity](https://github.com/alanjfs/sequentity): A MIDI-like
|
||||||
|
sequencer/tracker for C++ and `ImGui` (with `Magnum` and `EnTT`).
|
||||||
|
* [EnTT meets Sol2](https://github.com/skaarj1989/entt-meets-sol2): freely
|
||||||
|
available examples of how to combine `EnTT` and `Sol2`.
|
||||||
|
* [Godot meets EnTT](https://github.com/portaloffreedom/godot_entt_example/):
|
||||||
|
a simple example on how to use `EnTT` within
|
||||||
|
[`Godot`](https://godotengine.org/).
|
||||||
|
* [Godot and GameNetworkingSockets meet EnTT](https://github.com/portaloffreedom/godot_entt_net_example):
|
||||||
|
a simple example on how to use `EnTT` and
|
||||||
|
[`GameNetworkingSockets`](https://github.com/ValveSoftware/GameNetworkingSockets)
|
||||||
|
within [`Godot`](https://godotengine.org/).
|
||||||
|
* [MatchOneEntt](https://github.com/mhaemmerle/MatchOneEntt): port of
|
||||||
|
[Match One](https://github.com/sschmid/Match-One) for `Entitas-CSharp`.
|
||||||
|
* GitHub contains also
|
||||||
|
[many other examples](https://github.com/search?o=desc&q=%22skypjack%2Fentt%22&s=indexed&type=Code)
|
||||||
|
of use of `EnTT` from which to take inspiration if interested.
|
88
external/entt/entt/docs/md/locator.md
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# Crash Course: service locator
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Service locator](#service-locator)
|
||||||
|
* [Opaque handles](#opaque-handles)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Usually, service locators are tightly bound to the services they expose and it's
|
||||||
|
hard to define a general purpose solution.<br/>
|
||||||
|
This tiny class tries to fill the gap and gets rid of the burden of defining a
|
||||||
|
different specific locator for each application.
|
||||||
|
|
||||||
|
# Service locator
|
||||||
|
|
||||||
|
The service locator API tries to mimic that of `std::optional` and adds some
|
||||||
|
extra functionalities on top of it such as allocator support.<br/>
|
||||||
|
There are a couple of functions to set up a service, namely `emplace` and
|
||||||
|
`allocate_emplace`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::locator<interface>::emplace<service>(argument);
|
||||||
|
entt::locator<interface>::allocate_emplace<service>(allocator, argument);
|
||||||
|
```
|
||||||
|
|
||||||
|
The difference is that the latter expects an allocator as the first argument and
|
||||||
|
uses it to allocate the service itself.<br/>
|
||||||
|
Once a service is set up, it's retrieved using the `value` function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
interface &service = entt::locator<interface>::value();
|
||||||
|
```
|
||||||
|
|
||||||
|
Since the service may not be set (and therefore this function may result in an
|
||||||
|
undefined behavior), the `has_value` and `value_or` functions are also available
|
||||||
|
to test a service locator and to get a fallback service in case there is none:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if(entt::locator<interface>::has_value()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
interface &service = entt::locator<interface>::value_or<fallback_impl>(argument);
|
||||||
|
```
|
||||||
|
|
||||||
|
All arguments are used only if necessary, that is, if a service doesn't already
|
||||||
|
exist and therefore the fallback service is constructed and returned. In all
|
||||||
|
other cases, they are discarded.<br/>
|
||||||
|
Finally, to reset a service, use the `reset` function.
|
||||||
|
|
||||||
|
## Opaque handles
|
||||||
|
|
||||||
|
Sometimes it's useful to _transfer_ a copy of a service to another locator. For
|
||||||
|
example, when working across boundaries it's common to _share_ a service with a
|
||||||
|
dynamically loaded module.<br/>
|
||||||
|
Options aren't much in this case. Among these is the possibility of _exporting_
|
||||||
|
services and assigning them to a different locator.
|
||||||
|
|
||||||
|
This is what the `handle` and `reset` functions are meant for.<br/>
|
||||||
|
The former returns an opaque object useful for _exporting_ (or rather, obtaining
|
||||||
|
a reference to) a service. The latter also accepts an optional argument to a
|
||||||
|
handle which then allows users to reset a service by initializing it with an
|
||||||
|
opaque handle:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto handle = entt::locator<interface>::handle();
|
||||||
|
entt::locator<interface>::reset(handle);
|
||||||
|
```
|
||||||
|
|
||||||
|
It's worth noting that it's possible to get handles for uninitialized services
|
||||||
|
and use them with other locators. Of course, all a user will get is to have an
|
||||||
|
uninitialized service elsewhere as well.
|
||||||
|
|
||||||
|
Note that exporting a service allows users to _share_ the object currently set
|
||||||
|
in a locator. Replacing it won't replace the element even where a service has
|
||||||
|
been configured with a handle to the previous item.<br/>
|
||||||
|
In other words, if an audio service is replaced with a null object to silence an
|
||||||
|
application and the original service was shared, this operation won't propagate
|
||||||
|
to the other locators. Therefore, a module that share the ownership of the
|
||||||
|
original audio service is still able to emit sounds.
|
961
external/entt/entt/docs/md/meta.md
vendored
Normal file
@ -0,0 +1,961 @@
|
|||||||
|
# Crash Course: runtime reflection system
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Names and identifiers](#names-and-identifiers)
|
||||||
|
* [Reflection in a nutshell](#reflection-in-a-nutshell)
|
||||||
|
* [Any to the rescue](#any-to-the-rescue)
|
||||||
|
* [Enjoy the runtime](#enjoy-the-runtime)
|
||||||
|
* [Container support](#container-support)
|
||||||
|
* [Pointer-like types](#pointer-like-types)
|
||||||
|
* [Template information](#template-information)
|
||||||
|
* [Automatic conversions](#automatic-conversions)
|
||||||
|
* [Implicitly generated default constructor](#implicitly-generated-default-constructor)
|
||||||
|
* [From void to any](#from-void-to-any)
|
||||||
|
* [Policies: the more, the less](#policies-the-more-the-less)
|
||||||
|
* [Named constants and enums](#named-constants-and-enums)
|
||||||
|
* [Properties and meta objects](#properties-and-meta-objects)
|
||||||
|
* [Unregister types](#unregister-types)
|
||||||
|
* [Meta context](#meta-context)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Reflection (or rather, its lack) is a trending topic in the C++ world and a tool
|
||||||
|
that can unlock a lot of interesting features in the specific case of `EnTT`. I
|
||||||
|
looked for a third-party library that met my needs on the subject, but I always
|
||||||
|
came across some details that I didn't like: macros, being intrusive, too many
|
||||||
|
allocations, and so on.<br/>
|
||||||
|
I finally decided to write a built-in, non-intrusive and macro-free runtime
|
||||||
|
reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes,
|
||||||
|
time will tell me, but at least I can model this tool around the library to
|
||||||
|
which it belongs and not the opposite.
|
||||||
|
|
||||||
|
# Names and identifiers
|
||||||
|
|
||||||
|
The meta system doesn't force users to rely on the tools provided by the library
|
||||||
|
when it comes to working with names and identifiers. It does this by offering an
|
||||||
|
API that works with opaque identifiers that may or may not be generated by means
|
||||||
|
of a hashed string.<br/>
|
||||||
|
This means that users can assign any type of identifier to the meta objects, as
|
||||||
|
long as they're numeric. It doesn't matter if they're generated at runtime, at
|
||||||
|
compile-time or with custom functions.
|
||||||
|
|
||||||
|
That being said, the examples in the following sections are all based on the
|
||||||
|
`hashed_string` class as provided by this library. Therefore, where an
|
||||||
|
identifier is required, it's likely that a user defined literal is used as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
For what it's worth, this is completely equivalent to:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto factory = entt::meta<my_type>().type(42u);
|
||||||
|
```
|
||||||
|
|
||||||
|
Obviously, human-readable identifiers are more convenient to use and highly
|
||||||
|
recommended.
|
||||||
|
|
||||||
|
# Reflection in a nutshell
|
||||||
|
|
||||||
|
Reflection always starts from actual C++ types. Users cannot reflect _imaginary_
|
||||||
|
types.<br/>
|
||||||
|
The `meta` function is where it all starts:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto factory = entt::meta<my_type>();
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned value is a _factory object_ to use to continue building the meta
|
||||||
|
type.
|
||||||
|
|
||||||
|
By default, a meta type is associated with the identifier returned by the
|
||||||
|
runtime type identification system built-in in `EnTT`.<br/>
|
||||||
|
However, it's also possible to assign custom identifiers to meta types:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by
|
||||||
|
type.<br/>
|
||||||
|
However, users can be interested in adding features to a reflected type so that
|
||||||
|
the reflection system can use it correctly under the hood, while they don't want
|
||||||
|
to also make the type _searchable_. In this case, it's sufficient not to invoke
|
||||||
|
`type`.
|
||||||
|
|
||||||
|
A factory is such that all its member functions return the factory itself. It's
|
||||||
|
generally used to create the following:
|
||||||
|
|
||||||
|
* _Constructors_. A constructors is assigned to a reflected type by specifying
|
||||||
|
its _list of arguments_. Free functions are also accepted if the return type
|
||||||
|
is the expected one. From a client perspective, nothing changes between a free
|
||||||
|
function or an actual constructor:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
|
||||||
|
```
|
||||||
|
|
||||||
|
Meta default constructors are implicitly generated, if possible.
|
||||||
|
|
||||||
|
* _Destructors_. Both free functions and member functions are valid destructors:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().dtor<&destroy>();
|
||||||
|
```
|
||||||
|
|
||||||
|
The purpose is to offer the possibility to free up resources that require
|
||||||
|
_special treatment_ before an object is actually destroyed.<br/>
|
||||||
|
A function should neither delete nor explicitly invoke the destructor of a
|
||||||
|
given instance.
|
||||||
|
|
||||||
|
* _Data members_. Meta data members are actual data members of the underlying
|
||||||
|
type but also static and global variables or constants of any kind. From the
|
||||||
|
point of view of the client, all the variables associated with the reflected
|
||||||
|
type appear as if they were part of the type itself:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>()
|
||||||
|
.data<&my_type::static_variable>("static"_hs)
|
||||||
|
.data<&my_type::data_member>("member"_hs)
|
||||||
|
.data<&global_variable>("global"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `data` function requires the identifier to use for the meta data member.
|
||||||
|
Users can then access it by _name_ at runtime.<br/>
|
||||||
|
Data members are also defined by means of a setter and getter pair. These are
|
||||||
|
either free functions, class members or a mix of them. This approach is also
|
||||||
|
convenient to create read-only properties from a non-const data member:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple setters are also supported by means of a `value_list` object:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().data<entt::value_list<&from_int, &from_string>, &my_type::data_member>("member"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
* _Member functions_. Meta member functions are actual member functions of the
|
||||||
|
underlying type but also plain free functions. From the point of view of the
|
||||||
|
client, all the functions associated with the reflected type appear as if they
|
||||||
|
were part of the type itself:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>()
|
||||||
|
.func<&my_type::static_function>("static"_hs)
|
||||||
|
.func<&my_type::member_function>("member"_hs)
|
||||||
|
.func<&free_function>("free"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `func` function requires the identifier to use for the meta data function.
|
||||||
|
Users can then access it by _name_ at runtime.<br/>
|
||||||
|
Overloading of meta functions is supported. Overloaded functions are resolved
|
||||||
|
at runtime by the reflection system according to the types of the arguments.
|
||||||
|
|
||||||
|
* _Base classes_. A base class is such that the underlying type is actually
|
||||||
|
derived from it:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<derived_type>().base<base_type>();
|
||||||
|
```
|
||||||
|
|
||||||
|
The reflection system tracks the relationship and allows for implicit casts at
|
||||||
|
runtime when required. In other terms, wherever a `base_type` is required, an
|
||||||
|
instance of `derived_type` is also accepted.
|
||||||
|
|
||||||
|
* _Conversion functions_. Conversion functions allow users to define conversions
|
||||||
|
that are implicitly performed by the reflection system when required:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<double>().conv<int>();
|
||||||
|
```
|
||||||
|
|
||||||
|
This is everything users need to create meta types. Refer to the inline
|
||||||
|
documentation for further details.
|
||||||
|
|
||||||
|
## Any to the rescue
|
||||||
|
|
||||||
|
The reflection system offers a kind of _extended version_ of the `entt::any`
|
||||||
|
class (see the core module for more details).<br/>
|
||||||
|
The purpose is to add some feature on top of those already present, so as to
|
||||||
|
integrate it with the meta type system without having to duplicate the code.
|
||||||
|
|
||||||
|
The API is very similar to that of the `any` type. The class `meta_any` _wraps_
|
||||||
|
many of the feature to infer a meta node, before forwarding some or all of the
|
||||||
|
arguments to the underlying storage.<br/>
|
||||||
|
Among the few relevant differences, `meta_any` adds support for containers and
|
||||||
|
pointer-like types, while `any` doesn't.<br/>
|
||||||
|
Similar to `any`, this class is also used to create _aliases_ for unmanaged
|
||||||
|
objects either with `forward_as_meta` or using the `std::in_place_type<T &>`
|
||||||
|
disambiguation tag, as well as from an existing object by means of the `as_ref`
|
||||||
|
member function.<br/>
|
||||||
|
Unlike `any` instead, `meta_any` treats an empty instance and one initialized
|
||||||
|
with `void` differently:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_any empty{};
|
||||||
|
entt::meta_any other{std::in_place_type<void>};
|
||||||
|
```
|
||||||
|
|
||||||
|
While `any` considers both as empty, `meta_any` treats objects initialized with
|
||||||
|
`void` as if they were _valid_ ones. This allows to differentiate between failed
|
||||||
|
function calls and function calls that are successful but return nothing.
|
||||||
|
|
||||||
|
Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to
|
||||||
|
cast the underlying object to a given type (either a reference or a value type)
|
||||||
|
or to _convert_ a `meta_any` in such a way that a cast becomes viable for the
|
||||||
|
resulting object.<br/>
|
||||||
|
There is in fact no `any_cast` equivalent for `meta_any`.
|
||||||
|
|
||||||
|
## Enjoy the runtime
|
||||||
|
|
||||||
|
Once the web of reflected types is constructed, it's a matter of using it at
|
||||||
|
runtime where required.<br/>
|
||||||
|
There are a few options to search for a reflected type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// direct access to a reflected type
|
||||||
|
auto by_type = entt::resolve<my_type>();
|
||||||
|
|
||||||
|
// look up a reflected type by identifier
|
||||||
|
auto by_id = entt::resolve("reflected_type"_hs);
|
||||||
|
|
||||||
|
// look up a reflected type by type info
|
||||||
|
auto by_type_id = entt::resolve(entt::type_id<my_type>());
|
||||||
|
```
|
||||||
|
|
||||||
|
There exists also an overload of the `resolve` function to use to iterate all
|
||||||
|
reflected types at once. It returns an iterable object to be used in a range-for
|
||||||
|
loop:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto &&[id, type]: entt::resolve()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In all cases, the returned value is an instance of `meta_type` (possibly with
|
||||||
|
its id). This kind of objects offer an API to know their _runtime identifiers_,
|
||||||
|
to iterate all the meta objects associated with them and even to build instances
|
||||||
|
of the underlying type.<br/>
|
||||||
|
Meta data members and functions are accessed by name:
|
||||||
|
|
||||||
|
* Meta data members:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto data = entt::resolve<my_type>().data("member"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned type is `meta_data` and may be invalid if there is no meta data
|
||||||
|
object associated with the given identifier.<br/>
|
||||||
|
A meta data object offers an API to query the underlying type (for example, to
|
||||||
|
know if it's a const or a static one), to get the meta type of the variable
|
||||||
|
and to set or get the contained value.
|
||||||
|
|
||||||
|
* Meta function members:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto func = entt::resolve<my_type>().func("member"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned type is `meta_func` and may be invalid if there is no meta
|
||||||
|
function object associated with the given identifier.<br/>
|
||||||
|
A meta function object offers an API to query the underlying type (for
|
||||||
|
example, to know if it's a const or a static function), to know the number of
|
||||||
|
arguments, the meta return type and the meta types of the parameters. In
|
||||||
|
addition, a meta function object is used to invoke the underlying function and
|
||||||
|
then get the return value in the form of a `meta_any` object.
|
||||||
|
|
||||||
|
All the meta objects thus obtained as well as the meta types explicitly convert
|
||||||
|
to a boolean value to check for validity:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Furthermore, all them (and a few more, like meta basis) are returned by a bunch
|
||||||
|
of overloads that provide the caller with iterable ranges of top-level elements.
|
||||||
|
As an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto &&[id, type]: entt::resolve<my_type>().base()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Meta type are also used to `construct` actual instances of the underlying
|
||||||
|
type.<br/>
|
||||||
|
In particular, the `construct` member function accepts a variable number of
|
||||||
|
arguments and searches for a match. It then returns a `meta_any` object that may
|
||||||
|
or may not be initialized, depending on whether a suitable constructor was found
|
||||||
|
or not.
|
||||||
|
|
||||||
|
There is no object that wraps the destructor of a meta type nor a `destroy`
|
||||||
|
member function in its API. Destructors are invoked implicitly by `meta_any`
|
||||||
|
behind the scenes and users have not to deal with them explicitly. Furthermore,
|
||||||
|
they've no name, cannot be searched and wouldn't have member functions to expose
|
||||||
|
anyway.<br/>
|
||||||
|
Similarly, conversion functions aren't directly accessible. They're used
|
||||||
|
internally by `meta_any` and the meta objects when needed.
|
||||||
|
|
||||||
|
Meta types and meta objects in general contain much more than what was said.
|
||||||
|
Refer to the inline documentation for further details.
|
||||||
|
|
||||||
|
## Container support
|
||||||
|
|
||||||
|
The runtime reflection system also supports containers of all types.<br/>
|
||||||
|
Moreover, _containers_ doesn't necessarily mean those offered by the C++
|
||||||
|
standard library. In fact, user defined data structures can also work with the
|
||||||
|
meta system in many cases.
|
||||||
|
|
||||||
|
To make a container be recognized as such by the meta system, users are required
|
||||||
|
to provide specializations for either the `meta_sequence_container_traits` class
|
||||||
|
or the `meta_associative_container_traits` class, according to the actual _type_
|
||||||
|
of the container.<br/>
|
||||||
|
`EnTT` already exports the specializations for some common classes. In
|
||||||
|
particular:
|
||||||
|
|
||||||
|
* `std::vector`, `std::array`, `std::deque` and `std::list` (but not
|
||||||
|
`std::forward_list`) are supported as _sequence containers_.
|
||||||
|
|
||||||
|
* `std::map`, `std::set` and their unordered counterparts are supported as
|
||||||
|
_associative containers_.
|
||||||
|
|
||||||
|
It's important to include the header file `container.hpp` to make these
|
||||||
|
specializations available to the compiler when needed.<br/>
|
||||||
|
The same file also contains many examples for the users that are interested in
|
||||||
|
making their own containers available to the meta system.
|
||||||
|
|
||||||
|
When a specialization of the `meta_sequence_container_traits` class exists, the
|
||||||
|
meta system treats the wrapped type as a sequence container. In a similar way,
|
||||||
|
a type is treated as an associative container if a specialization of the
|
||||||
|
`meta_associative_container_traits` class is found for it.<br/>
|
||||||
|
Proxy objects are returned by dedicated members of the `meta_any` class. The
|
||||||
|
following is a deliberately verbose example of how users can access a proxy
|
||||||
|
object for a sequence container:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::vector<int> vec{1, 2, 3};
|
||||||
|
entt::meta_any any = entt::forward_as_meta(vec);
|
||||||
|
|
||||||
|
if(any.type().is_sequence_container()) {
|
||||||
|
if(auto view = any.as_sequence_container(); view) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The method to use to get a proxy object for associative containers is
|
||||||
|
`as_associative_container` instead.<br/>
|
||||||
|
It's not necessary to perform a double check actually. Instead, it's enough to
|
||||||
|
query the meta type or verify that the proxy object is valid. In fact, proxies
|
||||||
|
are contextually convertible to bool to check for validity. For example, invalid
|
||||||
|
proxies are returned when the wrapped object isn't a container.<br/>
|
||||||
|
In all cases, users aren't expected to _reflect_ containers explicitly. It's
|
||||||
|
sufficient to assign a container for which a specialization of the traits
|
||||||
|
classes exists to a `meta_any` object to be able to get its proxy object.
|
||||||
|
|
||||||
|
The interface of the `meta_sequence_container` proxy object is the same for all
|
||||||
|
types of sequence containers, although the available features differ from case
|
||||||
|
to case. In particular:
|
||||||
|
|
||||||
|
* The `value_type` member function returns the meta type of the elements.
|
||||||
|
|
||||||
|
* The `size` member function returns the number of elements in the container as
|
||||||
|
an unsigned integer value.
|
||||||
|
|
||||||
|
* The `resize` member function allows to resize the wrapped container and
|
||||||
|
returns true in case of success.<br/>
|
||||||
|
For example, it's not possible to resize fixed size containers.
|
||||||
|
|
||||||
|
* The `clear` member function allows to clear the wrapped container and returns
|
||||||
|
true in case of success.<br/>
|
||||||
|
For example, it's not possible to clear fixed size containers.
|
||||||
|
|
||||||
|
* The `begin` and `end` member functions return opaque iterators that is used to
|
||||||
|
iterate the container directly:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(entt::meta_any element: view) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In all cases, given an underlying container of type `C`, the returned element
|
||||||
|
contains an object of type `C::value_type` which therefore depends on the
|
||||||
|
actual container.<br/>
|
||||||
|
All meta iterators are input iterators and don't offer an indirection operator
|
||||||
|
on purpose.
|
||||||
|
|
||||||
|
* The `insert` member function is used to add elements to the container. It
|
||||||
|
accepts a meta iterator and the element to insert:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto last = view.end();
|
||||||
|
// appends an integer to the container
|
||||||
|
view.insert(last, 42);
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns a meta iterator pointing to the inserted element and a
|
||||||
|
boolean value to indicate whether the operation was successful or not. A call
|
||||||
|
to `insert` may silently fail in case of fixed size containers or whether the
|
||||||
|
arguments aren't at least convertible to the required types.<br/>
|
||||||
|
Since meta iterators are contextually convertible to bool, users can rely on
|
||||||
|
them to know if the operation failed on the actual container or upstream, for
|
||||||
|
example due to an argument conversion problem.
|
||||||
|
|
||||||
|
* The `erase` member function is used to remove elements from the container. It
|
||||||
|
accepts a meta iterator to the element to remove:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto first = view.begin();
|
||||||
|
// removes the first element from the container
|
||||||
|
view.erase(first);
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns a meta iterator following the last removed element and a
|
||||||
|
boolean value to indicate whether the operation was successful or not. A call
|
||||||
|
to `erase` may silently fail in case of fixed size containers.
|
||||||
|
|
||||||
|
* The `operator[]` is used to access container elements. It accepts a single
|
||||||
|
argument, the position of the element to return:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
|
||||||
|
entt::meta_any value = view[pos];
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The function returns instances of `meta_any` that directly refer to the actual
|
||||||
|
elements. Modifying the returned object directly modifies the element inside
|
||||||
|
the container.<br/>
|
||||||
|
Depending on the underlying sequence container, this operation may not be as
|
||||||
|
efficient. For example, in the case of an `std::list`, a positional access
|
||||||
|
translates to a linear visit of the list itself (probably not what the user
|
||||||
|
expects).
|
||||||
|
|
||||||
|
Similarly, also the interface of the `meta_associative_container` proxy object
|
||||||
|
is the same for all types of associative containers. However, there are some
|
||||||
|
differences in behavior in the case of key-only containers. In particular:
|
||||||
|
|
||||||
|
* The `key_only` member function returns true if the wrapped container is a
|
||||||
|
key-only one.
|
||||||
|
|
||||||
|
* The `key_type` member function returns the meta type of the keys.
|
||||||
|
|
||||||
|
* The `mapped_type` member function returns an invalid meta type for key-only
|
||||||
|
containers and the meta type of the mapped values for all other types of
|
||||||
|
containers.
|
||||||
|
|
||||||
|
* The `value_type` member function returns the meta type of the elements.<br/>
|
||||||
|
For example, it returns the meta type of `int` for `std::set<int>` while it
|
||||||
|
returns the meta type of `std::pair<const int, char>` for
|
||||||
|
`std::map<int, char>`.
|
||||||
|
|
||||||
|
* The `size` member function returns the number of elements in the container as
|
||||||
|
an unsigned integer value.
|
||||||
|
|
||||||
|
* The `clear` member function allows to clear the wrapped container and returns
|
||||||
|
true in case of success.
|
||||||
|
|
||||||
|
* The `begin` and `end` member functions return opaque iterators that are used
|
||||||
|
to iterate the container directly:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(std::pair<entt::meta_any, entt::meta_any> element: view) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In all cases, given an underlying container of type `C`, the returned element
|
||||||
|
is a key-value pair where the key has type `C::key_type` and the value has
|
||||||
|
type `C::mapped_type`. Since key-only containers don't have a mapped type,
|
||||||
|
their _value_ is nothing more than an invalid `meta_any` object.<br/>
|
||||||
|
All meta iterators are input iterators and don't offer an indirection operator
|
||||||
|
on purpose.
|
||||||
|
|
||||||
|
While the accessed key is usually constant in the associative containers and
|
||||||
|
is therefore returned by copy, the value (if any) is wrapped by an instance of
|
||||||
|
`meta_any` that directly refers to the actual element. Modifying it directly
|
||||||
|
modifies the element inside the container.
|
||||||
|
|
||||||
|
* The `insert` member function is used to add elements to a container. It gets
|
||||||
|
two arguments, respectively the key and the value to insert:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto last = view.end();
|
||||||
|
// appends an integer to the container
|
||||||
|
view.insert(last.handle(), 42, 'c');
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns a boolean value to indicate whether the operation was
|
||||||
|
successful or not. A call to `insert` may fail when the arguments aren't at
|
||||||
|
least convertible to the required types.
|
||||||
|
|
||||||
|
* The `erase` member function is used to remove elements from a container. It
|
||||||
|
gets a single argument, the key to remove:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
view.erase(42);
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns a boolean value to indicate whether the operation was
|
||||||
|
successful or not. A call to `erase` may fail when the argument isn't at least
|
||||||
|
convertible to the required type.
|
||||||
|
|
||||||
|
* The `operator[]` is used to access elements in a container. It gets a single
|
||||||
|
argument, the key of the element to return:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_any value = view[42];
|
||||||
|
```
|
||||||
|
|
||||||
|
The function returns instances of `meta_any` that directly refer to the actual
|
||||||
|
elements. Modifying the returned object directly modifies the element inside
|
||||||
|
the container.
|
||||||
|
|
||||||
|
Container support is minimal but likely sufficient to satisfy all needs.
|
||||||
|
|
||||||
|
## Pointer-like types
|
||||||
|
|
||||||
|
As with containers, it's also possible to _tell_ to the meta system which types
|
||||||
|
are _pointers_. This makes it possible to dereference instances of `meta_any`,
|
||||||
|
thus obtaining light _references_ to pointed objects that are also correctly
|
||||||
|
associated with their meta types.<br/>
|
||||||
|
To make the meta system recognize a type as _pointer-like_, users can specialize
|
||||||
|
the `is_meta_pointer_like` class. `EnTT` already exports the specializations for
|
||||||
|
some common classes. In particular:
|
||||||
|
|
||||||
|
* All types of raw pointers.
|
||||||
|
* `std::unique_ptr` and `std::shared_ptr`.
|
||||||
|
|
||||||
|
It's important to include the header file `pointer.hpp` to make these
|
||||||
|
specializations available to the compiler when needed.<br/>
|
||||||
|
The same file also contains many examples for the users that are interested in
|
||||||
|
making their own pointer-like types available to the meta system.
|
||||||
|
|
||||||
|
When a type is recognized as a pointer-like one by the meta system, it's
|
||||||
|
possible to dereference the instances of `meta_any` that contain these objects.
|
||||||
|
The following is a deliberately verbose example to show how to use this feature:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int value = 42;
|
||||||
|
// meta type equivalent to that of int *
|
||||||
|
entt::meta_any any{&value};
|
||||||
|
|
||||||
|
if(any.type().is_pointer_like()) {
|
||||||
|
// meta type equivalent to that of int
|
||||||
|
if(entt::meta_any ref = *any; ref) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It's not necessary to perform a double check. Instead, it's enough to query the
|
||||||
|
meta type or verify that the returned object is valid. For example, invalid
|
||||||
|
instances are returned when the wrapped object isn't a pointer-like type.<br/>
|
||||||
|
Dereferencing a pointer-like object returns an instance of `meta_any` which
|
||||||
|
_refers_ to the pointed object. Modifying it means modifying the pointed object
|
||||||
|
directly (unless the returned element is const).
|
||||||
|
|
||||||
|
In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
|
||||||
|
`EnTT` also supports classes that don't offer an `operator*`. In particular:
|
||||||
|
|
||||||
|
* It's possible to exploit a solution based on ADL lookup by offering a function
|
||||||
|
(also a template one) named `dereference_meta_pointer_like`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename Type>
|
||||||
|
Type & dereference_meta_pointer_like(const custom_pointer_type<Type> &ptr) {
|
||||||
|
return ptr.deref();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* When not in control of the type's namespace, it's possible to inject into the
|
||||||
|
`entt` namespace a specialization of the `adl_meta_pointer_like` class
|
||||||
|
template to bypass the adl lookup as a whole:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename Type>
|
||||||
|
struct entt::adl_meta_pointer_like<custom_pointer_type<Type>> {
|
||||||
|
static decltype(auto) dereference(const custom_pointer_type<Type> &ptr) {
|
||||||
|
return ptr.deref();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
In all other cases and when dereferencing a pointer works as expected regardless
|
||||||
|
of the pointed type, no user intervention is required.
|
||||||
|
|
||||||
|
## Template information
|
||||||
|
|
||||||
|
Meta types also provide a minimal set of information about the _nature_ of the
|
||||||
|
original type in case it's a class template.<br/>
|
||||||
|
By default, this works out of the box and requires no user action. However, it's
|
||||||
|
important to include the header file `template.hpp` to make this information
|
||||||
|
available to the compiler when needed.
|
||||||
|
|
||||||
|
Meta template information are easily found:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// this method returns true if the type is recognized as a class template specialization
|
||||||
|
if(auto type = entt::resolve<std::shared_ptr<my_type>>(); type.is_template_specialization()) {
|
||||||
|
// meta type of the class template conveniently wrapped by entt::meta_class_template_tag
|
||||||
|
auto class_type = type.template_type();
|
||||||
|
|
||||||
|
// number of template arguments
|
||||||
|
std::size_t arity = type.template_arity();
|
||||||
|
|
||||||
|
// meta type of the i-th argument
|
||||||
|
auto arg_type = type.template_arg(0u);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Typically, when template information for a type are required, what the library
|
||||||
|
provides is sufficient. However, there are some cases where a user may want more
|
||||||
|
details or a different set of information.<br/>
|
||||||
|
Consider the case of a class template that is meant to wrap function types:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename>
|
||||||
|
struct function_type;
|
||||||
|
|
||||||
|
template<typename Ret, typename... Args>
|
||||||
|
struct function_type<Ret(Args...)> {};
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, rather than the function type, it might be useful to provide the
|
||||||
|
return type and unpacked arguments as if they were different template parameters
|
||||||
|
for the original class template.<br/>
|
||||||
|
To achieve this, users must enter the library internals and provide their own
|
||||||
|
specialization for the class template `entt::meta_template_traits`, such as:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename Ret, typename... Args>
|
||||||
|
struct entt::meta_template_traits<function_type<Ret(Args...)>> {
|
||||||
|
using class_type = meta_class_template_tag<function_type>;
|
||||||
|
using args_type = type_list<Ret, Args...>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The reflection system doesn't verify the accuracy of the information nor infer a
|
||||||
|
correspondence between real types and meta types.<br/>
|
||||||
|
Therefore, the specialization is used as is and the information it contains is
|
||||||
|
associated with the appropriate type when required.
|
||||||
|
|
||||||
|
## Automatic conversions
|
||||||
|
|
||||||
|
In C++, there are a number of conversions allowed between arithmetic types that
|
||||||
|
make it convenient to work with this kind of data.<br/>
|
||||||
|
If this were to be translated into explicit registrations with the reflection
|
||||||
|
system, it would result in a long series of instructions such as the following:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<int>()
|
||||||
|
.conv<bool>()
|
||||||
|
.conv<char>()
|
||||||
|
// ...
|
||||||
|
.conv<double>();
|
||||||
|
```
|
||||||
|
|
||||||
|
Repeated for each type eligible to undergo this type of conversions. This is
|
||||||
|
both error-prone and repetitive.<br/>
|
||||||
|
Similarly, the language allows users to silently convert unscoped enums to their
|
||||||
|
underlying types and offers what it takes to do the same for scoped enums. It
|
||||||
|
would result in the following if it were to be done explicitly:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_enum>()
|
||||||
|
.conv<std::underlying_type_t<my_enum>>();
|
||||||
|
```
|
||||||
|
|
||||||
|
Fortunately, all of this can also be avoided. `EnTT` offers implicit support for
|
||||||
|
these types of conversions:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_any any{42};
|
||||||
|
any.allow_cast<double>();
|
||||||
|
double value = any.cast<double>();
|
||||||
|
```
|
||||||
|
|
||||||
|
With no need for registration, the conversion takes place automatically under
|
||||||
|
the hood. The same goes for a call to `allow_cast` involving a meta type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_type type = entt::resolve<int>();
|
||||||
|
entt::meta_any any{my_enum::a_value};
|
||||||
|
any.allow_cast(type);
|
||||||
|
int value = any.cast<int>();
|
||||||
|
```
|
||||||
|
|
||||||
|
This makes working with arithmetic types and scoped or unscoped enums as easy as
|
||||||
|
it is in C++.<br/>
|
||||||
|
It's still possible to set up conversion functions manually and these are always
|
||||||
|
preferred over the automatic ones.
|
||||||
|
|
||||||
|
## Implicitly generated default constructor
|
||||||
|
|
||||||
|
Creating objects of default constructible types through the reflection system
|
||||||
|
while not having to explicitly register the meta type or its default constructor
|
||||||
|
is also possible.<br/>
|
||||||
|
For example, in the case of primitive types like `int` or `char`, but not just
|
||||||
|
them.
|
||||||
|
|
||||||
|
For default constructible types only, default constructors are automatically
|
||||||
|
defined and associated with their meta types, whether they are explicitly or
|
||||||
|
implicitly generated.<br/>
|
||||||
|
Therefore, this is all is needed to construct an integer from its meta type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::resolve<int>().construct();
|
||||||
|
```
|
||||||
|
|
||||||
|
Where the meta type is for example the one returned from a meta container,
|
||||||
|
useful for building keys without knowing or having to register the actual types.
|
||||||
|
|
||||||
|
In all cases, when users register default constructors, they are preferred both
|
||||||
|
during searches and when the `construct` member function is invoked.
|
||||||
|
|
||||||
|
## From void to any
|
||||||
|
|
||||||
|
Sometimes all a user has is an opaque pointer to an object of a known meta type.
|
||||||
|
It would be handy in this case to be able to construct a `meta_any` element from
|
||||||
|
it.<br/>
|
||||||
|
For this purpose, the `meta_type` class offers a `from_void` member function
|
||||||
|
designed to convert an opaque pointer into a `meta_any`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_any any = entt::resolve(id).from_void(element);
|
||||||
|
```
|
||||||
|
|
||||||
|
Unfortunately, it's not possible to do a check on the actual type. Therefore,
|
||||||
|
this call can be considered as a _static cast_ with all its _problems_.<br/>
|
||||||
|
On the other hand, the ability to construct a `meta_any` from an opaque pointer
|
||||||
|
opens the door to some pretty interesting uses that are worth exploring.
|
||||||
|
|
||||||
|
## Policies: the more, the less
|
||||||
|
|
||||||
|
Policies are a kind of compile-time directives that can be used when registering
|
||||||
|
reflection information.<br/>
|
||||||
|
Their purpose is to require slightly different behavior than the default in some
|
||||||
|
specific cases. For example, when reading a given data member, its value is
|
||||||
|
returned wrapped in a `meta_any` object which, by default, makes a copy of it.
|
||||||
|
For large objects or if the caller wants to access the original instance, this
|
||||||
|
behavior isn't desirable. Policies are there to offer a solution to this and
|
||||||
|
other problems.
|
||||||
|
|
||||||
|
There are a few alternatives available at the moment:
|
||||||
|
|
||||||
|
* The _as-is_ policy, associated with the type `entt::as_is_t`.<br/>
|
||||||
|
This is the default policy. In general, it should never be used explicitly,
|
||||||
|
since it's implicitly selected if no other policy is specified.<br/>
|
||||||
|
In this case, the return values of the functions as well as the properties
|
||||||
|
exposed as data members are always returned by copy in a dedicated wrapper and
|
||||||
|
therefore associated with their original meta types.
|
||||||
|
|
||||||
|
* The _as-void_ policy, associated with the type `entt::as_void_t`.<br/>
|
||||||
|
Its purpose is to discard the return value of a meta object, whatever it is,
|
||||||
|
thus making it appear as if its type were `void`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
If the use with functions is obvious, perhaps less so is use with constructors
|
||||||
|
and data members. In the first case, the returned wrapper is always empty even
|
||||||
|
though the constructor is still invoked. In the second case, the property
|
||||||
|
isn't accessible for reading instead.
|
||||||
|
|
||||||
|
* The _as-ref_ and _as-cref_ policies, associated with the types
|
||||||
|
`entt::as_ref_t` and `entt::as_cref_t`.<br/>
|
||||||
|
They allow to build wrappers that act as references to unmanaged objects.
|
||||||
|
Accessing the object contained in the wrapper for which the _reference_ was
|
||||||
|
requested makes it possible to directly access the instance used to initialize
|
||||||
|
the wrapper itself:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
These policies work with constructors (for example, when objects are taken
|
||||||
|
from an external container rather than created on demand), data members and
|
||||||
|
functions in general.<br/>
|
||||||
|
If on the one hand `as_cref_t` always forces the return type to be const,
|
||||||
|
`as_ref_t` _adapts_ to the constness of the passed object and to that of the
|
||||||
|
return type if any.
|
||||||
|
|
||||||
|
Some uses are rather trivial, but it's useful to note that there are some less
|
||||||
|
obvious corner cases that can in turn be solved with the use of policies.
|
||||||
|
|
||||||
|
## Named constants and enums
|
||||||
|
|
||||||
|
As mentioned, the `data` member function is used to reflect constants of any
|
||||||
|
type.<br/>
|
||||||
|
This allows users to create meta types for enums that work exactly like any
|
||||||
|
other meta type built from a class. Similarly, arithmetic types are _enriched_
|
||||||
|
with constants of special meaning where required.<br/>
|
||||||
|
All values thus exported appear to users as if they were constant data members
|
||||||
|
of the reflected types. This avoids the need to _export_ what is the difference
|
||||||
|
between enums and classes in C++ directly in the space of the reflected types.
|
||||||
|
|
||||||
|
Exposing constant values or elements from an enum is quite simple:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_enum>()
|
||||||
|
.data<my_enum::a_value>("a_value"_hs)
|
||||||
|
.data<my_enum::another_value>("another_value"_hs);
|
||||||
|
|
||||||
|
entt::meta<int>().data<2048>("max_int"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
Accessing them is trivial as well. It's a matter of doing the following, as with
|
||||||
|
any other data member of a meta type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto value = entt::resolve<my_enum>().data("a_value"_hs).get({}).cast<my_enum>();
|
||||||
|
auto max = entt::resolve<int>().data("max_int"_hs).get({}).cast<int>();
|
||||||
|
```
|
||||||
|
|
||||||
|
All this happens behind the scenes without any allocation because of the small
|
||||||
|
object optimization performed by the `meta_any` class.
|
||||||
|
|
||||||
|
## Properties and meta objects
|
||||||
|
|
||||||
|
Sometimes (for example, when it comes to creating an editor) it might be useful
|
||||||
|
to attach properties to the meta objects created. Fortunately, this is possible
|
||||||
|
for most of them:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message");
|
||||||
|
```
|
||||||
|
|
||||||
|
Properties are always in the key/value form. The key is a numeric identifier,
|
||||||
|
mostly similar to the identifier used to register meta objects. There are no
|
||||||
|
restrictions on the type of the value instead, as long as it's movable.<br/>
|
||||||
|
Key only properties are also supported out of the box:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta<my_type>().type("reflected_type"_hs).prop(my_enum::key_only);
|
||||||
|
```
|
||||||
|
|
||||||
|
To attach multiple properties to a meta object, just invoke `prop` more than
|
||||||
|
once.<br/>
|
||||||
|
It's also possible to call `prop` at different times, as long as the factory is
|
||||||
|
reset to the meta object of interest.
|
||||||
|
|
||||||
|
The meta objects for which properties are supported are currently meta types,
|
||||||
|
meta data and meta functions.<br/>
|
||||||
|
These types also offer a couple of member functions named `prop` to iterate all
|
||||||
|
properties at once or to search a specific property by key:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// iterate all properties of a meta type
|
||||||
|
for(auto &&[id, prop]: entt::resolve<my_type>().prop()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for a given property by name
|
||||||
|
auto prop = entt::resolve<my_type>().prop("tooltip"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
Meta properties are objects having a fairly poor interface, all in all. They
|
||||||
|
only provide the `value` member function to retrieve the contained value in the
|
||||||
|
form of a `meta_any` object.
|
||||||
|
|
||||||
|
## Unregister types
|
||||||
|
|
||||||
|
A type registered with the reflection system can also be _unregistered_. This
|
||||||
|
means unregistering all its data members, member functions, conversion functions
|
||||||
|
and so on. However, base classes aren't unregistered as well, since they don't
|
||||||
|
necessarily depend on it.<br/>
|
||||||
|
Roughly speaking, unregistering a type means disconnecting all associated meta
|
||||||
|
objects from it and making its identifier no longer available:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_reset<my_type>();
|
||||||
|
```
|
||||||
|
|
||||||
|
It's also possible to reset types by their unique identifiers:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_reset("my_type"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, there exists a non-template overload of the `meta_reset` function that
|
||||||
|
doesn't accept arguments and resets all meta types at once:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_reset();
|
||||||
|
```
|
||||||
|
|
||||||
|
A type can be re-registered later with a completely different name and form.
|
||||||
|
|
||||||
|
## Meta context
|
||||||
|
|
||||||
|
All meta types and their parts are created at runtime and stored in a default
|
||||||
|
_context_. This is obtained via a service locator as:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto &&context = entt::locator<entt::meta_context>::value_or();
|
||||||
|
```
|
||||||
|
|
||||||
|
By itself, a context is an opaque object that the user cannot do much with.
|
||||||
|
However, users can replace an existing context with another at any time:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_context other{};
|
||||||
|
auto &&context = entt::locator<entt::meta_context>::value_or();
|
||||||
|
std::swap(context, other);
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful for testing purposes or to define multiple context objects with
|
||||||
|
different meta type to use as appropriate.
|
||||||
|
|
||||||
|
If _replacing_ the default context isn't enough, `EnTT` also offers the ability
|
||||||
|
to use multiple and externally managed contexts with the runtime reflection
|
||||||
|
system.<br/>
|
||||||
|
For example, to create new meta types within a context other than the default
|
||||||
|
one, simply pass it as an argument to the `meta` call:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_ctx context{};
|
||||||
|
auto factory = entt::meta<my_type>(context).type("reflected_type"_hs);
|
||||||
|
```
|
||||||
|
|
||||||
|
By doing so, the new meta type isn't available in the default context but is
|
||||||
|
usable by passing around the new context when needed, such as when creating a
|
||||||
|
new `meta_any` object:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_any any{context, std::in_place_type<my_type>};
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly, to search for meta types in a context other than the default one,
|
||||||
|
it's necessary to pass it to the `resolve` function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::meta_type type = entt::resolve(context, "reflected_type"_hs)
|
||||||
|
```
|
||||||
|
|
||||||
|
More generally, when using externally managed contexts, it's always required to
|
||||||
|
provide the system with the context to use, at least at the _entry point_.<br/>
|
||||||
|
For example, once the `meta_type` instant is obtained, it's no longer necessary
|
||||||
|
to pass the context around as the meta type takes the information with it and
|
||||||
|
eventually propagates it to all its parts.<br/>
|
||||||
|
On the other hand, it's necessary to instruct the library on where meta types
|
||||||
|
are to be fetched when `meta_any`s and `meta_handle`s are constructed, a factory
|
||||||
|
created or a meta type resolved.
|
357
external/entt/entt/docs/md/poly.md
vendored
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
# Crash Course: poly
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Other libraries](#other-libraries)
|
||||||
|
* [Concept and implementation](#concept-and-implementation)
|
||||||
|
* [Deduced interface](#deduced-interface)
|
||||||
|
* [Defined interface](#defined-interface)
|
||||||
|
* [Fulfill a concept](#fulfill-a-concept)
|
||||||
|
* [Inheritance](#inheritance)
|
||||||
|
* [Static polymorphism in the wild](#static-polymorphism-in-the-wild)
|
||||||
|
* [Storage size and alignment requirement](#storage-size-and-alignment-requirement)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Static polymorphism is a very powerful tool in C++, albeit sometimes cumbersome
|
||||||
|
to obtain.<br/>
|
||||||
|
This module aims to make it simple and easy to use.
|
||||||
|
|
||||||
|
The library allows to define _concepts_ as interfaces to fulfill with concrete
|
||||||
|
classes without having to inherit from a common base.<br/>
|
||||||
|
Among others, this is one of the advantages of static polymorphism in general
|
||||||
|
and of a generic wrapper like that offered by the `poly` class template in
|
||||||
|
particular.<br/>
|
||||||
|
The result is an object to pass around as such and not through a reference or a
|
||||||
|
pointer, as it happens when it comes to working with dynamic polymorphism.
|
||||||
|
|
||||||
|
Since the `poly` class template makes use of `entt::any` internally, it also
|
||||||
|
supports most of its feature. For example, the possibility to create aliases to
|
||||||
|
existing and thus unmanaged objects. This allows users to exploit the static
|
||||||
|
polymorphism while maintaining ownership of objects.<br/>
|
||||||
|
Likewise, the `poly` class template also benefits from the small buffer
|
||||||
|
optimization offered by the `entt::any` class and therefore minimizes the number
|
||||||
|
of allocations, avoiding them altogether where possible.
|
||||||
|
|
||||||
|
## Other libraries
|
||||||
|
|
||||||
|
There are some very interesting libraries regarding static polymorphism.<br/>
|
||||||
|
The ones that I like more are:
|
||||||
|
|
||||||
|
* [`dyno`](https://github.com/ldionne/dyno): runtime polymorphism done right.
|
||||||
|
* [`Poly`](https://github.com/facebook/folly/blob/master/folly/docs/Poly.md):
|
||||||
|
a class template that makes it easy to define a type-erasing polymorphic
|
||||||
|
object wrapper.
|
||||||
|
|
||||||
|
The former is admittedly an experimental library, with many interesting ideas.
|
||||||
|
I've some doubts about the usefulness of some feature in real world projects,
|
||||||
|
but perhaps my lack of experience comes into play here. In my opinion, its only
|
||||||
|
flaw is the API which I find slightly more cumbersome than other solutions.<br/>
|
||||||
|
The latter was undoubtedly a source of inspiration for this module, although I
|
||||||
|
opted for different choices in the implementation of both the final API and some
|
||||||
|
feature.
|
||||||
|
|
||||||
|
Either way, the authors are gurus of the C++ community, people I only have to
|
||||||
|
learn from.
|
||||||
|
|
||||||
|
# Concept and implementation
|
||||||
|
|
||||||
|
The first thing to do to create a _type-erasing polymorphic object wrapper_ (to
|
||||||
|
use the terminology introduced by Eric Niebler) is to define a _concept_ that
|
||||||
|
types will have to adhere to.<br/>
|
||||||
|
For this purpose, the library offers a single class that supports both deduced
|
||||||
|
and fully defined interfaces. Although having interfaces deduced automatically
|
||||||
|
is convenient and allows users to write less code in most cases, it has some
|
||||||
|
limitations and it's therefore useful to be able to get around the deduction by
|
||||||
|
providing a custom definition for the static virtual table.
|
||||||
|
|
||||||
|
Once the interface is defined, a generic implementation is needed to fulfill the
|
||||||
|
concept itself.<br/>
|
||||||
|
Also in this case, the library allows customizations based on types or families
|
||||||
|
of types, so as to be able to go beyond the generic case where necessary.
|
||||||
|
|
||||||
|
## Deduced interface
|
||||||
|
|
||||||
|
This is how a concept with a deduced interface is defined:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Drawable: entt::type_list<> {
|
||||||
|
template<typename Base>
|
||||||
|
struct type: Base {
|
||||||
|
void draw() { this->template invoke<0>(*this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
It's recognizable by the fact that it inherits from an empty type list.<br/>
|
||||||
|
Functions can also be const, accept any number of parameters and return a type
|
||||||
|
other than `void`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Drawable: entt::type_list<> {
|
||||||
|
template<typename Base>
|
||||||
|
struct type: Base {
|
||||||
|
bool draw(int pt) const { return this->template invoke<0>(*this, pt); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, all parameters are passed to `invoke` after the reference to
|
||||||
|
`this` and the return value is whatever the internal call returns.<br/>
|
||||||
|
As for `invoke`, this is a name that is injected into the _concept_ through
|
||||||
|
`Base`, from which one must necessarily inherit. Since it's also a dependent
|
||||||
|
name, the `this-> template` form is unfortunately necessary due to the rules of
|
||||||
|
the language. However, there also exists an alternative that goes through an
|
||||||
|
external call:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Drawable: entt::type_list<> {
|
||||||
|
template<typename Base>
|
||||||
|
struct type: Base {
|
||||||
|
void draw() const { entt::poly_call<0>(*this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Once the _concept_ is defined, users must provide a generic implementation of it
|
||||||
|
in order to tell the system how any type can satisfy its requirements. This is
|
||||||
|
done via an alias template within the concept itself.<br/>
|
||||||
|
The index passed as a template parameter to either `invoke` or `poly_call`
|
||||||
|
refers to how this alias is defined.
|
||||||
|
|
||||||
|
## Defined interface
|
||||||
|
|
||||||
|
A fully defined concept is no different to one for which the interface is
|
||||||
|
deduced, with the only difference that the list of types is not empty this time:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Drawable: entt::type_list<void()> {
|
||||||
|
template<typename Base>
|
||||||
|
struct type: Base {
|
||||||
|
void draw() { entt::poly_call<0>(*this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Again, parameters and return values other than `void` are allowed. Also, the
|
||||||
|
function type must be const when the method to bind to it is const:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Drawable: entt::type_list<bool(int) const> {
|
||||||
|
template<typename Base>
|
||||||
|
struct type: Base {
|
||||||
|
bool draw(int pt) const { return entt::poly_call<0>(*this, pt); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Why should a user fully define a concept if the function types are the same as
|
||||||
|
the deduced ones?<br>
|
||||||
|
In fact, this is the limitation that can be worked around by manually defining
|
||||||
|
the static virtual table.
|
||||||
|
|
||||||
|
When things are deduced, there is an implicit constraint.<br/>
|
||||||
|
If the concept exposes a member function called `draw` with function type
|
||||||
|
`void()`, a concept is satisfied:
|
||||||
|
|
||||||
|
* Either by a class that exposes a member function with the same name and the
|
||||||
|
same signature.
|
||||||
|
|
||||||
|
* Or through a lambda that makes use of existing member functions from the
|
||||||
|
interface itself.
|
||||||
|
|
||||||
|
In other words, it's not possible to make use of functions not belonging to the
|
||||||
|
interface, even if they're part of the types that fulfill the concept.<br/>
|
||||||
|
Similarly, it's not possible to deduce a function in the static virtual table
|
||||||
|
with a function type different from that of the associated member function in
|
||||||
|
the interface itself.
|
||||||
|
|
||||||
|
Explicitly defining a static virtual table suppresses the deduction step and
|
||||||
|
allows maximum flexibility when providing the implementation for a concept.
|
||||||
|
|
||||||
|
## Fulfill a concept
|
||||||
|
|
||||||
|
The `impl` alias template of a concept is used to define how it's fulfilled:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Drawable: entt::type_list<> {
|
||||||
|
// ...
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
using impl = entt::value_list<&Type::draw>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, it's stated that the `draw` method of a generic type is enough to
|
||||||
|
satisfy the requirements of the `Drawable` concept.<br/>
|
||||||
|
Both member functions and free functions are supported to fulfill concepts:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename Type>
|
||||||
|
void print(Type &self) { self.print(); }
|
||||||
|
|
||||||
|
struct Drawable: entt::type_list<void()> {
|
||||||
|
// ...
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
using impl = entt::value_list<&print<Type>>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Likewise, as long as the parameter types and return type support conversions to
|
||||||
|
and from those of the function type referenced in the static virtual table, the
|
||||||
|
actual implementation may differ in its function type since it's erased
|
||||||
|
internally.<br/>
|
||||||
|
Moreover, the `self` parameter isn't strictly required by the system and can be
|
||||||
|
left out for free functions if not required.
|
||||||
|
|
||||||
|
Refer to the inline documentation for more details.
|
||||||
|
|
||||||
|
# Inheritance
|
||||||
|
|
||||||
|
_Concept inheritance_ is straightforward due to how poly looks like in `EnTT`.
|
||||||
|
Therefore, it's quite easy to build hierarchies of concepts if necessary.<br/>
|
||||||
|
The only constraint is that all concepts in a hierarchy must belong to the same
|
||||||
|
_family_, that is, they must be either all deduced or all defined.
|
||||||
|
|
||||||
|
For a deduced concept, inheritance is achieved in a few steps:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct DrawableAndErasable: entt::type_list<> {
|
||||||
|
template<typename Base>
|
||||||
|
struct type: typename Drawable::template type<Base> {
|
||||||
|
static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<Drawable>::type>;
|
||||||
|
void erase() { entt::poly_call<base + 0>(*this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
using impl = entt::value_list_cat_t<
|
||||||
|
typename Drawable::impl<Type>,
|
||||||
|
entt::value_list<&Type::erase>
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The static virtual table is empty and must remain so.<br/>
|
||||||
|
On the other hand, `type` no longer inherits from `Base`. Instead, it forwards
|
||||||
|
its template parameter to the type exposed by the _base class_. Internally, the
|
||||||
|
_size_ of the static virtual table of the base class is used as an offset for
|
||||||
|
the local indexes.<br/>
|
||||||
|
Finally, by means of the `value_list_cat_t` utility, the implementation consists
|
||||||
|
in appending the new functions to the previous list.
|
||||||
|
|
||||||
|
As for a defined concept instead, the list of types is _extended_ in a similar
|
||||||
|
way to what is shown for the implementation of the above concept.<br/>
|
||||||
|
To do this, it's useful to declare a function that allows to convert a _concept_
|
||||||
|
into its underlying `type_list` object:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename... Type>
|
||||||
|
entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);
|
||||||
|
```
|
||||||
|
|
||||||
|
The definition isn't strictly required, since the function is only used through
|
||||||
|
a `decltype` as it follows:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct DrawableAndErasable: entt::type_list_cat_t<
|
||||||
|
decltype(as_type_list(std::declval<Drawable>())),
|
||||||
|
entt::type_list<void()>
|
||||||
|
> {
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Similar to above, `type_list_cat_t` is used to concatenate the underlying static
|
||||||
|
virtual table with the new function types.<br/>
|
||||||
|
Everything else is the same as already shown instead.
|
||||||
|
|
||||||
|
# Static polymorphism in the wild
|
||||||
|
|
||||||
|
Once the _concept_ and implementation are defined, it's possible to use the
|
||||||
|
`poly` class template to _wrap_ instances that meet the requirements:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using drawable = entt::poly<Drawable>;
|
||||||
|
|
||||||
|
struct circle {
|
||||||
|
void draw() { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct square {
|
||||||
|
void draw() { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
drawable instance{circle{}};
|
||||||
|
instance->draw();
|
||||||
|
|
||||||
|
instance = square{};
|
||||||
|
instance->draw();
|
||||||
|
```
|
||||||
|
|
||||||
|
This class offers a wide range of constructors, from the default one (which
|
||||||
|
returns an uninitialized `poly` object) to the copy and move constructors, as
|
||||||
|
well as the ability to create objects in-place.<br/>
|
||||||
|
Among others, there is also a constructor that allows users to wrap unmanaged
|
||||||
|
objects in a `poly` instance (either const or non-const ones):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
circle shape;
|
||||||
|
drawable instance{std::in_place_type<circle &>, shape};
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly, it's possible to create non-owning copies of `poly` from an existing
|
||||||
|
object:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
drawable other = instance.as_ref();
|
||||||
|
```
|
||||||
|
|
||||||
|
In both cases, although the interface of the `poly` object doesn't change, it
|
||||||
|
doesn't construct any element or take care of destroying the referenced objects.
|
||||||
|
|
||||||
|
Note also how the underlying concept is accessed via a call to `operator->` and
|
||||||
|
not directly as `instance.draw()`.<br/>
|
||||||
|
This allows users to decouple the API of the wrapper from that of the concept.
|
||||||
|
Therefore, where `instance.data()` invokes the `data` member function of the
|
||||||
|
poly object, `instance->data()` maps directly to the functionality exposed by
|
||||||
|
the underlying concept.
|
||||||
|
|
||||||
|
# Storage size and alignment requirement
|
||||||
|
|
||||||
|
Under the hood, the `poly` class template makes use of `entt::any`. Therefore,
|
||||||
|
it can take advantage of the possibility of defining at compile-time the size of
|
||||||
|
the storage suitable for the small buffer optimization as well as the alignment
|
||||||
|
requirements:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::basic_poly<Drawable, sizeof(double[4]), alignof(double[4])>
|
||||||
|
```
|
||||||
|
|
||||||
|
The default size is `sizeof(double[2])`, which seems like a good compromise
|
||||||
|
between a buffer that is too large and one unable to hold anything larger than
|
||||||
|
an integer. The alignment requirement is optional and by default such that it's
|
||||||
|
the most stringent (the largest) for any object whose size is at most equal to
|
||||||
|
the one provided.<br/>
|
||||||
|
It's worth noting that providing a size of 0 (which is an accepted value in all
|
||||||
|
respects) will force the system to dynamically allocate the contained objects in
|
||||||
|
all cases.
|
217
external/entt/entt/docs/md/process.md
vendored
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
# Crash Course: cooperative scheduler
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [The process](#the-process)
|
||||||
|
* [Adaptor](#adaptor)
|
||||||
|
* [The scheduler](#the-scheduler)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Processes are a useful tool to work around the strict definition of a system and
|
||||||
|
introduce logic in a different way, usually without resorting to other component
|
||||||
|
types.<br/>
|
||||||
|
`EnTT` offers minimal support to this paradigm by introducing a few classes used
|
||||||
|
to define and execute cooperative processes.
|
||||||
|
|
||||||
|
# The process
|
||||||
|
|
||||||
|
A typical task inherits from the `process` class template that stays true to the
|
||||||
|
CRTP idiom. Moreover, derived classes specify what the intended type for elapsed
|
||||||
|
times is.
|
||||||
|
|
||||||
|
A process should expose publicly the following member functions whether needed
|
||||||
|
(note that it isn't required to define a function unless the derived class wants
|
||||||
|
to _override_ the default behavior):
|
||||||
|
|
||||||
|
* `void update(Delta, void *);`
|
||||||
|
|
||||||
|
This is invoked once per tick until a process is explicitly aborted or ends
|
||||||
|
either with or without errors. Even though it's not mandatory to declare this
|
||||||
|
member function, as a rule of thumb each process should at least define it to
|
||||||
|
work _properly_. The `void *` parameter is an opaque pointer to user data (if
|
||||||
|
any) forwarded directly to the process during an update.
|
||||||
|
|
||||||
|
* `void init();`
|
||||||
|
|
||||||
|
This is invoked when the process joins the running queue of a scheduler. It
|
||||||
|
happens usually as soon as the process is attached to the scheduler if it's a
|
||||||
|
top level one, otherwise when it replaces its parent if it's a _continuation_.
|
||||||
|
|
||||||
|
* `void succeeded();`
|
||||||
|
|
||||||
|
This is invoked in case of success, immediately after an update and during the
|
||||||
|
same tick.
|
||||||
|
|
||||||
|
* `void failed();`
|
||||||
|
|
||||||
|
This is invoked in case of errors, immediately after an update and during the
|
||||||
|
same tick.
|
||||||
|
|
||||||
|
* `void aborted();`
|
||||||
|
|
||||||
|
This is invoked only if a process is explicitly aborted. There is no guarantee
|
||||||
|
that it executes in the same tick, it depends solely on whether the process is
|
||||||
|
aborted immediately or not.
|
||||||
|
|
||||||
|
Derived classes can also change the internal state of a process by invoking
|
||||||
|
`succeed` and `fail`, as well as `pause` and `unpause` the process itself.<br/>
|
||||||
|
All these are protected member functions made available to manage the life cycle
|
||||||
|
of a process from a derived class.
|
||||||
|
|
||||||
|
Here is a minimal example for the sake of curiosity:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_process: entt::process<my_process, std::uint32_t> {
|
||||||
|
using delta_type = std::uint32_t;
|
||||||
|
|
||||||
|
my_process(delta_type delay)
|
||||||
|
: remaining{delay}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void update(delta_type delta, void *) {
|
||||||
|
remaining -= std::min(remaining, delta);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
if(!remaining) {
|
||||||
|
succeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
delta_type remaining;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adaptor
|
||||||
|
|
||||||
|
Lambdas and functors can't be used directly with a scheduler because they aren't
|
||||||
|
properly defined processes with managed life cycles.<br/>
|
||||||
|
This class helps in filling the gap and turning lambdas and functors into
|
||||||
|
full-featured processes usable by a scheduler.
|
||||||
|
|
||||||
|
The function call operator has a signature similar to the one of the `update`
|
||||||
|
function of a process but for the fact that it receives two extra callbacks to
|
||||||
|
invoke whenever a process terminates with success or with an error:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void(Delta delta, void *data, auto succeed, auto fail);
|
||||||
|
```
|
||||||
|
|
||||||
|
Parameters have the following meaning:
|
||||||
|
|
||||||
|
* `delta` is the elapsed time.
|
||||||
|
* `data` is an opaque pointer to user data if any, `nullptr` otherwise.
|
||||||
|
* `succeed` is a function to call when a process terminates with success.
|
||||||
|
* `fail` is a function to call when a process terminates with errors.
|
||||||
|
|
||||||
|
Both `succeed` and `fail` accept no parameters at all.
|
||||||
|
|
||||||
|
Note that usually users shouldn't worry about creating adaptors at all. A
|
||||||
|
scheduler creates them internally each and every time a lambda or a functor is
|
||||||
|
used as a process.
|
||||||
|
|
||||||
|
# The scheduler
|
||||||
|
|
||||||
|
A cooperative scheduler runs different processes and helps managing their life
|
||||||
|
cycles.
|
||||||
|
|
||||||
|
Each process is invoked once per tick. If it terminates, it's removed
|
||||||
|
automatically from the scheduler and it's never invoked again. Otherwise, it's
|
||||||
|
a good candidate to run one more time the next tick.<br/>
|
||||||
|
A process can also have a _child_. In this case, the parent process is replaced
|
||||||
|
with its child when it terminates and only if it returns with success. In case
|
||||||
|
of errors, both the parent process and its child are discarded. This way, it's
|
||||||
|
easy to create chain of processes to run sequentially.
|
||||||
|
|
||||||
|
Using a scheduler is straightforward. To create it, users must provide only the
|
||||||
|
type for the elapsed times and no arguments at all:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::basic_scheduler<std::uint64_t> scheduler;
|
||||||
|
```
|
||||||
|
|
||||||
|
Otherwise, the `scheduler` alias is also available for the most common cases. It
|
||||||
|
uses `std::uint32_t` as a default type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::scheduler scheduler;
|
||||||
|
```
|
||||||
|
|
||||||
|
The class has member functions to query its internal data structures, like
|
||||||
|
`empty` or `size`, as well as a `clear` utility to reset it to a clean state:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// checks if there are processes still running
|
||||||
|
const auto empty = scheduler.empty();
|
||||||
|
|
||||||
|
// gets the number of processes still running
|
||||||
|
entt::scheduler::size_type size = scheduler.size();
|
||||||
|
|
||||||
|
// resets the scheduler to its initial state and discards all the processes
|
||||||
|
scheduler.clear();
|
||||||
|
```
|
||||||
|
|
||||||
|
To attach a process to a scheduler there are mainly two ways:
|
||||||
|
|
||||||
|
* If the process inherits from the `process` class template, it's enough to
|
||||||
|
indicate its type and submit all the parameters required to construct it to
|
||||||
|
the `attach` member function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
scheduler.attach<my_process>(1000u);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Otherwise, in case of a lambda or a functor, it's enough to provide an
|
||||||
|
instance of the class to the `attach` member function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
scheduler.attach([](auto...){ /* ... */ });
|
||||||
|
```
|
||||||
|
|
||||||
|
In both cases, the return value is an opaque object that offers a `then` member
|
||||||
|
function used to create chains of processes to run sequentially.<br/>
|
||||||
|
As a minimal example of use:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// schedules a task in the form of a lambda function
|
||||||
|
scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
// appends a child in the form of another lambda function
|
||||||
|
.then([](auto delta, void *, auto succeed, auto fail) {
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
// appends a child in the form of a process class
|
||||||
|
.then<my_process>(1000u);
|
||||||
|
```
|
||||||
|
|
||||||
|
To update a scheduler and therefore all its processes, the `update` member
|
||||||
|
function is the way to go:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// updates all the processes, no user data are provided
|
||||||
|
scheduler.update(delta);
|
||||||
|
|
||||||
|
// updates all the processes and provides them with custom data
|
||||||
|
scheduler.update(delta, &data);
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition to these functions, the scheduler offers an `abort` member function
|
||||||
|
that is used to discard all the running processes at once:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// aborts all the processes abruptly ...
|
||||||
|
scheduler.abort(true);
|
||||||
|
|
||||||
|
// ... or gracefully during the next tick
|
||||||
|
scheduler.abort();
|
||||||
|
```
|
91
external/entt/entt/docs/md/reference.md
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# Similar projects
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Similar projects](#similar-projects)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
There are many projects similar to `EnTT`, both open source and not.<br/>
|
||||||
|
Some even borrowed some ideas from this library and expressed them in different
|
||||||
|
languages.<br/>
|
||||||
|
Others developed different architectures from scratch and therefore offer
|
||||||
|
alternative solutions with their pros and cons.
|
||||||
|
|
||||||
|
If you know of other similar projects out there, feel free to open an issue or a
|
||||||
|
PR and I'll be glad to add them to this page.<br/>
|
||||||
|
I hope the following lists can grow much more in the future.
|
||||||
|
|
||||||
|
# Similar projects
|
||||||
|
|
||||||
|
Below an incomplete list of similar projects that I've come across so far.<br/>
|
||||||
|
If some terms or designs aren't clear, I recommend referring to the
|
||||||
|
[_ECS Back and Forth_](https://skypjack.github.io/tags/#ecs) series for all the
|
||||||
|
details.
|
||||||
|
|
||||||
|
* C:
|
||||||
|
* [destral_ecs](https://github.com/roig/destral_ecs): a single-file ECS based
|
||||||
|
on sparse sets.
|
||||||
|
* [Diana](https://github.com/discoloda/Diana): an ECS that uses sparse sets to
|
||||||
|
keep track of entities in systems.
|
||||||
|
* [Flecs](https://github.com/SanderMertens/flecs): a multithreaded archetype
|
||||||
|
ECS based on semi-contiguous arrays rather than chunks.
|
||||||
|
* [lent](https://github.com/nem0/lent): the Donald Trump of the ECS libraries.
|
||||||
|
|
||||||
|
* C++:
|
||||||
|
* [decs](https://github.com/vblanco20-1/decs): a chunk based archetype ECS.
|
||||||
|
* [ecst](https://github.com/SuperV1234/ecst): a multithreaded compile-time
|
||||||
|
ECS that uses sparse sets to keep track of entities in systems.
|
||||||
|
* [EntityX](https://github.com/alecthomas/entityx): a bitset based ECS that
|
||||||
|
uses a single large matrix of components indexed with entities.
|
||||||
|
* [Gaia-ECS](https://github.com/richardbiely/gaia-ecs): a chunk based
|
||||||
|
archetype ECS.
|
||||||
|
* [Polypropylene](https://github.com/pmbittner/Polypropylene): a hybrid
|
||||||
|
solution between an ECS and dynamic mixins.
|
||||||
|
|
||||||
|
* C#
|
||||||
|
* [Arch](https://github.com/genaray/Arch): a simple, fast and _unity entities_
|
||||||
|
inspired archetype ECS with optional multithreading.
|
||||||
|
* [Entitas](https://github.com/sschmid/Entitas-CSharp): the ECS framework for
|
||||||
|
C# and Unity, where _reactive systems_ were invented.
|
||||||
|
* [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity
|
||||||
|
Component System framework.
|
||||||
|
* [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting
|
||||||
|
platform agnostic and table based ECS framework.
|
||||||
|
|
||||||
|
* Go:
|
||||||
|
* [gecs](https://github.com/tutumagi/gecs): a sparse sets based ECS inspired
|
||||||
|
by `EnTT`.
|
||||||
|
|
||||||
|
* Javascript:
|
||||||
|
* [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs):
|
||||||
|
an archetype ECS in TypeScript.
|
||||||
|
* [ecsy](https://github.com/MozillaReality/ecsy): I haven't had the time to
|
||||||
|
investigate the underlying design of `ecsy` but it looks cool anyway.
|
||||||
|
|
||||||
|
* Perl:
|
||||||
|
* [Game::Entities](https://gitlab.com/jjatria/perl-game-entities): a simple
|
||||||
|
entity registry for ECS designs inspired by `EnTT`.
|
||||||
|
|
||||||
|
* Raku:
|
||||||
|
* [Game::Entities](https://gitlab.com/jjatria/raku-game-entities): a simple
|
||||||
|
entity registry for ECS designs inspired by `EnTT`.
|
||||||
|
|
||||||
|
* Rust:
|
||||||
|
* [Legion](https://github.com/TomGillen/legion): a chunk based archetype ECS.
|
||||||
|
* [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from
|
||||||
|
`EnTT` and offers a sparse sets based ECS with grouping functionalities.
|
||||||
|
* [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set based ECS
|
||||||
|
written in Rust.
|
||||||
|
* [Specs](https://github.com/amethyst/specs): a parallel ECS based mainly on
|
||||||
|
hierarchical bitsets that allows different types of storage as needed.
|
||||||
|
|
||||||
|
* Zig
|
||||||
|
* [zig-ecs](https://github.com/prime31/zig-ecs): a _zig-ification_ of `EnTT`.
|
191
external/entt/entt/docs/md/resource.md
vendored
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
# Crash Course: resource management
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [The resource, the loader and the cache](#the-resource-the-loader-and-the-cache)
|
||||||
|
* [Resource handle](#resource-handle)
|
||||||
|
* [Loaders](#loader)
|
||||||
|
* [The cache class](#the-cache)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Resource management is usually one of the most critical parts of a game.
|
||||||
|
Solutions are often tuned to the particular application. There exist several
|
||||||
|
approaches and all of them are perfectly fine as long as they fit the
|
||||||
|
requirements of the piece of software in which they are used.<br/>
|
||||||
|
Examples are loading everything on start, loading on request, predictive
|
||||||
|
loading, and so on.
|
||||||
|
|
||||||
|
`EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different
|
||||||
|
cases.<br/>
|
||||||
|
Instead, the library comes with a minimal, general purpose resource cache that
|
||||||
|
might be useful in many cases.
|
||||||
|
|
||||||
|
# The resource, the loader and the cache
|
||||||
|
|
||||||
|
Resource, loader and cache are the three main actors for the purpose.<br/>
|
||||||
|
The _resource_ is an image, an audio, a video or any other type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_resource { const int value; };
|
||||||
|
```
|
||||||
|
|
||||||
|
The _loader_ is a callable type the aim of which is to load a specific resource:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_loader final {
|
||||||
|
using result_type = std::shared_ptr<my_resource>;
|
||||||
|
|
||||||
|
result_type operator()(int value) const {
|
||||||
|
// ...
|
||||||
|
return std::make_shared<my_resource>(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Its function operator can accept any arguments and should return a value of the
|
||||||
|
declared result type (`std::shared_ptr<my_resource>` in the example).<br/>
|
||||||
|
A loader can also overload its function call operator to make it possible to
|
||||||
|
construct the same or another resource from different lists of arguments.
|
||||||
|
|
||||||
|
Finally, a cache is a specialization of a class template tailored to a specific
|
||||||
|
resource and (optionally) a loader:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using my_cache = entt::resource_cache<my_resource, my_loader>;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
my_cache cache{};
|
||||||
|
```
|
||||||
|
|
||||||
|
The class is designed to create different caches for different resource types
|
||||||
|
and to manage each one independently in the most appropriate way.<br/>
|
||||||
|
As a (very) trivial example, audio tracks can survive in most of the scenes of
|
||||||
|
an application while meshes can be associated with a single scene only, then
|
||||||
|
discarded when a player leaves it.
|
||||||
|
|
||||||
|
## Resource handle
|
||||||
|
|
||||||
|
Resources aren't returned directly to the caller. Instead, they are wrapped in a
|
||||||
|
_resource handle_, an instance of the `entt::resource` class template.<br/>
|
||||||
|
For those who know the _flyweight design pattern_ already, that's exactly what
|
||||||
|
it is. To all others, this is the time to brush up on some notions instead.
|
||||||
|
|
||||||
|
A shared pointer could have been used as a resource handle. In fact, the default
|
||||||
|
implementation mostly maps the interface of its standard counterpart and only
|
||||||
|
adds a few things on top of it.<br/>
|
||||||
|
However, the handle in `EnTT` is designed as a standalone class template. This
|
||||||
|
is due to the fact that specializing a class in the standard library is often
|
||||||
|
undefined behavior while having the ability to specialize the handle for one,
|
||||||
|
more or all resource types could help over time.
|
||||||
|
|
||||||
|
## Loaders
|
||||||
|
|
||||||
|
A loader is responsible for _loading_ resources (quite obviously).<br/>
|
||||||
|
By default, it's just a callable object that forwards its arguments to the
|
||||||
|
resource itself. That is, a _passthrough type_. All the work is demanded to the
|
||||||
|
constructor(s) of the resource itself.<br/>
|
||||||
|
Loaders also are fully customizable as expected.
|
||||||
|
|
||||||
|
A custom loader is a class with at least one function call operator and a member
|
||||||
|
type named `result_type`.<br/>
|
||||||
|
The loader isn't required to return a resource handle. As long as `return_type`
|
||||||
|
is suitable for constructing a handle, that's fine.
|
||||||
|
|
||||||
|
When using the default handle, it expects a resource type which is convertible
|
||||||
|
to or suitable for constructing an `std::shared_ptr<Type>` (where `Type` is the
|
||||||
|
actual resource type).<br/>
|
||||||
|
In other terms, the loader should return shared pointers to the given resource
|
||||||
|
type. However, this isn't mandatory. Users can easily get around this constraint
|
||||||
|
by specializing both the handle and the loader.
|
||||||
|
|
||||||
|
A cache forwards all its arguments to the loader if required. This means that
|
||||||
|
loaders can also support tag dispatching to offer different loading policies:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_loader {
|
||||||
|
using result_type = std::shared_ptr<my_resource>;
|
||||||
|
|
||||||
|
struct from_disk_tag{};
|
||||||
|
struct from_network_tag{};
|
||||||
|
|
||||||
|
template<typename Args>
|
||||||
|
result_type operator()(from_disk_tag, Args&&... args) {
|
||||||
|
// ...
|
||||||
|
return std::make_shared<my_resource>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Args>
|
||||||
|
result_type operator()(from_network_tag, Args&&... args) {
|
||||||
|
// ...
|
||||||
|
return std::make_shared<my_resource>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This makes the whole loading logic quite flexible and easy to extend over time.
|
||||||
|
|
||||||
|
## The cache class
|
||||||
|
|
||||||
|
The cache is the class that is asked to _connect the dots_.<br/>
|
||||||
|
It loads the resources, stores them aside and returns handles as needed:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::resource_cache<my_resource, my_loader> cache{};
|
||||||
|
```
|
||||||
|
|
||||||
|
Under the hood, a cache is nothing more than a map where the key value has type
|
||||||
|
`entt::id_type` while the mapped value is whatever type its loader returns.<br/>
|
||||||
|
For this reason, it offers most of the functionalities a user would expect from
|
||||||
|
a map, such as `empty` or `size` and so on. Similarly, it's an iterable type
|
||||||
|
that also supports indexing by resource id:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for(auto [id, res]: cache) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
if(entt::resource<my_resource> res = cache["resource/id"_hs]; res) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Please, refer to the inline documentation for all the details about the other
|
||||||
|
functions (such as `contains` or `erase`).
|
||||||
|
|
||||||
|
Set aside the part of the API that this class _shares_ with a map, it also adds
|
||||||
|
something on top of it in order to address the most common requirements of a
|
||||||
|
resource cache.<br/>
|
||||||
|
In particular, it doesn't have an `emplace` member function which is replaced by
|
||||||
|
`load` and `force_load` instead (where the former loads a new resource only if
|
||||||
|
not present while the second triggers a forced loading in any case):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto ret = cache.load("resource/id"_hs);
|
||||||
|
|
||||||
|
// true only if the resource was not already present
|
||||||
|
const bool loaded = ret.second;
|
||||||
|
|
||||||
|
// takes the resource handle pointed to by the returned iterator
|
||||||
|
entt::resource<my_resource> res = ret.first->second;
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the hashed string is used for convenience in the example above.<br/>
|
||||||
|
Resource identifiers are nothing more than integral values. Therefore, plain
|
||||||
|
numbers as well as non-class enum value are accepted.
|
||||||
|
|
||||||
|
It's worth mentioning that the iterators of a cache as well as its indexing
|
||||||
|
operators return resource handles rather than instances of the mapped type.<br/>
|
||||||
|
Since the cache has no control over the loader and a resource isn't required to
|
||||||
|
also be convertible to bool, these handles can be invalid. This usually means an
|
||||||
|
error in the user logic but it may also be an _expected_ event.<br/>
|
||||||
|
It's therefore recommended to verify handles validity with a check in debug (for
|
||||||
|
example, when loading) or an appropriate logic in retail.
|
565
external/entt/entt/docs/md/signal.md
vendored
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
# Crash Course: events, signals and everything in between
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Delegate](#delegate)
|
||||||
|
* [Runtime arguments](#runtime-arguments)
|
||||||
|
* [Lambda support](#lambda-support)
|
||||||
|
* [Raw access](#raw-access)
|
||||||
|
* [Signals](#signals)
|
||||||
|
* [Event dispatcher](#event-dispatcher)
|
||||||
|
* [Named queues](#named-queues)
|
||||||
|
* [Event emitter](#event-emitter)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Signals are more often than not a core part of games and software architectures
|
||||||
|
in general.<br/>
|
||||||
|
They help to decouple the various parts of a system while allowing them to
|
||||||
|
communicate with each other somehow.
|
||||||
|
|
||||||
|
The so called _modern C++_ comes with a tool that can be useful in this regard,
|
||||||
|
the `std::function`. As an example, it can be used to create delegates.<br/>
|
||||||
|
However, there is no guarantee that an `std::function` doesn't perform
|
||||||
|
allocations under the hood and this could be problematic sometimes. Furthermore,
|
||||||
|
it solves a problem but may not adapt well to other requirements that may arise
|
||||||
|
from time to time.
|
||||||
|
|
||||||
|
In case that the flexibility and power of an `std::function` isn't required or
|
||||||
|
if the price to pay for them is too high, `EnTT` offers a complete set of
|
||||||
|
lightweight classes to solve the same and many other problems.
|
||||||
|
|
||||||
|
# Delegate
|
||||||
|
|
||||||
|
A delegate can be used as a general purpose invoker with no memory overhead for
|
||||||
|
free functions, lambdas and members provided along with an instance on which to
|
||||||
|
invoke them.<br/>
|
||||||
|
It doesn't claim to be a drop-in replacement for an `std::function`, so don't
|
||||||
|
expect to use it whenever an `std::function` fits well. That said, it's most
|
||||||
|
likely even a better fit than an `std::function` in a lot of cases, so expect to
|
||||||
|
use it quite a lot anyway.
|
||||||
|
|
||||||
|
The interface is trivial. It offers a default constructor to create empty
|
||||||
|
delegates:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::delegate<int(int)> delegate{};
|
||||||
|
```
|
||||||
|
|
||||||
|
What is needed to create an instance is to specify the type of the function the
|
||||||
|
delegate _accepts_, that is the signature of the functions it models.<br/>
|
||||||
|
However, attempting to use an empty delegate by invoking its function call
|
||||||
|
operator results in undefined behavior or most likely a crash.
|
||||||
|
|
||||||
|
There exist a few overloads of the `connect` member function to initialize a
|
||||||
|
delegate:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int f(int i) { return i; }
|
||||||
|
|
||||||
|
struct my_struct {
|
||||||
|
int f(const int &i) const { return i; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// bind a free function to the delegate
|
||||||
|
delegate.connect<&f>();
|
||||||
|
|
||||||
|
// bind a member function to the delegate
|
||||||
|
my_struct instance;
|
||||||
|
delegate.connect<&my_struct::f>(instance);
|
||||||
|
```
|
||||||
|
|
||||||
|
The delegate class also accepts data members, if needed. In this case, the
|
||||||
|
function type of the delegate is such that the parameter list is empty and the
|
||||||
|
value of the data member is at least convertible to the return type.
|
||||||
|
|
||||||
|
Free functions having type equivalent to `void(T &, args...)` are accepted as
|
||||||
|
well. The first argument `T &` is considered a payload and the function will
|
||||||
|
receive it back every time it's invoked. In other terms, this works just fine
|
||||||
|
with the above definition:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void g(const char &c, int i) { /* ... */ }
|
||||||
|
const char c = 'c';
|
||||||
|
|
||||||
|
delegate.connect<&g>(c);
|
||||||
|
delegate(42);
|
||||||
|
```
|
||||||
|
|
||||||
|
Function `g` is invoked with a reference to `c` and `42`. However, the function
|
||||||
|
type of the delegate is still `void(int)`. This is also the signature of its
|
||||||
|
function call operator.<br/>
|
||||||
|
Another interesting aspect of the delegate class is that it accepts functions
|
||||||
|
with a list of parameters that is shorter than that of its function type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void g() { /* ... */ }
|
||||||
|
delegate.connect<&g>();
|
||||||
|
delegate(42);
|
||||||
|
```
|
||||||
|
|
||||||
|
Where the function type of the delegate is `void(int)` as above. It goes without
|
||||||
|
saying that the extra arguments are silently discarded internally. This is a
|
||||||
|
nice-to-have feature in a lot of cases, as an example when the `delegate` class
|
||||||
|
is used as a building block of a signal-slot system.<br/>
|
||||||
|
In fact, this filtering works both ways. The class tries to pass its first
|
||||||
|
_count_ arguments **first**, then the last _count_. Watch out for conversion
|
||||||
|
rules if in doubt when connecting a listener!<br/>
|
||||||
|
Arbitrary functions that pull random arguments from the delegate list aren't
|
||||||
|
supported instead. Other feature were preferred, such as support for functions
|
||||||
|
with compatible argument lists although not equal to those of the delegate.
|
||||||
|
|
||||||
|
To create and initialize a delegate at once, there are a few specialized
|
||||||
|
constructors. Because of the rules of the language, the listener is provided by
|
||||||
|
means of the `entt::connect_arg` variable template:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::delegate<int(int)> func{entt::connect_arg<&f>};
|
||||||
|
```
|
||||||
|
|
||||||
|
Aside `connect`, a `disconnect` counterpart isn't provided. Instead, there
|
||||||
|
exists a `reset` member function to use to clear a delegate.<br/>
|
||||||
|
To know if a delegate is empty, it can be used explicitly in every conditional
|
||||||
|
statement:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if(delegate) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, to invoke a delegate, the function call operator is the way to go as
|
||||||
|
already shown in the examples above:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto ret = delegate(42);
|
||||||
|
```
|
||||||
|
|
||||||
|
In all cases, listeners don't have to strictly follow the signature of the
|
||||||
|
delegate. As long as a listener can be invoked with the given arguments to yield
|
||||||
|
a result that is convertible to the given result type, everything works just
|
||||||
|
fine.
|
||||||
|
|
||||||
|
As a side note, members of classes may or may not be associated with instances.
|
||||||
|
If they are not, the first argument of the function type must be that of the
|
||||||
|
class on which the members operate and an instance of this class must obviously
|
||||||
|
be passed when invoking the delegate:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::delegate<void(my_struct &, int)> delegate;
|
||||||
|
delegate.connect<&my_struct::f>();
|
||||||
|
|
||||||
|
my_struct instance;
|
||||||
|
delegate(instance, 42);
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, it's not possible to _deduce_ the function type since the first
|
||||||
|
argument doesn't necessarily have to be a reference (for example, it can be a
|
||||||
|
pointer, as well as a const reference).<br/>
|
||||||
|
Therefore, the function type must be declared explicitly for unbound members.
|
||||||
|
|
||||||
|
## Runtime arguments
|
||||||
|
|
||||||
|
The `delegate` class is meant to be used primarily with template arguments.
|
||||||
|
However, as a consequence of its design, it also offers minimal support for
|
||||||
|
runtime arguments.<br/>
|
||||||
|
When used like this, some features aren't supported though. In particular:
|
||||||
|
|
||||||
|
* Curried functions aren't accepted.
|
||||||
|
* Functions with an argument list that differs from that of the delegate aren't
|
||||||
|
supported.
|
||||||
|
* Return type and types of arguments **must** coincide with those of the
|
||||||
|
delegate and _being at least convertible_ isn't enough anymore.
|
||||||
|
|
||||||
|
Moreover, for a given function type `Ret(Args...)`, the signature of the
|
||||||
|
functions connected at runtime must necessarily be `Ret(const void *, Args...)`.
|
||||||
|
|
||||||
|
Runtime arguments can be passed both to the constructor of a delegate and to the
|
||||||
|
`connect` member function. An optional parameter is also accepted in both cases.
|
||||||
|
This argument is used to pass arbitrary user data back and forth as a
|
||||||
|
`const void *` upon invocation.<br/>
|
||||||
|
To connect a function to a delegate _in the hard way_:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int func(const void *ptr, int i) { return *static_cast<const int *>(ptr) * i; }
|
||||||
|
const int value = 42;
|
||||||
|
|
||||||
|
// use the constructor ...
|
||||||
|
entt::delegate delegate{&func, &value};
|
||||||
|
|
||||||
|
// ... or the connect member function
|
||||||
|
delegate.connect(&func, &value);
|
||||||
|
```
|
||||||
|
|
||||||
|
The type of the delegate is deduced from the function if possible. In this case,
|
||||||
|
since the first argument is an implementation detail, the deduced function type
|
||||||
|
is `int(int)`.<br/>
|
||||||
|
Invoking a delegate built in this way follows the same rules as previously
|
||||||
|
explained.
|
||||||
|
|
||||||
|
## Lambda support
|
||||||
|
|
||||||
|
In general, the `delegate` class doesn't fully support lambda functions in all
|
||||||
|
their nuances. The reason is pretty simple: a `delegate` isn't a drop-in
|
||||||
|
replacement for an `std::function`. Instead, it tries to overcome the problems
|
||||||
|
with the latter.<br/>
|
||||||
|
That being said, non-capturing lambda functions are supported, even though some
|
||||||
|
features aren't available in this case.
|
||||||
|
|
||||||
|
This is a logical consequence of the support for connecting functions at
|
||||||
|
runtime. Therefore, lambda functions undergo the same rules and
|
||||||
|
limitations.<br/>
|
||||||
|
In fact, since non-capturing lambda functions decay to pointers to functions,
|
||||||
|
they can be used with a `delegate` as if they were _normal functions_ with
|
||||||
|
optional payload:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
my_struct instance;
|
||||||
|
|
||||||
|
// use the constructor ...
|
||||||
|
entt::delegate delegate{+[](const void *ptr, int value) {
|
||||||
|
return static_cast<const my_struct *>(ptr)->f(value);
|
||||||
|
}, &instance};
|
||||||
|
|
||||||
|
// ... or the connect member function
|
||||||
|
delegate.connect([](const void *ptr, int value) {
|
||||||
|
return static_cast<const my_struct *>(ptr)->f(value);
|
||||||
|
}, &instance);
|
||||||
|
```
|
||||||
|
|
||||||
|
As above, the first parameter (`const void *`) isn't part of the function type
|
||||||
|
of the delegate and is used to dispatch arbitrary user data back and forth. In
|
||||||
|
other terms, the function type of the delegate above is `int(int)`.
|
||||||
|
|
||||||
|
## Raw access
|
||||||
|
|
||||||
|
While not recommended, a delegate also allows direct access to the stored
|
||||||
|
callable function target and underlying data, if any.<br/>
|
||||||
|
This makes it possible to bypass the behavior of the delegate itself and force
|
||||||
|
calls on different instances:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
my_struct other;
|
||||||
|
delegate.target(&other, 42);
|
||||||
|
```
|
||||||
|
|
||||||
|
It goes without saying that this type of approach is **very** risky, especially
|
||||||
|
since there is no way of knowing whether the contained function was originally a
|
||||||
|
member function of some class, a free function or a lambda.<br/>
|
||||||
|
Another possible (and meaningful) use of this feature is that of identifying a
|
||||||
|
particular delegate through its descriptive _traits_ instead.
|
||||||
|
|
||||||
|
# Signals
|
||||||
|
|
||||||
|
Signal handlers work with references to classes, function pointers and pointers
|
||||||
|
to members. Listeners can be any kind of objects and users are in charge of
|
||||||
|
connecting and disconnecting them from a signal to avoid crashes due to
|
||||||
|
different lifetimes. On the other side, performance shouldn't be affected that
|
||||||
|
much by the presence of such a signal handler.<br/>
|
||||||
|
Signals make use of delegates internally and therefore they undergo the same
|
||||||
|
rules and offer similar functionalities. It may be a good idea to consult the
|
||||||
|
documentation of the `delegate` class for further information.
|
||||||
|
|
||||||
|
A signal handler is can be used as a private data member without exposing any
|
||||||
|
_publish_ functionality to the clients of a class.<br/>
|
||||||
|
The basic idea is to impose a clear separation between the signal itself and the
|
||||||
|
`sink` class, that is a tool to be used to connect and disconnect listeners on
|
||||||
|
the fly.
|
||||||
|
|
||||||
|
The API of a signal handler is straightforward. If a collector is supplied to
|
||||||
|
the signal when something is published, all the values returned by its listeners
|
||||||
|
are literally _collected_ and used later by the caller. Otherwise, the class
|
||||||
|
works just like a plain signal that emits events from time to time.<br/>
|
||||||
|
To create instances of signal handlers it's sufficient to provide the type of
|
||||||
|
function to which they refer:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
entt::sigh<void(int, char)> signal;
|
||||||
|
```
|
||||||
|
|
||||||
|
Signals offer all the basic functionalities required to know how many listeners
|
||||||
|
they contain (`size`) or if they contain at least a listener (`empty`), as well
|
||||||
|
as a function to use to swap handlers (`swap`).
|
||||||
|
|
||||||
|
Besides them, there are member functions to use both to connect and disconnect
|
||||||
|
listeners in all their forms by means of a sink:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void foo(int, char) { /* ... */ }
|
||||||
|
|
||||||
|
struct listener {
|
||||||
|
void bar(const int &, char) { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
entt::sink sink{signal};
|
||||||
|
listener instance;
|
||||||
|
|
||||||
|
sink.connect<&foo>();
|
||||||
|
sink.connect<&listener::bar>(instance);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// disconnects a free function
|
||||||
|
sink.disconnect<&foo>();
|
||||||
|
|
||||||
|
// disconnect a member function of an instance
|
||||||
|
sink.disconnect<&listener::bar>(instance);
|
||||||
|
|
||||||
|
// disconnect all member functions of an instance, if any
|
||||||
|
sink.disconnect(&instance);
|
||||||
|
|
||||||
|
// discards all listeners at once
|
||||||
|
sink.disconnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
As shown above, listeners don't have to strictly follow the signature of the
|
||||||
|
signal. As long as a listener can be invoked with the given arguments to yield a
|
||||||
|
result that is convertible to the given return type, everything works just
|
||||||
|
fine.<br/>
|
||||||
|
In all cases, the `connect` member function returns by default a `connection`
|
||||||
|
object to be used as an alternative to break a connection by means of its
|
||||||
|
`release` member function.<br/>
|
||||||
|
A `scoped_connection` can also be created from a connection. In this case, the
|
||||||
|
link is broken automatically as soon as the object goes out of scope.
|
||||||
|
|
||||||
|
Once listeners are attached (or even if there are no listeners at all), events
|
||||||
|
and data in general are published through a signal by means of the `publish`
|
||||||
|
member function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
signal.publish(42, 'c');
|
||||||
|
```
|
||||||
|
|
||||||
|
To collect data, the `collect` member function is used instead:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int f() { return 0; }
|
||||||
|
int g() { return 1; }
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
entt::sigh<int()> signal;
|
||||||
|
entt::sink sink{signal};
|
||||||
|
|
||||||
|
sink.connect<&f>();
|
||||||
|
sink.connect<&g>();
|
||||||
|
|
||||||
|
std::vector<int> vec{};
|
||||||
|
signal.collect([&vec](int value) { vec.push_back(value); });
|
||||||
|
|
||||||
|
assert(vec[0] == 0);
|
||||||
|
assert(vec[1] == 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
A collector must expose a function operator that accepts as an argument a type
|
||||||
|
to which the return type of the listeners can be converted. Moreover, it can
|
||||||
|
optionally return a boolean value that is true to stop collecting data, false
|
||||||
|
otherwise. This way one can avoid calling all the listeners in case it isn't
|
||||||
|
necessary.<br/>
|
||||||
|
Functors can also be used in place of a lambda. Since the collector is copied
|
||||||
|
when invoking the `collect` member function, `std::ref` is the way to go in this
|
||||||
|
case:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_collector {
|
||||||
|
std::vector<int> vec{};
|
||||||
|
|
||||||
|
bool operator()(int v) {
|
||||||
|
vec.push_back(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
my_collector collector;
|
||||||
|
signal.collect(std::ref(collector));
|
||||||
|
```
|
||||||
|
|
||||||
|
# Event dispatcher
|
||||||
|
|
||||||
|
The event dispatcher class allows users to trigger immediate events or to queue
|
||||||
|
and publish them all together later.<br/>
|
||||||
|
This class lazily instantiates its queues. Therefore, it's not necessary to
|
||||||
|
_announce_ the event types in advance:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// define a general purpose dispatcher
|
||||||
|
entt::dispatcher dispatcher{};
|
||||||
|
```
|
||||||
|
|
||||||
|
A listener registered with a dispatcher is such that its type offers one or more
|
||||||
|
member functions that take arguments of type `Event &` for any type of event,
|
||||||
|
regardless of the return value.<br/>
|
||||||
|
These functions are linked directly via `connect` to a _sink_:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct an_event { int value; };
|
||||||
|
struct another_event {};
|
||||||
|
|
||||||
|
struct listener {
|
||||||
|
void receive(const an_event &) { /* ... */ }
|
||||||
|
void method(const another_event &) { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
listener listener;
|
||||||
|
dispatcher.sink<an_event>().connect<&listener::receive>(listener);
|
||||||
|
dispatcher.sink<another_event>().connect<&listener::method>(listener);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that connecting listeners within event handlers can result in undefined
|
||||||
|
behavior.<br/>
|
||||||
|
The `disconnect` member function is used to remove one listener at a time or all
|
||||||
|
of them at once:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
dispatcher.sink<an_event>().disconnect<&listener::receive>(listener);
|
||||||
|
dispatcher.sink<another_event>().disconnect(&listener);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `trigger` member function serves the purpose of sending an immediate event
|
||||||
|
to all the listeners registered so far:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
dispatcher.trigger(an_event{42});
|
||||||
|
dispatcher.trigger<another_event>();
|
||||||
|
```
|
||||||
|
|
||||||
|
Listeners are invoked immediately, order of execution isn't guaranteed. This
|
||||||
|
method can be used to push around urgent messages like an _is terminating_
|
||||||
|
notification on a mobile app.
|
||||||
|
|
||||||
|
On the other hand, the `enqueue` member function queues messages together and
|
||||||
|
helps to maintain control over the moment they are sent to listeners:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
dispatcher.enqueue<an_event>(42);
|
||||||
|
dispatcher.enqueue(another_event{});
|
||||||
|
```
|
||||||
|
|
||||||
|
Events are stored aside until the `update` member function is invoked:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// emits all the events of the given type at once
|
||||||
|
dispatcher.update<an_event>();
|
||||||
|
|
||||||
|
// emits all the events queued so far at once
|
||||||
|
dispatcher.update();
|
||||||
|
```
|
||||||
|
|
||||||
|
This way users can embed the dispatcher in a loop and literally dispatch events
|
||||||
|
once per tick to their systems.
|
||||||
|
|
||||||
|
## Named queues
|
||||||
|
|
||||||
|
All queues within a dispatcher are associated by default with an event type and
|
||||||
|
then retrieved from it.<br/>
|
||||||
|
However, it's possible to create queues with different _names_ (and therefore
|
||||||
|
also multiple queues for a single type). In fact, more or less all functions
|
||||||
|
also take an additional parameter. As an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
dispatcher.sink<an_event>("custom"_hs).connect<&listener::receive>(listener);
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, the term _name_ is misused as these are actual numeric identifiers
|
||||||
|
of type `id_type`.<br/>
|
||||||
|
An exception to this rule is the `enqueue` function. There is no additional
|
||||||
|
parameter for it but rather a different function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
dispatcher.enqueue_hint<an_event>("custom"_hs, 42);
|
||||||
|
```
|
||||||
|
|
||||||
|
This is mainly due to the template argument deduction rules and unfortunately
|
||||||
|
there is no real (elegant) way to avoid it.
|
||||||
|
|
||||||
|
# Event emitter
|
||||||
|
|
||||||
|
A general purpose event emitter thought mainly for those cases where it comes to
|
||||||
|
working with asynchronous stuff.<br/>
|
||||||
|
Originally designed to fit the requirements of
|
||||||
|
[`uvw`](https://github.com/skypjack/uvw) (a wrapper for `libuv` written in
|
||||||
|
modern C++), it was adapted later to be included in this library.
|
||||||
|
|
||||||
|
To create an emitter type, derived classes must inherit from the base as:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_emitter: emitter<my_emitter> {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Handlers for the different events are created internally on the fly. It's not
|
||||||
|
required to specify in advance the full list of accepted events.<br/>
|
||||||
|
Moreover, whenever an event is published, an emitter also passes a reference
|
||||||
|
to itself to its listeners.
|
||||||
|
|
||||||
|
To create new instances of an emitter, no arguments are required:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
my_emitter emitter{};
|
||||||
|
```
|
||||||
|
|
||||||
|
Listeners are movable and callable objects (free functions, lambdas, functors,
|
||||||
|
`std::function`s, whatever) whose function type is compatible with:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void(Type &, my_emitter &)
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `Type` is the type of event they want to receive.<br/>
|
||||||
|
To attach a listener to an emitter, there exists the `on` member function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
emitter.on<my_event>([](const my_event &event, my_emitter &emitter) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly, the `reset` member function is used to disconnect listeners given a
|
||||||
|
type while `clear` is used to disconnect all listeners at once:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// resets the listener for my_event
|
||||||
|
emitter.erase<my_event>();
|
||||||
|
|
||||||
|
// resets all listeners
|
||||||
|
emitter.clear()
|
||||||
|
```
|
||||||
|
|
||||||
|
To send an event to the listener registered on a given type, the `publish`
|
||||||
|
function is the way to go:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct my_event { int i; };
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
emitter.publish(my_event{42});
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, the `empty` member function tests if there exists at least a listener
|
||||||
|
registered with the event emitter while `contains` is used to check if a given
|
||||||
|
event type is associated with a valid listener:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if(emitter.contains<my_event>()) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This class introduces a _nice-to-have_ model based on events and listeners.<br/>
|
||||||
|
More in general, it's a handy tool when the derived classes _wrap_ asynchronous
|
||||||
|
operations but it's not limited to such uses.
|
107
external/entt/entt/docs/md/unreal.md
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# EnTT and Unreal Engine
|
||||||
|
|
||||||
|
<!--
|
||||||
|
@cond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
* [Enable Cpp17](#enable-cpp17)
|
||||||
|
* [EnTT as a third party module](#entt-as-a-third-party-module)
|
||||||
|
* [Include EnTT](#include-entt)
|
||||||
|
<!--
|
||||||
|
@endcond TURN_OFF_DOXYGEN
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Enable Cpp17
|
||||||
|
|
||||||
|
As of writing (Unreal Engine v4.25), the default C++ standard of Unreal Engine
|
||||||
|
is C++14.<br/>
|
||||||
|
On the other hand, note that `EnTT` requires C++17 to compile. To enable it, in
|
||||||
|
the main module of the project there should be a `<Game Name>.Build.cs` file,
|
||||||
|
the constructor of which must contain the following lines:
|
||||||
|
|
||||||
|
```cs
|
||||||
|
PCHUsage = PCHUsageMode.NoSharedPCHs;
|
||||||
|
PrivatePCHHeaderFile = "<PCH filename>.h";
|
||||||
|
CppStandard = CppStandardVersion.Cpp17;
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `<PCH filename>.h` with the name of the already existing PCH header
|
||||||
|
file, if any.<br/>
|
||||||
|
In case the project doesn't already contain a file of this type, it's possible
|
||||||
|
to create one with the following content:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#pragma once
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
```
|
||||||
|
|
||||||
|
Remember to remove any old `PCHUsage = <...>` line that was previously there. At
|
||||||
|
this point, C++17 support should be in place.<br/>
|
||||||
|
Try to compile the project to ensure it works as expected before following
|
||||||
|
further steps.
|
||||||
|
|
||||||
|
Note that updating a *project* to C++17 doesn't necessarily mean that the IDE in
|
||||||
|
use will also start to recognize its syntax.<br/>
|
||||||
|
If the plan is to use C++17 in the project too, check the specific instructions
|
||||||
|
for the IDE in use.
|
||||||
|
|
||||||
|
## EnTT as a third party module
|
||||||
|
|
||||||
|
Once this point is reached, the `Source` directory should look like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
Source
|
||||||
|
| MyGame.Target.cs
|
||||||
|
| MyGameEditor.Target.cs
|
||||||
|
|
|
||||||
|
+---MyGame
|
||||||
|
| | MyGame.Build.cs
|
||||||
|
| | MyGame.h (PCH Header file)
|
||||||
|
|
|
||||||
|
\---ThirdParty
|
||||||
|
\---EnTT
|
||||||
|
| EnTT.Build.cs
|
||||||
|
|
|
||||||
|
\---entt (GitHub repository content inside)
|
||||||
|
```
|
||||||
|
|
||||||
|
To make this happen, create the folder `ThirdParty` under `Source` if it doesn't
|
||||||
|
exist already. Then, add an `EnTT` folder under `ThirdParty`.<br/>
|
||||||
|
Within the latter, create a new file `EnTT.Build.cs` with the following content:
|
||||||
|
|
||||||
|
```cs
|
||||||
|
using System.IO;
|
||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class EnTT: ModuleRules {
|
||||||
|
public EnTT(ReadOnlyTargetRules Target) : base(Target) {
|
||||||
|
Type = ModuleType.External;
|
||||||
|
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "entt", "src", "entt"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The last line indicates that the actual files will be found in the directory
|
||||||
|
`EnTT/entt/src/entt`.<br/>
|
||||||
|
Download the repository for `EnTT` and place it next to `EnTT.Build.cs` or
|
||||||
|
update the path above accordingly.
|
||||||
|
|
||||||
|
Finally, open the `<Game Name>.Build.cs` file and add `EnTT` as a dependency at
|
||||||
|
the end of the list:
|
||||||
|
|
||||||
|
```cs
|
||||||
|
PublicDependencyModuleNames.AddRange(new[] {
|
||||||
|
"Core", "CoreUObject", "Engine", "InputCore", [...], "EnTT"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that some IDEs might require a restart to start recognizing the new module
|
||||||
|
for code-highlighting features and such.
|
||||||
|
|
||||||
|
## Include EnTT
|
||||||
|
|
||||||
|
In any source file of the project, add `#include "entt.hpp"` or any other path
|
||||||
|
to the file from `EnTT` to use it.<br/>
|
||||||
|
Try to create a registry as `entt::registry registry;` to make sure everything
|
||||||
|
compiles fine.
|
34
external/entt/entt/entt.imp
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[
|
||||||
|
{ "include": [ "@<gtest/internal/.*>", "private", "<gtest/gtest.h>", "public" ] },
|
||||||
|
{ "include": [ "@<gtest/gtest-.*>", "private", "<gtest/gtest.h>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_map.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_set.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/any.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/family.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/hashed_string.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/ident.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/monostate.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_info.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_traits.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/entity.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/group.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/handle.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/helper.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/observer.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/organizer.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/registry.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/runtime_view.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/snapshot.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/sparse_set.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/storage.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/view.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/meta/fwd.hpp[\">]", "private", "<entt/meta/meta.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/poly/fwd.hpp[\">]", "private", "<entt/poly/poly.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/cache.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/loader.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/resource.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/delegate.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/dispatcher.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/emitter.hpp>", "public" ] },
|
||||||
|
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/sigh.hpp>", "public" ] }
|
||||||
|
]
|
3
external/entt/entt/natvis/entt/config.natvis
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
</AutoVisualizer>
|
33
external/entt/entt/natvis/entt/container.natvis
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::dense_map<*>">
|
||||||
|
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
|
||||||
|
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
|
||||||
|
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item>
|
||||||
|
<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item>
|
||||||
|
<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item>
|
||||||
|
<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item>
|
||||||
|
<IndexListItems>
|
||||||
|
<Size>size()</Size>
|
||||||
|
<ValueNode>packed.first_base::value[$i].element</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::dense_set<*>">
|
||||||
|
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
|
||||||
|
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
|
||||||
|
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item>
|
||||||
|
<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item>
|
||||||
|
<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item>
|
||||||
|
<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item>
|
||||||
|
<IndexListItems>
|
||||||
|
<Size>size()</Size>
|
||||||
|
<ValueNode>packed.first_base::value[$i].second</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
32
external/entt/entt/natvis/entt/core.natvis
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::basic_any<*>">
|
||||||
|
<DisplayString>{{ type={ info->alias,na }, policy={ mode,en } }}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::compressed_pair<*>">
|
||||||
|
<Intrinsic Name="first" Optional="true" Expression="((first_base*)this)->value"/>
|
||||||
|
<Intrinsic Name="first" Optional="true" Expression="*(first_base::base_type*)this"/>
|
||||||
|
<Intrinsic Name="second" Optional="true" Expression="((second_base*)this)->value"/>
|
||||||
|
<Intrinsic Name="second" Optional="true" Expression="*(second_base::base_type*)this"/>
|
||||||
|
<DisplayString >({ first() }, { second() })</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[first]">first()</Item>
|
||||||
|
<Item Name="[second]">second()</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::basic_hashed_string<*>">
|
||||||
|
<DisplayString Condition="base_type::repr != nullptr">{{ hash={ base_type::hash } }}</DisplayString>
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[data]">base_type::repr,na</Item>
|
||||||
|
<Item Name="[length]">base_type::length</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::type_info">
|
||||||
|
<DisplayString>{{ name={ alias,na } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[hash]">identifier</Item>
|
||||||
|
<Item Name="[index]">seq</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
123
external/entt/entt/natvis/entt/entity.natvis
vendored
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::basic_registry<*>">
|
||||||
|
<Intrinsic Name="to_entity" Expression="*((traits_type::entity_type *)&entity) & traits_type::entity_mask">
|
||||||
|
<Parameter Name="entity" Type="traits_type::value_type &"/>
|
||||||
|
</Intrinsic>
|
||||||
|
<DisplayString>{{ pools={ pools.size() } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[entities]">entities</Item>
|
||||||
|
<Synthetic Name="[pools]">
|
||||||
|
<DisplayString>{ pools.size() }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<IndexListItems ExcludeView="simple">
|
||||||
|
<Size>pools.size()</Size>
|
||||||
|
<ValueNode>*pools.packed.first_base::value[$i].element.second</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
<IndexListItems IncludeView="simple">
|
||||||
|
<Size>pools.size()</Size>
|
||||||
|
<ValueNode>*pools.packed.first_base::value[$i].element.second,view(simple)</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
<Item Name="[groups]" ExcludeView="simple">groups.size()</Item>
|
||||||
|
<Synthetic Name="[vars]">
|
||||||
|
<DisplayString>{ vars.ctx.size() }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<IndexListItems>
|
||||||
|
<Size>vars.ctx.size()</Size>
|
||||||
|
<ValueNode>vars.ctx.packed.first_base::value[$i].element.second</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::basic_sparse_set<*>">
|
||||||
|
<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item>
|
||||||
|
<Item Name="[policy]">mode,en</Item>
|
||||||
|
<Synthetic Name="[sparse]">
|
||||||
|
<DisplayString>{ sparse.size() * traits_type::page_size }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem IncludeView="simple">sparse,view(simple)</ExpandedItem>
|
||||||
|
<CustomListItems ExcludeView="simple">
|
||||||
|
<Variable Name="pos" InitialValue="0"/>
|
||||||
|
<Variable Name="page" InitialValue="0"/>
|
||||||
|
<Variable Name="offset" InitialValue="0"/>
|
||||||
|
<Variable Name="last" InitialValue="sparse.size() * traits_type::page_size"/>
|
||||||
|
<Loop>
|
||||||
|
<Break Condition="pos == last"/>
|
||||||
|
<Exec>page = pos / traits_type::page_size</Exec>
|
||||||
|
<Exec>offset = pos & (traits_type::page_size - 1)</Exec>
|
||||||
|
<If Condition="sparse[page] && (*((traits_type::entity_type *)&sparse[page][offset]) < ~traits_type::entity_mask)">
|
||||||
|
<Item Name="[{ pos }]">*((traits_type::entity_type *)&sparse[page][offset]) & traits_type::entity_mask</Item>
|
||||||
|
</If>
|
||||||
|
<Exec>++pos</Exec>
|
||||||
|
</Loop>
|
||||||
|
</CustomListItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
<Synthetic Name="[packed]">
|
||||||
|
<DisplayString>{ packed.size() }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem IncludeView="simple">packed,view(simple)</ExpandedItem>
|
||||||
|
<CustomListItems ExcludeView="simple">
|
||||||
|
<Variable Name="pos" InitialValue="0"/>
|
||||||
|
<Variable Name="last" InitialValue="packed.size()"/>
|
||||||
|
<Loop>
|
||||||
|
<Break Condition="pos == last"/>
|
||||||
|
<If Condition="*((traits_type::entity_type *)&packed[pos]) < ~traits_type::entity_mask">
|
||||||
|
<Item Name="[{ pos }]">packed[pos]</Item>
|
||||||
|
</If>
|
||||||
|
<Exec>++pos</Exec>
|
||||||
|
</Loop>
|
||||||
|
</CustomListItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::basic_storage<*>">
|
||||||
|
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[capacity]" Optional="true" ExcludeView="simple">payload.capacity() * traits_type::page_size</Item>
|
||||||
|
<Item Name="[page size]" Optional="true" ExcludeView="simple">traits_type::page_size</Item>
|
||||||
|
<Item Name="[length]" Optional="true" ExcludeView="simple">length</Item>
|
||||||
|
<Item Name="[base]" ExcludeView="simple">(base_type*)this,nand</Item>
|
||||||
|
<Item Name="[base]" IncludeView="simple">(base_type*)this,view(simple)nand</Item>
|
||||||
|
<!-- having SFINAE-like techniques in natvis is priceless :) -->
|
||||||
|
<CustomListItems Condition="payload.size() != 0" Optional="true">
|
||||||
|
<Variable Name="pos" InitialValue="0" />
|
||||||
|
<Variable Name="last" InitialValue="base_type::packed.size()"/>
|
||||||
|
<Loop>
|
||||||
|
<Break Condition="pos == last"/>
|
||||||
|
<If Condition="*((base_type::traits_type::entity_type *)&base_type::packed[pos]) < ~base_type::traits_type::entity_mask">
|
||||||
|
<Item Name="[{ pos }:{ base_type::packed[pos] }]">payload[pos / traits_type::page_size][pos & (traits_type::page_size - 1)]</Item>
|
||||||
|
</If>
|
||||||
|
<Exec>++pos</Exec>
|
||||||
|
</Loop>
|
||||||
|
</CustomListItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::basic_view<*>">
|
||||||
|
<DisplayString>{{ size_hint={ view->packed.size() } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[pools]">pools,na</Item>
|
||||||
|
<Item Name="[filter]">filter,na</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::basic_runtime_view<*>">
|
||||||
|
<DisplayString Condition="pools.size() != 0u">{{ size_hint={ pools[0]->packed.size() } }}</DisplayString>
|
||||||
|
<DisplayString>{{ size_hint=0 }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[pools]">pools,na</Item>
|
||||||
|
<Item Name="[filter]">filter,na</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::null_t">
|
||||||
|
<DisplayString><null></DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::tombstone_t">
|
||||||
|
<DisplayString><tombstone></DisplayString>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
19
external/entt/entt/natvis/entt/graph.natvis
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::adjacency_matrix<*>">
|
||||||
|
<DisplayString>{{ size={ vert } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<CustomListItems>
|
||||||
|
<Variable Name="pos" InitialValue="0" />
|
||||||
|
<Variable Name="last" InitialValue="vert * vert"/>
|
||||||
|
<Loop>
|
||||||
|
<Break Condition="pos == last"/>
|
||||||
|
<If Condition="matrix[pos] != 0u">
|
||||||
|
<Item Name="{pos / vert}">pos % vert</Item>
|
||||||
|
</If>
|
||||||
|
<Exec>++pos</Exec>
|
||||||
|
</Loop>
|
||||||
|
</CustomListItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
3
external/entt/entt/natvis/entt/locator.natvis
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
</AutoVisualizer>
|
121
external/entt/entt/natvis/entt/meta.natvis
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::internal::meta_base_node">
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::meta_conv_node">
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::meta_ctor_node">
|
||||||
|
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::meta_data_node">
|
||||||
|
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||||
|
<Parameter Name="property" Type="int"/>
|
||||||
|
</Intrinsic>
|
||||||
|
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[arity]">arity</Item>
|
||||||
|
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
|
||||||
|
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
|
||||||
|
<Item Name="[prop]">prop</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::meta_func_node" >
|
||||||
|
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||||
|
<Parameter Name="property" Type="int"/>
|
||||||
|
</Intrinsic>
|
||||||
|
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
|
||||||
|
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
|
||||||
|
<Item Name="[next]" Condition="next != nullptr">*next</Item>
|
||||||
|
<Item Name="[prop]">prop</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::meta_prop_node">
|
||||||
|
<DisplayString>{ value }</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::meta_template_node">
|
||||||
|
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::meta_type_node">
|
||||||
|
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||||
|
<Parameter Name="property" Type="int"/>
|
||||||
|
</Intrinsic>
|
||||||
|
<DisplayString Condition="info != nullptr">{{ type={ info->alias,na } }}</DisplayString>
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[id]">id</Item>
|
||||||
|
<Item Name="[sizeof]">size_of</Item>
|
||||||
|
<Item Name="[is_arithmetic]">has_property(entt::internal::meta_traits::is_arithmetic)</Item>
|
||||||
|
<Item Name="[is_integral]">has_property(entt::internal::meta_traits::is_integral)</Item>
|
||||||
|
<Item Name="[is_signed]">has_property(entt::internal::meta_traits::is_signed)</Item>
|
||||||
|
<Item Name="[is_array]">has_property(entt::internal::meta_traits::is_array)</Item>
|
||||||
|
<Item Name="[is_enum]">has_property(entt::internal::meta_traits::is_enum)</Item>
|
||||||
|
<Item Name="[is_class]">has_property(entt::internal::meta_traits::is_class)</Item>
|
||||||
|
<Item Name="[is_meta_pointer_like]">has_property(entt::internal::meta_traits::is_meta_pointer_like)</Item>
|
||||||
|
<Item Name="[is_meta_sequence_container]">has_property(entt::internal::meta_traits::is_meta_sequence_container)</Item>
|
||||||
|
<Item Name="[is_meta_associative_container]">has_property(entt::internal::meta_traits::is_meta_associative_container)</Item>
|
||||||
|
<Item Name="[default_constructor]">default_constructor != nullptr</Item>
|
||||||
|
<Item Name="[conversion_helper]">conversion_helper != nullptr</Item>
|
||||||
|
<Item Name="[from_void]">from_void != nullptr</Item>
|
||||||
|
<Item Name="[template_info]">templ</Item>
|
||||||
|
<Item Name="[details]" Condition="details != nullptr">*details</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_any">
|
||||||
|
<DisplayString Condition="node.info != nullptr">{{ type={ node.info->alias,na }, policy={ storage.mode,en } }}</DisplayString>
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem>node</ExpandedItem>
|
||||||
|
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_handle">
|
||||||
|
<DisplayString>{ any }</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_associative_container">
|
||||||
|
<DisplayString>{ storage }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_sequence_container">
|
||||||
|
<DisplayString>{ storage }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_data">
|
||||||
|
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||||
|
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_func">
|
||||||
|
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||||
|
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_prop">
|
||||||
|
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||||
|
<DisplayString>{{}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||||
|
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::meta_type">
|
||||||
|
<DisplayString>{ node }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem>node</ExpandedItem>
|
||||||
|
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
3
external/entt/entt/natvis/entt/platform.natvis
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
</AutoVisualizer>
|
6
external/entt/entt/natvis/entt/poly.natvis
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::basic_poly<*>">
|
||||||
|
<DisplayString>{ storage }</DisplayString>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
3
external/entt/entt/natvis/entt/process.natvis
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
</AutoVisualizer>
|
15
external/entt/entt/natvis/entt/resource.natvis
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::resource<*>">
|
||||||
|
<DisplayString>{ value }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem>value</ExpandedItem>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::resource_cache<*>">
|
||||||
|
<DisplayString>{ pool.first_base::value }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ExpandedItem>pool.first_base::value</ExpandedItem>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
55
external/entt/entt/natvis/entt/signal.natvis
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
<Type Name="entt::delegate<*>">
|
||||||
|
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[empty]">fn == nullptr</Item>
|
||||||
|
<Item Name="[data]">instance</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::basic_dispatcher<*>">
|
||||||
|
<Intrinsic Name="size" Expression="pools.first_base::value.size()"/>
|
||||||
|
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Synthetic Name="[pools]">
|
||||||
|
<DisplayString>{ size() }</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<IndexListItems>
|
||||||
|
<Size>size()</Size>
|
||||||
|
<ValueNode>*pools.first_base::value.packed.first_base::value[$i].element.second</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::internal::dispatcher_handler<*>">
|
||||||
|
<DisplayString>{{ size={ events.size() }, event={ "$T1" } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[signal]">signal</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::emitter<*>">
|
||||||
|
<DisplayString>{{ size={ handlers.first_base::value.packed.first_base::value.size() } }}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::connection">
|
||||||
|
<DisplayString>{{ bound={ signal != nullptr } }}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::scoped_connection">
|
||||||
|
<DisplayString>{ conn }</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::sigh<*>">
|
||||||
|
<DisplayString>{{ size={ calls.size() }, type={ "$T1" } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<IndexListItems>
|
||||||
|
<Size>calls.size()</Size>
|
||||||
|
<ValueNode>calls[$i]</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="entt::sink<*>">
|
||||||
|
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[signal]">signal,na</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
</AutoVisualizer>
|
299
external/entt/entt/scripts/amalgamate.py
vendored
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
# amalgamate.py - Amalgamate C source and header files.
|
||||||
|
# Copyright (c) 2012, Erik Edlund <erik.edlund@32767.se>
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# * Neither the name of Erik Edlund, nor the names of its contributors may
|
||||||
|
# be used to endorse or promote products derived from this software without
|
||||||
|
# specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class Amalgamation(object):
|
||||||
|
|
||||||
|
# Prepends self.source_path to file_path if needed.
|
||||||
|
def actual_path(self, file_path):
|
||||||
|
if not os.path.isabs(file_path):
|
||||||
|
file_path = os.path.join(self.source_path, file_path)
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
# Search included file_path in self.include_paths and
|
||||||
|
# in source_dir if specified.
|
||||||
|
def find_included_file(self, file_path, source_dir):
|
||||||
|
search_dirs = self.include_paths[:]
|
||||||
|
if source_dir:
|
||||||
|
search_dirs.insert(0, source_dir)
|
||||||
|
|
||||||
|
for search_dir in search_dirs:
|
||||||
|
search_path = os.path.join(search_dir, file_path)
|
||||||
|
if os.path.isfile(self.actual_path(search_path)):
|
||||||
|
return search_path
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __init__(self, args):
|
||||||
|
with open(args.config, 'r') as f:
|
||||||
|
config = json.loads(f.read())
|
||||||
|
for key in config:
|
||||||
|
setattr(self, key, config[key])
|
||||||
|
|
||||||
|
self.verbose = args.verbose == "yes"
|
||||||
|
self.prologue = args.prologue
|
||||||
|
self.source_path = args.source_path
|
||||||
|
self.included_files = []
|
||||||
|
|
||||||
|
# Generate the amalgamation and write it to the target file.
|
||||||
|
def generate(self):
|
||||||
|
amalgamation = ""
|
||||||
|
|
||||||
|
if self.prologue:
|
||||||
|
with open(self.prologue, 'r') as f:
|
||||||
|
amalgamation += datetime.datetime.now().strftime(f.read())
|
||||||
|
|
||||||
|
if self.verbose:
|
||||||
|
print("Config:")
|
||||||
|
print(" target = {0}".format(self.target))
|
||||||
|
print(" working_dir = {0}".format(os.getcwd()))
|
||||||
|
print(" include_paths = {0}".format(self.include_paths))
|
||||||
|
print("Creating amalgamation:")
|
||||||
|
for file_path in self.sources:
|
||||||
|
# Do not check the include paths while processing the source
|
||||||
|
# list, all given source paths must be correct.
|
||||||
|
# actual_path = self.actual_path(file_path)
|
||||||
|
print(" - processing \"{0}\"".format(file_path))
|
||||||
|
t = TranslationUnit(file_path, self, True)
|
||||||
|
amalgamation += t.content
|
||||||
|
|
||||||
|
with open(self.target, 'w') as f:
|
||||||
|
f.write(amalgamation)
|
||||||
|
|
||||||
|
print("...done!\n")
|
||||||
|
if self.verbose:
|
||||||
|
print("Files processed: {0}".format(self.sources))
|
||||||
|
print("Files included: {0}".format(self.included_files))
|
||||||
|
print("")
|
||||||
|
|
||||||
|
|
||||||
|
def _is_within(match, matches):
|
||||||
|
for m in matches:
|
||||||
|
if match.start() > m.start() and \
|
||||||
|
match.end() < m.end():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class TranslationUnit(object):
|
||||||
|
# // C++ comment.
|
||||||
|
cpp_comment_pattern = re.compile(r"//.*?\n")
|
||||||
|
|
||||||
|
# /* C comment. */
|
||||||
|
c_comment_pattern = re.compile(r"/\*.*?\*/", re.S)
|
||||||
|
|
||||||
|
# "complex \"stri\\\ng\" value".
|
||||||
|
string_pattern = re.compile("[^']" r'".*?(?<=[^\\])"', re.S)
|
||||||
|
|
||||||
|
# Handle simple include directives. Support for advanced
|
||||||
|
# directives where macros and defines needs to expanded is
|
||||||
|
# not a concern right now.
|
||||||
|
include_pattern = re.compile(
|
||||||
|
r'#\s*include\s+(<|")(?P<path>.*?)("|>)', re.S)
|
||||||
|
|
||||||
|
# #pragma once
|
||||||
|
pragma_once_pattern = re.compile(r'#\s*pragma\s+once', re.S)
|
||||||
|
|
||||||
|
# Search for pattern in self.content, add the match to
|
||||||
|
# contexts if found and update the index accordingly.
|
||||||
|
def _search_content(self, index, pattern, contexts):
|
||||||
|
match = pattern.search(self.content, index)
|
||||||
|
if match:
|
||||||
|
contexts.append(match)
|
||||||
|
return match.end()
|
||||||
|
return index + 2
|
||||||
|
|
||||||
|
# Return all the skippable contexts, i.e., comments and strings
|
||||||
|
def _find_skippable_contexts(self):
|
||||||
|
# Find contexts in the content in which a found include
|
||||||
|
# directive should not be processed.
|
||||||
|
skippable_contexts = []
|
||||||
|
|
||||||
|
# Walk through the content char by char, and try to grab
|
||||||
|
# skippable contexts using regular expressions when found.
|
||||||
|
i = 1
|
||||||
|
content_len = len(self.content)
|
||||||
|
while i < content_len:
|
||||||
|
j = i - 1
|
||||||
|
current = self.content[i]
|
||||||
|
previous = self.content[j]
|
||||||
|
|
||||||
|
if current == '"':
|
||||||
|
# String value.
|
||||||
|
i = self._search_content(j, self.string_pattern,
|
||||||
|
skippable_contexts)
|
||||||
|
elif current == '*' and previous == '/':
|
||||||
|
# C style comment.
|
||||||
|
i = self._search_content(j, self.c_comment_pattern,
|
||||||
|
skippable_contexts)
|
||||||
|
elif current == '/' and previous == '/':
|
||||||
|
# C++ style comment.
|
||||||
|
i = self._search_content(j, self.cpp_comment_pattern,
|
||||||
|
skippable_contexts)
|
||||||
|
else:
|
||||||
|
# Skip to the next char.
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return skippable_contexts
|
||||||
|
|
||||||
|
# Returns True if the match is within list of other matches
|
||||||
|
|
||||||
|
# Removes pragma once from content
|
||||||
|
def _process_pragma_once(self):
|
||||||
|
content_len = len(self.content)
|
||||||
|
if content_len < len("#include <x>"):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Find contexts in the content in which a found include
|
||||||
|
# directive should not be processed.
|
||||||
|
skippable_contexts = self._find_skippable_contexts()
|
||||||
|
|
||||||
|
pragmas = []
|
||||||
|
pragma_once_match = self.pragma_once_pattern.search(self.content)
|
||||||
|
while pragma_once_match:
|
||||||
|
if not _is_within(pragma_once_match, skippable_contexts):
|
||||||
|
pragmas.append(pragma_once_match)
|
||||||
|
|
||||||
|
pragma_once_match = self.pragma_once_pattern.search(self.content,
|
||||||
|
pragma_once_match.end())
|
||||||
|
|
||||||
|
# Handle all collected pragma once directives.
|
||||||
|
prev_end = 0
|
||||||
|
tmp_content = ''
|
||||||
|
for pragma_match in pragmas:
|
||||||
|
tmp_content += self.content[prev_end:pragma_match.start()]
|
||||||
|
prev_end = pragma_match.end()
|
||||||
|
tmp_content += self.content[prev_end:]
|
||||||
|
self.content = tmp_content
|
||||||
|
|
||||||
|
# Include all trivial #include directives into self.content.
|
||||||
|
def _process_includes(self):
|
||||||
|
content_len = len(self.content)
|
||||||
|
if content_len < len("#include <x>"):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Find contexts in the content in which a found include
|
||||||
|
# directive should not be processed.
|
||||||
|
skippable_contexts = self._find_skippable_contexts()
|
||||||
|
|
||||||
|
# Search for include directives in the content, collect those
|
||||||
|
# which should be included into the content.
|
||||||
|
includes = []
|
||||||
|
include_match = self.include_pattern.search(self.content)
|
||||||
|
while include_match:
|
||||||
|
if not _is_within(include_match, skippable_contexts):
|
||||||
|
include_path = include_match.group("path")
|
||||||
|
search_same_dir = include_match.group(1) == '"'
|
||||||
|
found_included_path = self.amalgamation.find_included_file(
|
||||||
|
include_path, self.file_dir if search_same_dir else None)
|
||||||
|
if found_included_path:
|
||||||
|
includes.append((include_match, found_included_path))
|
||||||
|
|
||||||
|
include_match = self.include_pattern.search(self.content,
|
||||||
|
include_match.end())
|
||||||
|
|
||||||
|
# Handle all collected include directives.
|
||||||
|
prev_end = 0
|
||||||
|
tmp_content = ''
|
||||||
|
for include in includes:
|
||||||
|
include_match, found_included_path = include
|
||||||
|
tmp_content += self.content[prev_end:include_match.start()]
|
||||||
|
tmp_content += "// {0}\n".format(include_match.group(0))
|
||||||
|
if found_included_path not in self.amalgamation.included_files:
|
||||||
|
t = TranslationUnit(found_included_path, self.amalgamation, False)
|
||||||
|
tmp_content += t.content
|
||||||
|
prev_end = include_match.end()
|
||||||
|
tmp_content += self.content[prev_end:]
|
||||||
|
self.content = tmp_content
|
||||||
|
|
||||||
|
return len(includes)
|
||||||
|
|
||||||
|
# Make all content processing
|
||||||
|
def _process(self):
|
||||||
|
if not self.is_root:
|
||||||
|
self._process_pragma_once()
|
||||||
|
self._process_includes()
|
||||||
|
|
||||||
|
def __init__(self, file_path, amalgamation, is_root):
|
||||||
|
self.file_path = file_path
|
||||||
|
self.file_dir = os.path.dirname(file_path)
|
||||||
|
self.amalgamation = amalgamation
|
||||||
|
self.is_root = is_root
|
||||||
|
|
||||||
|
self.amalgamation.included_files.append(self.file_path)
|
||||||
|
|
||||||
|
actual_path = self.amalgamation.actual_path(file_path)
|
||||||
|
if not os.path.isfile(actual_path):
|
||||||
|
raise IOError("File not found: \"{0}\"".format(file_path))
|
||||||
|
with open(actual_path, 'r') as f:
|
||||||
|
self.content = f.read()
|
||||||
|
self._process()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
description = "Amalgamate C source and header files."
|
||||||
|
usage = " ".join([
|
||||||
|
"amalgamate.py",
|
||||||
|
"[-v]",
|
||||||
|
"-c path/to/config.json",
|
||||||
|
"-s path/to/source/dir",
|
||||||
|
"[-p path/to/prologue.(c|h)]"
|
||||||
|
])
|
||||||
|
argsparser = argparse.ArgumentParser(
|
||||||
|
description=description, usage=usage)
|
||||||
|
|
||||||
|
argsparser.add_argument("-v", "--verbose", dest="verbose",
|
||||||
|
choices=["yes", "no"], metavar="", help="be verbose")
|
||||||
|
|
||||||
|
argsparser.add_argument("-c", "--config", dest="config",
|
||||||
|
required=True, metavar="", help="path to a JSON config file")
|
||||||
|
|
||||||
|
argsparser.add_argument("-s", "--source", dest="source_path",
|
||||||
|
required=True, metavar="", help="source code path")
|
||||||
|
|
||||||
|
argsparser.add_argument("-p", "--prologue", dest="prologue",
|
||||||
|
required=False, metavar="", help="path to a C prologue file")
|
||||||
|
|
||||||
|
amalgamation = Amalgamation(argsparser.parse_args())
|
||||||
|
amalgamation.generate()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
8
external/entt/entt/scripts/config.json
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"project": "entt",
|
||||||
|
"target": "single_include/entt/entt.hpp",
|
||||||
|
"sources": [
|
||||||
|
"src/entt/entt.hpp"
|
||||||
|
],
|
||||||
|
"include_paths": ["src"]
|
||||||
|
}
|
60
external/entt/entt/scripts/update_homebrew.sh
vendored
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# only argument should be the version to upgrade to
|
||||||
|
if [ $# != 1 ]
|
||||||
|
then
|
||||||
|
echo "Expected a version tag like v2.7.1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION="$1"
|
||||||
|
URL="https://github.com/skypjack/entt/archive/$VERSION.tar.gz"
|
||||||
|
FORMULA="entt.rb"
|
||||||
|
|
||||||
|
echo "Updating homebrew package to $VERSION"
|
||||||
|
|
||||||
|
echo "Cloning..."
|
||||||
|
git clone https://github.com/skypjack/homebrew-entt.git
|
||||||
|
if [ $? != 0 ]
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd homebrew-entt
|
||||||
|
|
||||||
|
# download the repo at the version
|
||||||
|
# exit with error messages if curl fails
|
||||||
|
echo "Curling..."
|
||||||
|
curl "$URL" --location --fail --silent --show-error --output archive.tar.gz
|
||||||
|
if [ $? != 0 ]
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# compute sha256 hash
|
||||||
|
echo "Hashing..."
|
||||||
|
HASH="$(openssl sha256 archive.tar.gz | cut -d " " -f 2)"
|
||||||
|
|
||||||
|
# delete the archive
|
||||||
|
rm archive.tar.gz
|
||||||
|
|
||||||
|
echo "Sedding..."
|
||||||
|
|
||||||
|
# change the url in the formula file
|
||||||
|
# the slashes in the URL must be escaped
|
||||||
|
ESCAPED_URL="$(echo "$URL" | sed -e 's/[\/&]/\\&/g')"
|
||||||
|
sed -i -e '/url/s/".*"/"'$ESCAPED_URL'"/' $FORMULA
|
||||||
|
|
||||||
|
# change the hash in the formula file
|
||||||
|
sed -i -e '/sha256/s/".*"/"'$HASH'"/' $FORMULA
|
||||||
|
|
||||||
|
# delete temporary file created by sed
|
||||||
|
rm -rf "$FORMULA-e"
|
||||||
|
|
||||||
|
# update remote repo
|
||||||
|
echo "Gitting..."
|
||||||
|
git add entt.rb
|
||||||
|
git commit -m "Update to $VERSION"
|
||||||
|
git push origin master
|
||||||
|
|
||||||
|
# out of homebrew-entt dir
|
||||||
|
cd ..
|